Merge pull request #1276 from frappe/main-hotfix

This commit is contained in:
Shariq Ansari 2025-09-22 15:25:13 +05:30 committed by GitHub
commit af64b86a04
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
71 changed files with 5238 additions and 2824 deletions

1
.gitignore vendored
View File

@ -7,6 +7,5 @@ dev-dist
tags
node_modules
crm/public/frontend
frontend/yarn.lock
crm/www/crm.html
build

View File

@ -0,0 +1,32 @@
import frappe
@frappe.whitelist()
def get_assignment_rules_list():
assignment_rules = []
for docname in frappe.get_all(
"Assignment Rule", filters={"document_type": ["in", ["CRM Lead", "CRM Deal"]]}
):
doc = frappe.get_value(
"Assignment Rule",
docname,
fieldname=[
"name",
"description",
"disabled",
"priority",
],
as_dict=True,
)
users_exists = bool(frappe.db.exists("Assignment Rule User", {"parent": docname.name}))
assignment_rules.append({**doc, "users_exists": users_exists})
return assignment_rules
@frappe.whitelist()
def duplicate_assignment_rule(docname, new_name):
doc = frappe.get_doc("Assignment Rule", docname)
doc.name = new_name
doc.assignment_rule_name = new_name
doc.insert()
return doc

View File

@ -25,7 +25,7 @@ class CRMDeal(Document):
add_status_change_log(self)
if frappe.db.get_value("CRM Deal Status", self.status, "type") == "Won":
self.closed_date = frappe.utils.nowdate()
self.validate_forcasting_fields()
self.validate_forecasting_fields()
self.validate_lost_reason()
self.update_exchange_rate()
@ -151,9 +151,21 @@ class CRMDeal(Document):
if not self.probability or self.probability == 0:
self.probability = frappe.db.get_value("CRM Deal Status", self.status, "probability") or 0
def validate_forcasting_fields(self):
def update_expected_deal_value(self):
"""
Update the expected deal value based on the net total or total.
"""
if (
frappe.db.get_single_value("FCRM Settings", "auto_update_expected_deal_value")
and (self.net_total or self.total)
and self.expected_deal_value
):
self.expected_deal_value = self.net_total or self.total
def validate_forecasting_fields(self):
self.update_closed_date()
self.update_default_probability()
self.update_expected_deal_value()
if frappe.db.get_single_value("FCRM Settings", "enable_forecasting"):
if not self.expected_deal_value or self.expected_deal_value == 0:
frappe.throw(_("Expected Deal Value is required."), frappe.MandatoryError)

View File

@ -8,6 +8,7 @@
"defaults_tab",
"restore_defaults",
"enable_forecasting",
"auto_update_expected_deal_value",
"currency_tab",
"currency",
"exchange_rate_provider_section",
@ -105,12 +106,19 @@
{
"fieldname": "column_break_vqck",
"fieldtype": "Column Break"
},
{
"default": "1",
"description": "Automatically update \"Expected Deal Value\" based on the total value of associated products in a deal",
"fieldname": "auto_update_expected_deal_value",
"fieldtype": "Check",
"label": "Auto Update Expected Deal Value"
}
],
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2025-07-29 11:26:50.420614",
"modified": "2025-09-16 17:33:26.406549",
"modified_by": "Administrator",
"module": "FCRM",
"name": "FCRM Settings",

View File

@ -25,6 +25,8 @@ def after_install(force=False):
add_standard_dropdown_items()
add_default_scripts()
create_default_manager_dashboard(force)
create_assignment_rule_custom_fields()
add_assignment_rule_property_setters()
frappe.db.commit()
@ -421,3 +423,80 @@ def add_default_scripts():
for doctype in ["CRM Lead", "CRM Deal"]:
create_product_details_script(doctype)
create_forecasting_script()
def add_assignment_rule_property_setters():
"""Add a property setter to the Assignment Rule DocType for assign_condition and unassign_condition."""
default_fields = {
"doctype": "Property Setter",
"doctype_or_field": "DocField",
"doc_type": "Assignment Rule",
"property_type": "Data",
"is_system_generated": 1,
}
if not frappe.db.exists("Property Setter", {"name": "Assignment Rule-assign_condition-depends_on"}):
frappe.get_doc(
{
**default_fields,
"name": "Assignment Rule-assign_condition-depends_on",
"field_name": "assign_condition",
"property": "depends_on",
"value": "eval: !doc.assign_condition_json",
}
).insert()
else:
frappe.db.set_value(
"Property Setter",
{"name": "Assignment Rule-assign_condition-depends_on"},
"value",
"eval: !doc.assign_condition_json",
)
if not frappe.db.exists("Property Setter", {"name": "Assignment Rule-unassign_condition-depends_on"}):
frappe.get_doc(
{
**default_fields,
"name": "Assignment Rule-unassign_condition-depends_on",
"field_name": "unassign_condition",
"property": "depends_on",
"value": "eval: !doc.unassign_condition_json",
}
).insert()
else:
frappe.db.set_value(
"Property Setter",
{"name": "Assignment Rule-unassign_condition-depends_on"},
"value",
"eval: !doc.unassign_condition_json",
)
def create_assignment_rule_custom_fields():
if not frappe.get_meta("Assignment Rule").has_field("assign_condition_json"):
click.secho("* Installing Custom Fields in Assignment Rule")
create_custom_fields(
{
"Assignment Rule": [
{
"description": "Autogenerated field by CRM App",
"fieldname": "assign_condition_json",
"fieldtype": "Code",
"label": "Assign Condition JSON",
"insert_after": "assign_condition",
"depends_on": "eval: doc.assign_condition_json",
},
{
"description": "Autogenerated field by CRM App",
"fieldname": "unassign_condition_json",
"fieldtype": "Code",
"label": "Unassign Condition JSON",
"insert_after": "unassign_condition",
"depends_on": "eval: doc.unassign_condition_json",
},
],
}
)
frappe.clear_cache(doctype="Assignment Rule")

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-07 17:34\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:02\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Arabic\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr "كمية"
@ -1645,7 +1645,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr ""
@ -2166,8 +2166,8 @@ msgstr ""
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr "البريد الإلكتروني"
@ -3215,8 +3215,8 @@ msgstr "العام الماضي"
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr ""
@ -3577,7 +3577,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr ""
@ -3628,7 +3628,7 @@ msgstr ""
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr "اسم"
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr ""
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr ""
@ -3882,7 +3882,7 @@ msgstr ""
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr ""
@ -4112,8 +4112,8 @@ msgstr "ترتيب حسب"
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr "منظمة"
@ -4143,7 +4143,7 @@ msgstr ""
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr ""
@ -4237,7 +4237,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr "هاتف"
@ -5177,7 +5177,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr "الحالة"

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-07 17:34\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:02\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Bosnian\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr "Cijeli dan"
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr "Iznos"
@ -1645,7 +1645,7 @@ msgstr "Analiza kanala generisanja poslova"
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr "Odgovorni Posla"
@ -2166,8 +2166,8 @@ msgstr "Uređivanje događaja"
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr "E-pošta"
@ -3215,8 +3215,8 @@ msgstr "Prošle godine"
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr "Zadnja izmjena"
@ -3577,7 +3577,7 @@ msgstr "Instalacija mobilne aplikacije"
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr "Mobilni Broj"
@ -3628,7 +3628,7 @@ msgstr "Moji Otvoreni Poslovi"
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr "Naziv"
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr "Nisu pronađeni korisnici"
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr "Nije pronađena web stranica"
@ -3882,7 +3882,7 @@ msgstr "Nema {0} Dostupnog"
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr "{0}"
@ -4112,8 +4112,8 @@ msgstr "Sortiraj prema"
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr "Organizacija"
@ -4143,7 +4143,7 @@ msgstr "Logo Organizacije"
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr "Organizacije"
@ -4237,7 +4237,7 @@ msgstr "Osoba"
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr "Telefon"
@ -5183,7 +5183,7 @@ msgstr "Počni s uzorkom od 10 potencijalnih klijenata"
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr "Status"

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-07 17:34\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:02\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Czech\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr ""
@ -1645,7 +1645,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr ""
@ -2166,8 +2166,8 @@ msgstr ""
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr ""
@ -3215,8 +3215,8 @@ msgstr ""
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr ""
@ -3577,7 +3577,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr ""
@ -3628,7 +3628,7 @@ msgstr ""
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr ""
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr ""
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr ""
@ -3882,7 +3882,7 @@ msgstr ""
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr ""
@ -4112,8 +4112,8 @@ msgstr ""
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr ""
@ -4143,7 +4143,7 @@ msgstr ""
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr ""
@ -4237,7 +4237,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr ""
@ -5177,7 +5177,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr ""

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-15 19:47\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:03\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Danish\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr "Hele dagen"
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr "Beløb"
@ -1645,7 +1645,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr ""
@ -2166,8 +2166,8 @@ msgstr ""
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr "E-mail"
@ -3215,8 +3215,8 @@ msgstr ""
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr ""
@ -3577,7 +3577,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr ""
@ -3628,7 +3628,7 @@ msgstr ""
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr ""
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr ""
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr ""
@ -3882,7 +3882,7 @@ msgstr ""
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr ""
@ -4112,8 +4112,8 @@ msgstr ""
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr ""
@ -4143,7 +4143,7 @@ msgstr ""
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr ""
@ -4237,7 +4237,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr ""
@ -5177,7 +5177,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr ""

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-07 17:34\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:02\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: German\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr "Betrag"
@ -1645,7 +1645,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr ""
@ -2166,8 +2166,8 @@ msgstr ""
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr "E-Mail"
@ -3215,8 +3215,8 @@ msgstr "Vergangenes Jahr"
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr "Zuletzt geändert"
@ -3577,7 +3577,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr ""
@ -3628,7 +3628,7 @@ msgstr ""
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr "Name"
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr ""
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr ""
@ -3882,7 +3882,7 @@ msgstr ""
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr "Kein {0} gefunden"
@ -4112,8 +4112,8 @@ msgstr "Sortieren nach"
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr "Firma"
@ -4143,7 +4143,7 @@ msgstr "Organisationslogo"
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr "Organisationen"
@ -4237,7 +4237,7 @@ msgstr "Person"
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr "Telefon"
@ -5177,7 +5177,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr "Status"

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-07 17:34\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:03\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Esperanto\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr "crwdns158770:0crwdne158770:0"
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr "crwdns152751:0crwdne152751:0"
@ -1645,7 +1645,7 @@ msgstr "crwdns156258:0crwdne156258:0"
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr "crwdns153043:0crwdne153043:0"
@ -2166,8 +2166,8 @@ msgstr "crwdns158854:0crwdne158854:0"
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr "crwdns153167:0crwdne153167:0"
@ -3215,8 +3215,8 @@ msgstr "crwdns153421:0crwdne153421:0"
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr "crwdns153423:0crwdne153423:0"
@ -3577,7 +3577,7 @@ msgstr "crwdns156468:0crwdne156468:0"
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr "crwdns153521:0crwdne153521:0"
@ -3628,7 +3628,7 @@ msgstr "crwdns153533:0crwdne153533:0"
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr "crwdns153535:0crwdne153535:0"
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr "crwdns156490:0crwdne156490:0"
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr "crwdns156492:0crwdne156492:0"
@ -3882,7 +3882,7 @@ msgstr "crwdns153607:0{0}crwdne153607:0"
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr "crwdns153609:0{0}crwdne153609:0"
@ -4112,8 +4112,8 @@ msgstr "crwdns153667:0crwdne153667:0"
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr "crwdns153669:0crwdne153669:0"
@ -4143,7 +4143,7 @@ msgstr "crwdns153677:0crwdne153677:0"
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr "crwdns153681:0crwdne153681:0"
@ -4237,7 +4237,7 @@ msgstr "crwdns153703:0crwdne153703:0"
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr "crwdns153705:0crwdne153705:0"
@ -5177,7 +5177,7 @@ msgstr "crwdns156620:0crwdne156620:0"
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr "crwdns153925:0crwdne153925:0"

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-07 17:34\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:02\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Spanish\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr "Importe"
@ -1645,7 +1645,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr ""
@ -2166,8 +2166,8 @@ msgstr ""
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr "Correo electrónico"
@ -3215,8 +3215,8 @@ msgstr "El año pasado"
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr ""
@ -3577,7 +3577,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr ""
@ -3628,7 +3628,7 @@ msgstr ""
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr "Nombre"
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr ""
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr ""
@ -3882,7 +3882,7 @@ msgstr ""
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr "Ningún {0} encontrado"
@ -4112,8 +4112,8 @@ msgstr "Ordenar por"
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr "Organización"
@ -4143,7 +4143,7 @@ msgstr ""
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr ""
@ -4237,7 +4237,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr "Teléfono"
@ -5177,7 +5177,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr "Estado"

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-15 19:47\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:03\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Persian\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr "مبلغ"
@ -1645,7 +1645,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr ""
@ -2166,8 +2166,8 @@ msgstr ""
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr "ایمیل"
@ -3215,8 +3215,8 @@ msgstr "سال گذشته"
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr ""
@ -3577,7 +3577,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr ""
@ -3628,7 +3628,7 @@ msgstr ""
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr "نام"
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr ""
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr ""
@ -3882,7 +3882,7 @@ msgstr ""
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr "هیچ {0} یافت نشد"
@ -4112,8 +4112,8 @@ msgstr "سفارش توسط"
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr "سازمان"
@ -4143,7 +4143,7 @@ msgstr "لوگوی سازمان"
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr "سازمان ها"
@ -4237,7 +4237,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr "تلفن"
@ -5177,7 +5177,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr "وضعیت"

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-07 17:34\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:02\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: French\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr "Montant"
@ -987,7 +987,7 @@ msgstr "Détails de l'appel"
#. Label of the receiver (Link) field in DocType 'CRM Call Log'
#: crm/fcrm/doctype/crm_call_log/crm_call_log.json
msgid "Call Received By"
msgstr ""
msgstr "Appel reçu par"
#. Description of the 'Duration' (Duration) field in DocType 'CRM Call Log'
#: crm/fcrm/doctype/crm_call_log/crm_call_log.json
@ -1645,7 +1645,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr ""
@ -1951,7 +1951,7 @@ msgstr ""
#. Option for the 'Status' (Select) field in DocType 'CRM Task'
#: crm/fcrm/doctype/crm_task/crm_task.json
msgid "Done"
msgstr ""
msgstr "Terminé"
#: frontend/src/components/Dashboard/AddChartModal.vue:33
#: frontend/src/components/Dashboard/AddChartModal.vue:71
@ -2166,8 +2166,8 @@ msgstr ""
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr "Courriel"
@ -3215,8 +3215,8 @@ msgstr "L'année dernière"
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr ""
@ -3577,7 +3577,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr ""
@ -3628,7 +3628,7 @@ msgstr ""
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr "Nom"
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr ""
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr ""
@ -3882,7 +3882,7 @@ msgstr ""
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr ""
@ -4112,8 +4112,8 @@ msgstr "Commandé par"
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr "Organisation"
@ -4143,7 +4143,7 @@ msgstr ""
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr ""
@ -4237,7 +4237,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr "Téléphone"
@ -5177,7 +5177,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr "Statut"

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-07 17:34\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:03\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Croatian\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr "Cijeli dan"
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr "Iznos"
@ -1645,7 +1645,7 @@ msgstr "Analiza kanala generisanja poslova"
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr "Odgovorni Posla"
@ -2166,8 +2166,8 @@ msgstr "Uređivanje događaja"
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr "E-pošta"
@ -3215,8 +3215,8 @@ msgstr "Prošle godine"
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr "Zadnja izmjena"
@ -3577,7 +3577,7 @@ msgstr "Instalacija mobilne aplikacije"
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr "Mobilni Broj"
@ -3628,7 +3628,7 @@ msgstr "Moji Otvoreni Poslovi"
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr "Naziv"
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr "Nisu pronađeni korisnici"
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr "Nije pronađena web stranica"
@ -3882,7 +3882,7 @@ msgstr "Nema {0} Dostupno"
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr "Nije pronađeno {0}"
@ -4112,8 +4112,8 @@ msgstr "Sortiraj prema"
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr "Organizacija"
@ -4143,7 +4143,7 @@ msgstr "Logo Organizacije"
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr "Organizacije"
@ -4237,7 +4237,7 @@ msgstr "Osoba"
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr "Telefon"
@ -5183,7 +5183,7 @@ msgstr "Započni s uzorkom od 10 potencijalnih klijenata"
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr "Status"

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-07 17:34\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:02\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Hungarian\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr ""
@ -1645,7 +1645,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr ""
@ -2166,8 +2166,8 @@ msgstr ""
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr ""
@ -3215,8 +3215,8 @@ msgstr ""
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr ""
@ -3577,7 +3577,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr ""
@ -3628,7 +3628,7 @@ msgstr ""
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr ""
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr ""
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr ""
@ -3882,7 +3882,7 @@ msgstr ""
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr ""
@ -4112,8 +4112,8 @@ msgstr ""
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr ""
@ -4143,7 +4143,7 @@ msgstr ""
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr ""
@ -4237,7 +4237,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr ""
@ -5177,7 +5177,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr ""

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-07 17:34\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:02\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Indonesian\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr "Jumlah"
@ -1645,7 +1645,7 @@ msgstr "Analisis saluran perolehan kesepakatan"
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr "Pemilik kesepakatan"
@ -2166,8 +2166,8 @@ msgstr ""
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr "Email"
@ -3215,8 +3215,8 @@ msgstr "Tahun Lalu"
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr "Terakhir diubah"
@ -3577,7 +3577,7 @@ msgstr "Instalasi aplikasi seluler"
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr "Nomor Ponsel"
@ -3628,7 +3628,7 @@ msgstr "Kesepakatan Terbuka Saya"
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr "Nama"
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr "Pengguna tidak ditemukan"
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr "Situs web tidak ditemukan"
@ -3882,7 +3882,7 @@ msgstr "Tidak Ada {0} yang Tersedia"
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr "{0} tidak ditemukan"
@ -4112,8 +4112,8 @@ msgstr "Urutkan Berdasarkan"
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr "Organisasi"
@ -4143,7 +4143,7 @@ msgstr "Logo organisasi"
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr "Organisasi"
@ -4237,7 +4237,7 @@ msgstr "Orang"
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr "Telepon"
@ -5177,7 +5177,7 @@ msgstr "Mulai dengan 10 contoh prospek"
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr "Status"

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-07 17:34\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:02\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Italian\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr ""
@ -1645,7 +1645,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr ""
@ -2166,8 +2166,8 @@ msgstr ""
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr "E-mail"
@ -3215,8 +3215,8 @@ msgstr ""
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr ""
@ -3577,7 +3577,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr "Cellulare"
@ -3628,7 +3628,7 @@ msgstr ""
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr ""
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr ""
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr ""
@ -3882,7 +3882,7 @@ msgstr ""
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr ""
@ -4112,8 +4112,8 @@ msgstr ""
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr ""
@ -4143,7 +4143,7 @@ msgstr ""
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr ""
@ -4237,7 +4237,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr "Telefono"
@ -5177,7 +5177,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr "Stato"

File diff suppressed because it is too large Load Diff

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-14 19:18\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-21 20:47\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Norwegian Bokmal\n"
"MIME-Version: 1.0\n"
@ -128,20 +128,20 @@ msgstr "<b>SNARVEIER</b>"
#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:98
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:98
msgid "<p>Dear {{ lead_name }},</p>\\n\\n<p>This is a reminder for the payment of {{ grand_total }}.</p>\\n\\n<p>Thanks,</p>\\n<p>Frappé</p>"
msgstr ""
msgstr "<p>Kjære {{ lead_name }},</p>\\n\\n<p>Dette er en påminnelse om betaling av {{ grand_total }}.</p>\\n\\n<p>Takk,</p>\\n<p>Frappé</p>"
#. Header text in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
msgid "<span class=\"h5\"><b>PORTAL</b></span>"
msgstr ""
msgstr "<span class=\"h5\"><b>PORTAL</b></span>"
#: frontend/src/components/CommunicationArea.vue:79
msgid "@John, can you please check this?"
msgstr ""
msgstr "@John, kan du sjekke dette?"
#: crm/fcrm/doctype/crm_lead/crm_lead.py:56
msgid "A Lead requires either a person's name or an organization's name"
msgstr ""
msgstr "En potensiell kunde krever enten en persons navn eller en organisasjons navn"
#: crm/templates/emails/helpdesk_invitation.html:5
msgid "A new account has been created for you at {0}"
@ -160,7 +160,7 @@ msgstr "API Nøkkel"
#: frontend/src/components/Settings/emailConfig.js:179
msgid "API Key is required"
msgstr ""
msgstr "API-key er påkrevd"
#. Label of the api_secret (Password) field in DocType 'CRM Twilio Settings'
#. Label of the api_secret (Password) field in DocType 'ERPNext CRM Settings'
@ -174,72 +174,72 @@ msgstr "API-hemmelighet"
#. Label of the api_token (Password) field in DocType 'CRM Exotel Settings'
#: crm/fcrm/doctype/crm_exotel_settings/crm_exotel_settings.json
msgid "API Token"
msgstr ""
msgstr "API-token"
#: frontend/src/components/Telephony/TwilioCallUI.vue:88
msgid "Accept"
msgstr ""
msgstr "Aksepter"
#: crm/fcrm/doctype/crm_invitation/crm_invitation.js:7
msgid "Accept Invitation"
msgstr ""
msgstr "Aksepter invitasjon"
#: frontend/src/components/Telephony/TwilioCallUI.vue:155
msgid "Accept call"
msgstr ""
msgstr "Aksepter anrop"
#. Option for the 'Status' (Select) field in DocType 'CRM Invitation'
#: crm/fcrm/doctype/crm_invitation/crm_invitation.json
msgid "Accepted"
msgstr ""
msgstr "Akseptert"
#. Label of the accepted_at (Datetime) field in DocType 'CRM Invitation'
#: crm/fcrm/doctype/crm_invitation/crm_invitation.json
msgid "Accepted At"
msgstr ""
msgstr "Akseptert kl. "
#. Label of the access_key (Data) field in DocType 'FCRM Settings'
#: crm/fcrm/doctype/fcrm_settings/fcrm_settings.json
msgid "Access Key"
msgstr ""
msgstr "Tilgangsnøkkel"
#: crm/fcrm/doctype/fcrm_settings/fcrm_settings.py:156
msgid "Access Key is required for Service Provider: {0}"
msgstr ""
msgstr "Tilgangsnøkkel er nødvendig for tjenesteleverandøren: {0}"
#: frontend/src/components/Settings/General/CurrencySettings.vue:97
msgid "Access key"
msgstr ""
msgstr "Tilgangsnøkkel"
#: frontend/src/components/Settings/General/CurrencySettings.vue:101
msgid "Access key for Exchangerate Host. Required for fetching exchange rates."
msgstr ""
msgstr "Tilgangsnøkkel for Exchangerate Host. Nødvendig for å hente valutakurser."
#: frontend/src/components/Settings/emailConfig.js:13
msgid "Account Name"
msgstr ""
msgstr "Kontonavn"
#. Label of the account_sid (Data) field in DocType 'CRM Exotel Settings'
#. Label of the account_sid (Data) field in DocType 'CRM Twilio Settings'
#: crm/fcrm/doctype/crm_exotel_settings/crm_exotel_settings.json
#: crm/fcrm/doctype/crm_twilio_settings/crm_twilio_settings.json
msgid "Account SID"
msgstr ""
msgstr "Konto-SID"
#: frontend/src/components/Settings/emailConfig.js:165
msgid "Account name is required"
msgstr ""
msgstr "Kontonavn er påkrevd"
#: frontend/src/components/CustomActions.vue:69
#: frontend/src/components/ViewControls.vue:683
#: frontend/src/components/ViewControls.vue:1064
msgid "Actions"
msgstr ""
msgstr "Handlinger"
#: frontend/src/pages/Deal.vue:527 frontend/src/pages/Lead.vue:384
#: frontend/src/pages/MobileDeal.vue:430 frontend/src/pages/MobileLead.vue:337
msgid "Activity"
msgstr ""
msgstr "Aktivitet"
#: frontend/src/components/Dashboard/AddChartModal.vue:41
#: frontend/src/components/Modals/AddExistingUserModal.vue:55
@ -252,7 +252,7 @@ msgstr "Legg til Konto"
#: frontend/src/components/Settings/AssignmentRules/AssigneeSearch.vue:9
msgid "Add Assignee"
msgstr ""
msgstr "Legg til rettighetshaver"
#: frontend/src/components/ColumnSettings.vue:68
#: frontend/src/components/Kanban/KanbanView.vue:157
@ -262,7 +262,7 @@ msgstr "Legg til Kolonne"
#: frontend/src/components/Modals/AddExistingUserModal.vue:4
#: frontend/src/components/Settings/Users.vue:21
msgid "Add Existing User"
msgstr ""
msgstr "Legg til eksisterende bruker"
#: frontend/src/components/Controls/GridFieldsEditorModal.vue:57
#: frontend/src/components/FieldLayoutEditor.vue:172
@ -277,7 +277,7 @@ msgstr "Legg til Filter"
#: frontend/src/components/Calendar/CalendarEventPanel.vue:273
msgid "Add Lead or Deal"
msgstr ""
msgstr "Legg til potensiell kunde eller avtale"
#: frontend/src/components/Controls/Grid.vue:324
msgid "Add Row"
@ -286,7 +286,7 @@ msgstr "Legg til Rad"
#: frontend/src/components/FieldLayoutEditor.vue:197
#: frontend/src/components/SidePanelLayoutEditor.vue:127
msgid "Add Section"
msgstr ""
msgstr "Legg til seksjon"
#: frontend/src/components/SortBy.vue:142
msgid "Add Sort"
@ -388,7 +388,7 @@ msgstr ""
#. Label of the address (Link) field in DocType 'CRM Organization'
#: crm/fcrm/doctype/crm_organization/crm_organization.json
msgid "Address"
msgstr ""
msgstr "Adresse"
#: frontend/src/components/Modals/AddExistingUserModal.vue:94
#: frontend/src/components/Settings/InviteUserPage.vue:169
@ -424,42 +424,42 @@ msgstr ""
#: frontend/src/components/Modals/EventModal.vue:71
#: frontend/src/composables/event.js:122
msgid "All day"
msgstr ""
msgstr "Hele dagen"
#. Label of the amount (Currency) field in DocType 'CRM Products'
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr ""
msgstr "Beløp"
#. Description of the 'Net Amount' (Currency) field in DocType 'CRM Products'
#: crm/fcrm/doctype/crm_products/crm_products.json
msgid "Amount after discount"
msgstr ""
msgstr "Beløp etter rabatt"
#: frontend/src/data/script.js:50 frontend/src/data/script.js:51
msgid "An error occurred"
msgstr ""
msgstr "En feil oppstod"
#: frontend/src/data/document.js:63
msgid "An error occurred while updating the document"
msgstr ""
msgstr "Det oppsto en feil under oppdatering av dokumentet"
#. Description of the 'Favicon' (Attach) field in DocType 'FCRM Settings'
#: crm/fcrm/doctype/fcrm_settings/fcrm_settings.json
msgid "An icon file with .ico extension. Should be 16 x 16 px. Generated using a favicon generator. [favicon-generator.org]"
msgstr ""
msgstr "En ikonfil med filtypen .ico. Bør være 16 x 16 px. Genereres ved hjelp av en favicon-generator. [favicon-generator.org]"
#. Description of the 'Logo' (Attach) field in DocType 'FCRM Settings'
#: crm/fcrm/doctype/fcrm_settings/fcrm_settings.json
msgid "An image with 1:1 & 2:1 ratio is preferred"
msgstr ""
msgstr "Et bilde med forholdet 1:1 og 2:1 er å foretrekke"
#: frontend/src/components/Filter.vue:43 frontend/src/components/Filter.vue:81
msgid "And"
msgstr ""
msgstr "Og"
#. Label of the annual_revenue (Currency) field in DocType 'CRM Deal'
#. Label of the annual_revenue (Currency) field in DocType 'CRM Lead'
@ -468,39 +468,39 @@ msgstr ""
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_organization/crm_organization.json
msgid "Annual Revenue"
msgstr ""
msgstr "Årlig omsetning"
#: frontend/src/components/Modals/DealModal.vue:200
#: frontend/src/components/Modals/LeadModal.vue:141
msgid "Annual Revenue should be a number"
msgstr ""
msgstr "Årlig omsetning må være et tall"
#: frontend/src/components/Settings/General/BrandSettings.vue:69
msgid "Appears in the left sidebar. Recommended size is 32x32 px in PNG or SVG"
msgstr ""
msgstr "Vises i venstre sidefelt. Anbefalt størrelse er 32x32 px i PNG eller SVG"
#: frontend/src/components/Settings/General/BrandSettings.vue:103
msgid "Appears next to the title in your browser tab. Recommended size is 32x32 px in PNG or ICO"
msgstr ""
msgstr "Vises ved siden av tittelen i nettleserfanen. Anbefalt størrelse er 32x32 px i PNG eller ICO"
#: frontend/src/components/Kanban/KanbanSettings.vue:101
#: frontend/src/components/Kanban/KanbanView.vue:46
msgid "Apply"
msgstr ""
msgstr "Bruk"
#. Label of the apply_on (Link) field in DocType 'CRM Service Level Agreement'
#: crm/fcrm/doctype/crm_service_level_agreement/crm_service_level_agreement.json
msgid "Apply On"
msgstr ""
msgstr "Bruk på"
#. Label of the view (Select) field in DocType 'CRM Form Script'
#: crm/fcrm/doctype/crm_form_script/crm_form_script.json
msgid "Apply To"
msgstr ""
msgstr "Bruk på"
#: frontend/src/components/Settings/AssignmentRules/AssignmentRuleView.vue:132
msgid "Apply on"
msgstr ""
msgstr "Bruk på"
#: frontend/src/components/Apps.vue:19
msgid "Apps"
@ -508,40 +508,40 @@ msgstr "Apper"
#: frontend/src/components/Activities/AttachmentArea.vue:128
msgid "Are you sure you want to delete this attachment?"
msgstr ""
msgstr "Er du sikker på at du vil slette dette vedlegget?"
#: frontend/src/pages/MobileContact.vue:260
msgid "Are you sure you want to delete this contact?"
msgstr ""
msgstr "Er du sikker på at du ønsker å slette denne kontakten?"
#: frontend/src/components/Modals/EventModal.vue:408
#: frontend/src/pages/Calendar.vue:300
msgid "Are you sure you want to delete this event?"
msgstr ""
msgstr "Er du sikker på at du vil slette denne hendelsen?"
#: frontend/src/pages/MobileOrganization.vue:261
msgid "Are you sure you want to delete this organization?"
msgstr ""
msgstr "Er du sikker på at du vil slette denne organisasjonen?"
#: frontend/src/components/Activities/TaskArea.vue:60
msgid "Are you sure you want to delete this task?"
msgstr ""
msgstr "Er du sikker på at du vil slette denne oppgaven?"
#: frontend/src/components/DeleteLinkedDocModal.vue:231
msgid "Are you sure you want to delete {0} linked item(s)?"
msgstr ""
msgstr "Er du sikker på at du vil slette {0} linkede element(er)?"
#: frontend/src/components/Calendar/CalendarEventPanel.vue:615
msgid "Are you sure you want to discard unsaved changes to this event?"
msgstr ""
msgstr "Er du sikker på at du vil forkaste ikke-lagrede endringer i denne hendelsen?"
#: frontend/src/components/Settings/AssignmentRules/AssignmentRuleView.vue:561
msgid "Are you sure you want to go back? Unsaved changes will be lost."
msgstr ""
msgstr "Er du sikker på at du vil gå tilbake? Ikke-lagrede endringer vil gå tapt."
#: frontend/src/composables/frappecloud.js:24
msgid "Are you sure you want to login to your Frappe Cloud dashboard?"
msgstr ""
msgstr "Er du sikker på at du vil logge inn på Frappe Cloud-dashbordet ditt?"
#: crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.js:9
msgid "Are you sure you want to reset 'Create Quotation from CRM Deal' Form Script?"
@ -549,11 +549,11 @@ msgstr "Er du sikker på at du vil tilbakestille skjemaskriptet \"Opprett tilbud
#: frontend/src/components/Settings/General/CurrencySettings.vue:174
msgid "Are you sure you want to set the currency as {0}? This cannot be changed later."
msgstr ""
msgstr "Er du sikker på at du vil angi valutaen som {0}? Dette kan ikke endres senere."
#: frontend/src/components/DeleteLinkedDocModal.vue:244
msgid "Are you sure you want to unlink {0} linked item(s)?"
msgstr ""
msgstr "Er du sikker på at du vil fjerne koblingen til {0} lenkede elementer?"
#: crm/fcrm/doctype/fcrm_settings/fcrm_settings.py:193
msgid "Ask your manager to set up the Exchange Rate Provider, as default provider does not support currency conversion for {0} to {1}."
@ -1067,7 +1067,7 @@ msgstr ""
#: frontend/src/components/FilesUploader/FilesUploader.vue:91
msgid "Capture"
msgstr ""
msgstr "Ta bilde"
#: frontend/src/components/Layouts/AppSidebar.vue:561
msgid "Capturing leads"
@ -1645,7 +1645,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr ""
@ -1754,7 +1754,7 @@ msgstr ""
#: frontend/src/components/Settings/AssignmentRules/AssigneeRules.vue:9
msgid "Define who receives the tickets and how theyre distributed among agents."
msgstr ""
msgstr "Definer hvem som skal motta billettene og hvordan de skal fordeles mellom agentene."
#: frontend/src/components/Activities/AttachmentArea.vue:131
#: frontend/src/components/Activities/NoteArea.vue:12
@ -1822,7 +1822,7 @@ msgstr ""
#: frontend/src/components/Settings/InviteUserPage.vue:84
msgid "Delete invitation"
msgstr ""
msgstr "Slett invitasjon"
#: frontend/src/components/DeleteLinkedDocModal.vue:230
msgid "Delete linked item"
@ -1887,7 +1887,7 @@ msgstr "Detaljer"
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/components/FilesUploader/FilesUploaderArea.vue:39
msgid "Device"
msgstr ""
msgstr "Enhet"
#: crm/fcrm/doctype/crm_form_script/crm_form_script.js:30
msgid "Disable"
@ -1911,7 +1911,7 @@ msgstr ""
#. Label of the discount_percentage (Percent) field in DocType 'CRM Products'
#: crm/fcrm/doctype/crm_products/crm_products.json
msgid "Discount %"
msgstr ""
msgstr "Rabatt %"
#. Label of the discount_amount (Currency) field in DocType 'CRM Products'
#: crm/fcrm/doctype/crm_products/crm_products.json
@ -1961,7 +1961,7 @@ msgstr ""
#: frontend/src/components/Activities/AudioPlayer.vue:166
#: frontend/src/components/ViewControls.vue:254
msgid "Download"
msgstr ""
msgstr "Last ned"
#: frontend/src/components/FilesUploader/FilesUploaderArea.vue:24
msgid "Drag and drop files here or upload from"
@ -2053,7 +2053,7 @@ msgstr "ERPNext er ikke integrert med CRM-systemet"
#: frontend/src/components/Settings/ERPNextSettings.vue:4
msgid "ERPNext settings"
msgstr "ERPNext-innstillinger"
msgstr "ERPNext innstillinger"
#: frontend/src/components/Settings/ERPNextSettings.vue:5
msgid "ERPNext settings updated"
@ -2166,8 +2166,8 @@ msgstr ""
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr ""
@ -2228,7 +2228,7 @@ msgstr ""
#: frontend/src/components/Filter.vue:123
msgid "Empty - Choose a field to filter by"
msgstr ""
msgstr "Tom - Velg et felt å filtrere etter"
#: frontend/src/components/SortBy.vue:130
msgid "Empty - Choose a field to sort by"
@ -2236,7 +2236,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_form_script/crm_form_script.js:30
msgid "Enable"
msgstr ""
msgstr "Aktiver"
#. Label of the enable_forecasting (Check) field in DocType 'FCRM Settings'
#: crm/fcrm/doctype/fcrm_settings/fcrm_settings.json
@ -2253,7 +2253,7 @@ msgstr "Aktiver utgående e-post"
#: frontend/src/components/Settings/General/GeneralSettings.vue:19
msgid "Enable forecasting"
msgstr ""
msgstr "Aktiver prognoser"
#. Label of the enabled (Check) field in DocType 'CRM Exotel Settings'
#. Label of the enabled (Check) field in DocType 'CRM Form Script'
@ -2278,7 +2278,7 @@ msgstr "Aktivert"
#. Label of the end_date (Date) field in DocType 'CRM Service Level Agreement'
#: crm/fcrm/doctype/crm_service_level_agreement/crm_service_level_agreement.json
msgid "End Date"
msgstr ""
msgstr "Sluttdato"
#. Label of the end_time (Datetime) field in DocType 'CRM Call Log'
#. Label of the end_time (Time) field in DocType 'CRM Service Day'
@ -2287,19 +2287,19 @@ msgstr ""
#: frontend/src/components/Calendar/CalendarEventPanel.vue:242
#: frontend/src/components/Modals/EventModal.vue:112
msgid "End Time"
msgstr ""
msgstr "Sluttidspunkt"
#: frontend/src/composables/event.js:206
msgid "End time should be after start time"
msgstr ""
msgstr "Sluttidspunkt må være etter starttidspunkt"
#: frontend/src/components/Settings/General/CurrencySettings.vue:122
msgid "Enter access key"
msgstr ""
msgstr "Angi tilgangsnøkkel"
#: frontend/src/components/FieldLayout/Field.vue:339
msgid "Enter {0}"
msgstr ""
msgstr "Angi {0}"
#: frontend/src/components/Filter.vue:66 frontend/src/components/Filter.vue:99
#: frontend/src/components/Filter.vue:267
@ -2313,12 +2313,12 @@ msgstr "Tilsvarer"
#: frontend/src/components/Modals/ConvertToDealModal.vue:176
msgid "Error converting to deal: {0}"
msgstr ""
msgstr "Feil ved konvertering til avtale: {0}"
#: frontend/src/pages/Deal.vue:731 frontend/src/pages/Lead.vue:469
#: frontend/src/pages/MobileDeal.vue:612 frontend/src/pages/MobileLead.vue:413
msgid "Error updating field"
msgstr ""
msgstr "Feil ved oppdatering av felt"
#: crm/fcrm/doctype/erpnext_crm_settings/erpnext_crm_settings.py:279
msgid "Error while creating customer in ERPNext, check error log for more details"
@ -2364,11 +2364,11 @@ msgstr ""
#. 'FCRM Settings'
#: crm/fcrm/doctype/fcrm_settings/fcrm_settings.json
msgid "Exchange Rate Provider"
msgstr ""
msgstr "Valutakursleverandør"
#: frontend/src/components/Settings/General/CurrencySettings.vue:67
msgid "Exchange rate provider"
msgstr ""
msgstr "Valutakursleverandør"
#. Option for the 'Telephony Medium' (Select) field in DocType 'CRM Call Log'
#. Label of the exotel (Check) field in DocType 'CRM Telephony Agent'
@ -2384,20 +2384,20 @@ msgstr ""
#: crm/integrations/exotel/handler.py:114
msgid "Exotel Exception"
msgstr ""
msgstr "Exotel-unntak"
#. Label of the exotel_number (Data) field in DocType 'CRM Telephony Agent'
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
msgid "Exotel Number"
msgstr ""
msgstr "Exotel-nummer"
#: crm/integrations/exotel/handler.py:85
msgid "Exotel Number Missing"
msgstr ""
msgstr "Exotel-nummer mangler"
#: crm/integrations/exotel/handler.py:89
msgid "Exotel Number {0} is not valid"
msgstr ""
msgstr "Exotel-nummer {0} er ikke gyldig"
#: frontend/src/components/Settings/TelephonySettings.vue:293
msgid "Exotel is not enabled"
@ -2468,7 +2468,7 @@ msgstr ""
#: frontend/src/components/Modals/AddExistingUserModal.vue:111
msgid "Failed to add users"
msgstr ""
msgstr "Kunne ikke legge til brukere"
#: crm/integrations/twilio/api.py:130
msgid "Failed to capture Twilio recording"
@ -2488,11 +2488,11 @@ msgstr ""
#: crm/fcrm/doctype/fcrm_settings/fcrm_settings.py:205
msgid "Failed to fetch exchange rate from {0} to {1} on {2}. Please check your internet connection or try again later."
msgstr ""
msgstr "Kunne ikke hente valutakurs fra {0} til {1} på {2}. Vennligst sjekk internettforbindelsen din eller prøv igjen senere."
#: frontend/src/data/script.js:106
msgid "Failed to load form controller: {0}"
msgstr ""
msgstr "Kunne ikke laste inn skjemakontroller: {0}"
#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:246
msgid "Failed to rename template"
@ -2523,7 +2523,7 @@ msgstr ""
#: crm/fcrm/doctype/fcrm_settings/fcrm_settings.json
#: frontend/src/components/Settings/General/BrandSettings.vue:81
msgid "Favicon"
msgstr ""
msgstr "Favicon"
#: frontend/src/components/ConditionsFilter/CFCondition.vue:38
#: frontend/src/components/Modals/EditValueModal.vue:5
@ -2533,7 +2533,7 @@ msgstr "Felt"
#: frontend/src/components/Controls/GridFieldsEditorModal.vue:19
#: frontend/src/components/Kanban/KanbanSettings.vue:48
msgid "Fields Order"
msgstr ""
msgstr "Feltrekkefølge"
#: frontend/src/components/FilesUploader/FilesUploaderArea.vue:333
msgid "File \"{0}\" was skipped because of invalid file type"
@ -2541,11 +2541,11 @@ msgstr "Filen «{0}» ble hoppet over på grunn av ugyldig filtype"
#: frontend/src/components/FilesUploader/FilesUploaderArea.vue:354
msgid "File \"{0}\" was skipped because only {1} uploads are allowed"
msgstr ""
msgstr "Filen \"{0}\" ble hoppet over fordi bare {1} -opplastinger er tillatt"
#: frontend/src/components/FilesUploader/FilesUploaderArea.vue:359
msgid "File \"{0}\" was skipped because only {1} uploads are allowed for DocType \"{2}\""
msgstr ""
msgstr "Filen \"{0}\" ble hoppet over fordi bare {1} -opplastinger er tillatt for DocType \"{2}\""
#: frontend/src/components/Filter.vue:6
msgid "Filter"
@ -2555,7 +2555,7 @@ msgstr "Filter"
#. Label of the filters_tab (Tab Break) field in DocType 'CRM View Settings'
#: crm/fcrm/doctype/crm_view_settings/crm_view_settings.json
msgid "Filters"
msgstr ""
msgstr "Filtre"
#. Label of the first_name (Data) field in DocType 'CRM Deal'
#. Label of the first_name (Data) field in DocType 'CRM Lead'
@ -2590,7 +2590,7 @@ msgstr ""
#. Level Priority'
#: crm/fcrm/doctype/crm_service_level_priority/crm_service_level_priority.json
msgid "First Response TIme"
msgstr ""
msgstr "Første responstid"
#. Label of the first_response_time (Duration) field in DocType 'CRM Deal'
#. Label of the first_response_time (Duration) field in DocType 'CRM Lead'
@ -2602,7 +2602,7 @@ msgstr ""
#: frontend/src/components/Filter.vue:130
#: frontend/src/components/Settings/ProfileSettings.vue:78
msgid "First name"
msgstr ""
msgstr "Fornavn"
#: frontend/src/components/Settings/EmailTemplate/EditEmailTemplate.vue:51
#: frontend/src/components/Settings/EmailTemplate/EmailTemplates.vue:84
@ -2617,11 +2617,11 @@ msgstr ""
#: frontend/src/components/Settings/General/GeneralSettings.vue:100
msgid "Forecasting disabled successfully"
msgstr ""
msgstr "Prognoser er deaktivert"
#: frontend/src/components/Settings/General/GeneralSettings.vue:99
msgid "Forecasting enabled successfully"
msgstr ""
msgstr "Prognoser er aktivert"
#. Option for the 'Apply To' (Select) field in DocType 'CRM Form Script'
#: crm/fcrm/doctype/crm_form_script/crm_form_script.json
@ -2646,7 +2646,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_holiday_list/crm_holiday_list.json
#: crm/fcrm/doctype/crm_service_day/crm_service_day.json
msgid "Friday"
msgstr ""
msgstr "Fredag"
#. Label of the from (Data) field in DocType 'CRM Call Log'
#. Label of the from (Data) field in DocType 'CRM Status Change Log'
@ -2670,7 +2670,7 @@ msgstr ""
#. Label of the from_user (Link) field in DocType 'CRM Notification'
#: crm/fcrm/doctype/crm_notification/crm_notification.json
msgid "From User"
msgstr ""
msgstr "Fra bruker"
#. Option for the 'SLA Status' (Select) field in DocType 'CRM Deal'
#. Option for the 'SLA Status' (Select) field in DocType 'CRM Lead'
@ -2689,7 +2689,7 @@ msgstr "Fullt navn"
#: crm/api/dashboard.py:728
#: frontend/src/components/Dashboard/AddChartModal.vue:96
msgid "Funnel conversion"
msgstr ""
msgstr "Traktkonvertering"
#: frontend/src/components/Calendar/CalendarEventPanel.vue:196
msgid "GMT+5:30"
@ -2822,7 +2822,7 @@ msgstr ""
#: frontend/src/components/FieldLayoutEditor.vue:354
msgid "Hide border"
msgstr ""
msgstr "Skjul grensen"
#: frontend/src/components/FieldLayoutEditor.vue:349
msgid "Hide label"
@ -2844,7 +2844,7 @@ msgstr ""
#. Agreement'
#: crm/fcrm/doctype/crm_service_level_agreement/crm_service_level_agreement.json
msgid "Holiday List"
msgstr ""
msgstr "Ferieliste"
#. Label of the holiday_list_name (Data) field in DocType 'CRM Holiday List'
#: crm/fcrm/doctype/crm_holiday_list/crm_holiday_list.json
@ -2861,12 +2861,12 @@ msgstr ""
#: frontend/src/components/Layouts/AppSidebar.vue:542
#: frontend/src/components/Settings/General/HomeActions.vue:9
msgid "Home actions"
msgstr ""
msgstr "Handlinger på Hjem-siden"
#: frontend/src/components/Settings/AssignmentRules/AssignmentRuleView.vue:204
#: frontend/src/components/Settings/AssignmentRules/AssignmentRuleView.vue:285
msgid "I understand, add conditions"
msgstr ""
msgstr "Jeg forstår, legg til betingelser"
#. Label of the id (Data) field in DocType 'CRM Call Log'
#: crm/fcrm/doctype/crm_call_log/crm_call_log.json
@ -2966,12 +2966,12 @@ msgstr ""
#: frontend/src/components/EmailEditor.vue:154
msgid "Insert Email Template"
msgstr ""
msgstr "Sett inn e-postmal"
#: frontend/src/components/CommentBox.vue:49
#: frontend/src/components/EmailEditor.vue:130
msgid "Insert Emoji"
msgstr ""
msgstr "Sett inn emoji"
#: frontend/src/components/Layouts/AppSidebar.vue:598
msgid "Integration"
@ -2979,7 +2979,7 @@ msgstr "Integrasjon"
#: crm/integrations/exotel/handler.py:73
msgid "Integration Not Enabled"
msgstr ""
msgstr "Integrasjon ikke aktivert"
#: frontend/src/components/Settings/Settings.vue:131
msgctxt "FCRM"
@ -3002,7 +3002,7 @@ msgstr ""
#: crm/integrations/exotel/handler.py:89
msgid "Invalid Exotel Number"
msgstr ""
msgstr "Ugyldig Exotel-nummer"
#: crm/api/dashboard.py:73
msgid "Invalid chart name"
@ -3022,7 +3022,7 @@ msgstr ""
#: frontend/src/pages/InvalidPage.vue:6
msgid "Invalid page or not permitted to access"
msgstr ""
msgstr "Ugyldig side eller manglende rettigheter"
#: frontend/src/composables/event.js:203
msgid "Invalid start or end time"
@ -3030,11 +3030,11 @@ msgstr ""
#: frontend/src/components/Settings/Users.vue:25
msgid "Invite New User"
msgstr ""
msgstr "Inviter ny bruker"
#: frontend/src/components/Settings/Settings.vue:107
msgid "Invite User"
msgstr ""
msgstr "Inviter bruker"
#: frontend/src/components/Settings/AssignmentRules/AssigneeSearch.vue:78
#: frontend/src/components/Settings/AssignmentRules/AssigneeSearch.vue:149
@ -3043,19 +3043,19 @@ msgstr ""
#: frontend/src/components/Settings/InviteUserPage.vue:56
msgid "Invite as"
msgstr ""
msgstr "Inviter som"
#: frontend/src/components/Settings/InviteUserPage.vue:29
msgid "Invite by email"
msgstr ""
msgstr "Invitasjon via e-post"
#: frontend/src/components/Layouts/AppSidebar.vue:543
msgid "Invite users"
msgstr ""
msgstr "Inviter brukere"
#: frontend/src/components/Settings/InviteUserPage.vue:10
msgid "Invite users to access CRM. Specify their roles to control access and permissions"
msgstr ""
msgstr "Inviter brukere til å få tilgang til CRM. Spesifiser rollene deres for å kontrollere tilgang og tillatelser"
#: frontend/src/components/Layouts/AppSidebar.vue:359
msgid "Invite your team"
@ -3090,13 +3090,13 @@ msgstr "Er ERPNext installert på et annet nettsted?"
#. Label of the is_group (Check) field in DocType 'CRM Territory'
#: crm/fcrm/doctype/crm_territory/crm_territory.json
msgid "Is Group"
msgstr ""
msgstr "Er gruppe"
#. Label of the is_helpdesk_in_different_site (Check) field in DocType
#. 'Helpdesk CRM Settings'
#: crm/fcrm/doctype/helpdesk_crm_settings/helpdesk_crm_settings.json
msgid "Is Helpdesk installed on a different site?"
msgstr ""
msgstr "Er Helpdesk installert på et annet nettsted?"
#. Label of the is_primary (Check) field in DocType 'CRM Contacts'
#. Label of the is_primary (Check) field in DocType 'CRM Telephony Phone'
@ -3123,7 +3123,7 @@ msgstr ""
#. Label of the json (JSON) field in DocType 'CRM Global Settings'
#: crm/fcrm/doctype/crm_global_settings/crm_global_settings.json
msgid "JSON"
msgstr ""
msgstr "JSON"
#. Label of the job_title (Data) field in DocType 'CRM Deal'
#. Label of the job_title (Data) field in DocType 'CRM Lead'
@ -3165,7 +3165,7 @@ msgstr "Innstillinger for Kanban-tavle"
#. Label of the key (Data) field in DocType 'CRM Invitation'
#: crm/fcrm/doctype/crm_invitation/crm_invitation.json
msgid "Key"
msgstr ""
msgstr "Nøkkel"
#. Label of the label (Data) field in DocType 'CRM Dropdown Item'
#. Label of the label (Data) field in DocType 'CRM View Settings'
@ -3215,8 +3215,8 @@ msgstr ""
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr ""
@ -3246,7 +3246,7 @@ msgstr ""
#: frontend/src/components/Telephony/ExotelCallUI.vue:200
#: frontend/src/pages/Tasks.vue:133
msgid "Lead"
msgstr ""
msgstr "Potensiell kunde"
#. Label of the lead_details_tab (Tab Break) field in DocType 'CRM Deal'
#: crm/fcrm/doctype/crm_deal/crm_deal.json
@ -3577,7 +3577,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr ""
@ -3628,7 +3628,7 @@ msgstr ""
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr ""
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr ""
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr ""
@ -3882,7 +3882,7 @@ msgstr ""
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr "Ingen {0} funnet"
@ -4112,8 +4112,8 @@ msgstr ""
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr ""
@ -4143,7 +4143,7 @@ msgstr ""
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr ""
@ -4237,7 +4237,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr ""
@ -4832,7 +4832,7 @@ msgstr ""
#: frontend/src/components/ViewControls.vue:125
#: frontend/src/pages/Dashboard.vue:36
msgid "Save"
msgstr ""
msgstr "Lagre"
#: frontend/src/components/Modals/ViewModal.vue:40
#: frontend/src/components/ViewControls.vue:58
@ -4904,7 +4904,7 @@ msgstr "Velg {0}"
#: frontend/src/components/EmailEditor.vue:165
msgid "Send"
msgstr ""
msgstr "Send"
#: frontend/src/components/Settings/InviteUserPage.vue:18
msgid "Send Invites"
@ -4934,7 +4934,7 @@ msgstr ""
#. Label of the naming_series (Select) field in DocType 'CRM Lead'
#: crm/fcrm/doctype/crm_lead/crm_lead.json
msgid "Series"
msgstr ""
msgstr "Nummerserie"
#. Label of the service_provider (Select) field in DocType 'FCRM Settings'
#: crm/fcrm/doctype/fcrm_settings/fcrm_settings.json
@ -5177,9 +5177,9 @@ msgstr ""
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr ""
msgstr "Status"
#. Label of the status_change_log (Table) field in DocType 'CRM Deal'
#. Label of the status_change_log (Table) field in DocType 'CRM Lead'
@ -5326,7 +5326,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_organization/crm_organization.json
msgid "Territory"
msgstr ""
msgstr "Territorium"
#. Label of the territory_manager (Link) field in DocType 'CRM Territory'
#: crm/fcrm/doctype/crm_territory/crm_territory.json
@ -5478,7 +5478,7 @@ msgstr ""
#: frontend/src/components/Modals/SidePanelModal.vue:59
msgid "Toggle on for preview"
msgstr ""
msgstr "Slå på for forhåndsvisning"
#: frontend/src/components/Filter.vue:631
msgid "Tomorrow"
@ -5685,7 +5685,7 @@ msgstr ""
#: frontend/src/components/Settings/TelephonySettings.vue:23
#: frontend/src/components/Telephony/ExotelCallUI.vue:210
msgid "Update"
msgstr ""
msgstr "Oppdater"
#: frontend/src/components/Settings/EmailEdit.vue:74
msgid "Update Account"
@ -5732,7 +5732,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: crm/fcrm/doctype/crm_view_settings/crm_view_settings.json
msgid "User"
msgstr ""
msgstr "Bruker"
#. Label of the user_name (Data) field in DocType 'CRM Telephony Agent'
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
@ -5787,7 +5787,7 @@ msgstr ""
#. Settings'
#: crm/fcrm/doctype/crm_exotel_settings/crm_exotel_settings.json
msgid "Webhook Verify Token"
msgstr ""
msgstr "Webhook-verifiseringstoken"
#. Label of the website (Data) field in DocType 'CRM Deal'
#. Label of the website (Data) field in DocType 'CRM Lead'
@ -5797,7 +5797,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_organization/crm_organization.json
#: frontend/src/components/Modals/AboutModal.vue:52
msgid "Website"
msgstr ""
msgstr "Nettsted"
#. Option for the 'Weekly Off' (Select) field in DocType 'CRM Holiday List'
#. Option for the 'Workday' (Select) field in DocType 'CRM Service Day'

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-07 17:34\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:02\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Dutch\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr ""
@ -1645,7 +1645,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr ""
@ -2166,8 +2166,8 @@ msgstr ""
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr ""
@ -3215,8 +3215,8 @@ msgstr ""
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr ""
@ -3577,7 +3577,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr ""
@ -3628,7 +3628,7 @@ msgstr ""
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr ""
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr ""
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr ""
@ -3882,7 +3882,7 @@ msgstr ""
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr ""
@ -4112,8 +4112,8 @@ msgstr ""
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr ""
@ -4143,7 +4143,7 @@ msgstr ""
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr ""
@ -4237,7 +4237,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr ""
@ -5177,7 +5177,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr ""

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-07 17:34\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:02\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Polish\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr ""
@ -1645,7 +1645,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr ""
@ -2166,8 +2166,8 @@ msgstr ""
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr ""
@ -3215,8 +3215,8 @@ msgstr "Ostatni rok"
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr ""
@ -3577,7 +3577,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr ""
@ -3628,7 +3628,7 @@ msgstr ""
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr ""
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr ""
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr ""
@ -3882,7 +3882,7 @@ msgstr ""
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr ""
@ -4112,8 +4112,8 @@ msgstr ""
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr ""
@ -4143,7 +4143,7 @@ msgstr ""
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr ""
@ -4237,7 +4237,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr ""
@ -5177,7 +5177,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr ""

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-15 19:46\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-17 20:27\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Portuguese\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr "Montante"
@ -588,7 +588,7 @@ msgstr "Atribuído a"
#: frontend/src/components/Settings/AssignmentRules/AssigneeRules.vue:5
msgid "Assignee Rules"
msgstr ""
msgstr "Regras de Atribuição"
#: frontend/src/components/Settings/AssignmentRules/AssigneeRules.vue:75
msgid "Assignees"
@ -1645,7 +1645,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr ""
@ -2166,8 +2166,8 @@ msgstr ""
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr "E-mail"
@ -3215,8 +3215,8 @@ msgstr "Último ano"
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr "Última modificação"
@ -3577,7 +3577,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr "Nr. de Telemóvel"
@ -3628,7 +3628,7 @@ msgstr ""
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr "Nome"
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr ""
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr ""
@ -3882,7 +3882,7 @@ msgstr "{0} não disponível"
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr "{0} não encontrado"
@ -4112,8 +4112,8 @@ msgstr "Ordenar por"
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr "Organização"
@ -4143,7 +4143,7 @@ msgstr "Logótipo da organização"
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr "Organizações"
@ -4237,7 +4237,7 @@ msgstr "Pessoa"
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr "Telefone"
@ -5177,7 +5177,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr "Estado"

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-07 17:34\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:02\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Portuguese, Brazilian\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr "Montante"
@ -1645,7 +1645,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr ""
@ -2166,8 +2166,8 @@ msgstr ""
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr ""
@ -3215,8 +3215,8 @@ msgstr "Ano passado"
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr ""
@ -3577,7 +3577,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr ""
@ -3628,7 +3628,7 @@ msgstr ""
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr "Nome"
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr ""
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr ""
@ -3882,7 +3882,7 @@ msgstr ""
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr ""
@ -4112,8 +4112,8 @@ msgstr "Ordenar Por"
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr "Organização"
@ -4143,7 +4143,7 @@ msgstr ""
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr ""
@ -4237,7 +4237,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr "Telefone"
@ -5177,7 +5177,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr ""

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-07 17:34\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:02\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Russian\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr ""
@ -1645,7 +1645,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr ""
@ -2166,8 +2166,8 @@ msgstr ""
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr ""
@ -3215,8 +3215,8 @@ msgstr ""
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr ""
@ -3577,7 +3577,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr ""
@ -3628,7 +3628,7 @@ msgstr ""
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr ""
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr ""
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr ""
@ -3882,7 +3882,7 @@ msgstr ""
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr "Не найдено {0}"
@ -4112,8 +4112,8 @@ msgstr ""
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr ""
@ -4143,7 +4143,7 @@ msgstr ""
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr ""
@ -4237,7 +4237,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr ""
@ -5177,7 +5177,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr ""

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-09 18:08\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:02\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Serbian (Cyrillic)\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr "Цео дан"
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr "Износ"
@ -1645,7 +1645,7 @@ msgstr "Анализа канала за генерисање пословних
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr "Власник пословне прилике"
@ -2166,8 +2166,8 @@ msgstr "Уређивање догађаја"
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr "Имејл"
@ -3215,8 +3215,8 @@ msgstr "Прошла година"
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr "Последњи пут измењено"
@ -3577,7 +3577,7 @@ msgstr "Инсталација мобилне апликације"
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr "Број мобилног телефона"
@ -3628,7 +3628,7 @@ msgstr "Моје отворене пословне прилике"
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr "Назив"
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr "Нису пронађени корисници"
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr "Није пронађен веб-сајт"
@ -3882,7 +3882,7 @@ msgstr "Нема доступних {0}"
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr "Није пронађен ниједан {0}"
@ -4112,8 +4112,8 @@ msgstr "Наруџбина од"
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr "Организација"
@ -4143,7 +4143,7 @@ msgstr "Лого организације"
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr "Организације"
@ -4237,7 +4237,7 @@ msgstr "Особа"
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr "Телефон"
@ -5177,7 +5177,7 @@ msgstr "Започни са 10 пробних потенцијалних кли
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr "Статус"

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-09 18:08\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:02\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Serbian (Latin)\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr "Ceo dan"
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr "Iznos"
@ -1645,7 +1645,7 @@ msgstr "Analiza kanala za generisanje poslovnih prilika"
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr "Vlasnik poslovne prilike"
@ -2166,8 +2166,8 @@ msgstr "Uređivanje događaja"
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr "Imejl"
@ -3215,8 +3215,8 @@ msgstr "Prošla godina"
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr "Poslednji put izmenjeno"
@ -3577,7 +3577,7 @@ msgstr "Instalacija mobilne aplikacije"
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr "Broj mobilnog telefona"
@ -3628,7 +3628,7 @@ msgstr "Moje otvorene poslovne prilike"
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr "Naziv"
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr "Nisu pronađeni korisnici"
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr "Nije pronađen veb-sajt"
@ -3882,7 +3882,7 @@ msgstr "Nema dostupnih {0}"
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr "Nije pronađen nijedan {0}"
@ -4112,8 +4112,8 @@ msgstr "Narudžbina od"
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr "Organizacija"
@ -4143,7 +4143,7 @@ msgstr "Logo organizacije"
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr "Organizacije"
@ -4237,7 +4237,7 @@ msgstr "Osoba"
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr "Telefon"
@ -5177,7 +5177,7 @@ msgstr "Započni sa 10 probnih potencijalnih klijenata"
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr "Status"

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-07 17:34\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:02\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Swedish\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr "Hela dagen"
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr "Belopp"
@ -1645,7 +1645,7 @@ msgstr "Affär generering kanal analys"
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr "Affär Ansvarig"
@ -2166,8 +2166,8 @@ msgstr "Redigerar händelse"
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr "E-post"
@ -3215,8 +3215,8 @@ msgstr "Förra Året"
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr "Senast ändrad"
@ -3577,7 +3577,7 @@ msgstr "Mobil App Installation"
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr "Mobilnummer"
@ -3628,7 +3628,7 @@ msgstr "Mina Öppna Affärer"
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr "Namn"
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr "Inga användare hittades"
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr "Ingen webbplats hittades"
@ -3882,7 +3882,7 @@ msgstr "Ingen {0} Tillgänglig"
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr "{0}"
@ -4112,8 +4112,8 @@ msgstr "Sortera Efter"
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr "Organisation"
@ -4143,7 +4143,7 @@ msgstr "Organisation Logotyp"
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr "Organisationer"
@ -4237,7 +4237,7 @@ msgstr "Person"
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr "Telefon"
@ -5183,7 +5183,7 @@ msgstr "Börja med exempel på 10 potentiella kunder"
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr "Status"

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-07 17:34\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:03\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Thai\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr "จำนวน"
@ -1645,7 +1645,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr ""
@ -2166,8 +2166,8 @@ msgstr ""
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr "อีเมล"
@ -3215,8 +3215,8 @@ msgstr "ปีที่แล้ว"
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr ""
@ -3577,7 +3577,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr ""
@ -3628,7 +3628,7 @@ msgstr ""
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr "ชื่อ"
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr ""
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr ""
@ -3882,7 +3882,7 @@ msgstr ""
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr "ไม่พบ {0}"
@ -4112,8 +4112,8 @@ msgstr "เรียงตาม"
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr "องค์กร"
@ -4143,7 +4143,7 @@ msgstr ""
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr ""
@ -4237,7 +4237,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr "โทรศัพท์"
@ -5177,7 +5177,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr "สถานะ"

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-11 18:51\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:02\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Turkish\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr "Tutar"
@ -1645,7 +1645,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr ""
@ -2166,8 +2166,8 @@ msgstr ""
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr "E-posta"
@ -3215,8 +3215,8 @@ msgstr "Geçen Yıl"
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr ""
@ -3577,7 +3577,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr ""
@ -3628,7 +3628,7 @@ msgstr ""
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr "Adı"
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr ""
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr ""
@ -3882,7 +3882,7 @@ msgstr ""
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr "{0} Bulunamadı"
@ -4112,8 +4112,8 @@ msgstr "Sipariş Veren"
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr "Organizasyon"
@ -4143,7 +4143,7 @@ msgstr ""
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr ""
@ -4237,7 +4237,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr "Telefon"
@ -5177,7 +5177,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr "Durum"

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-07 17:34\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:02\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Vietnamese\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr ""
@ -1645,7 +1645,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr ""
@ -2166,8 +2166,8 @@ msgstr ""
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr ""
@ -3215,8 +3215,8 @@ msgstr ""
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr ""
@ -3577,7 +3577,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr ""
@ -3628,7 +3628,7 @@ msgstr ""
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr ""
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr ""
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr ""
@ -3882,7 +3882,7 @@ msgstr ""
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr ""
@ -4112,8 +4112,8 @@ msgstr ""
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr ""
@ -4143,7 +4143,7 @@ msgstr ""
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr ""
@ -4237,7 +4237,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr ""
@ -5177,7 +5177,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr ""

View File

@ -2,8 +2,8 @@ msgid ""
msgstr ""
"Project-Id-Version: frappe\n"
"Report-Msgid-Bugs-To: shariq@frappe.io\n"
"POT-Creation-Date: 2025-09-07 09:35+0000\n"
"PO-Revision-Date: 2025-09-07 17:34\n"
"POT-Creation-Date: 2025-09-14 09:35+0000\n"
"PO-Revision-Date: 2025-09-16 20:02\n"
"Last-Translator: shariq@frappe.io\n"
"Language-Team: Chinese Simplified\n"
"MIME-Version: 1.0\n"
@ -430,7 +430,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_products/crm_products.json
#: frontend/src/pages/Contact.vue:499 frontend/src/pages/MobileContact.vue:507
#: frontend/src/pages/MobileOrganization.vue:451
#: frontend/src/pages/Organization.vue:458
#: frontend/src/pages/Organization.vue:472
msgid "Amount"
msgstr "金额"
@ -1645,7 +1645,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:520 frontend/src/pages/MobileContact.vue:528
#: frontend/src/pages/MobileOrganization.vue:472
#: frontend/src/pages/Organization.vue:479
#: frontend/src/pages/Organization.vue:493
msgid "Deal owner"
msgstr "商机负责人"
@ -2166,8 +2166,8 @@ msgstr ""
#: frontend/src/pages/MobileContact.vue:518
#: frontend/src/pages/MobileOrganization.vue:462
#: frontend/src/pages/MobileOrganization.vue:490
#: frontend/src/pages/Organization.vue:469
#: frontend/src/pages/Organization.vue:497
#: frontend/src/pages/Organization.vue:483
#: frontend/src/pages/Organization.vue:511
msgid "Email"
msgstr "电子邮件"
@ -3215,8 +3215,8 @@ msgstr "去年"
#: frontend/src/pages/Contact.vue:525 frontend/src/pages/MobileContact.vue:533
#: frontend/src/pages/MobileOrganization.vue:477
#: frontend/src/pages/MobileOrganization.vue:505
#: frontend/src/pages/Organization.vue:484
#: frontend/src/pages/Organization.vue:512
#: frontend/src/pages/Organization.vue:498
#: frontend/src/pages/Organization.vue:526
msgid "Last modified"
msgstr "最后修改"
@ -3577,7 +3577,7 @@ msgstr ""
#: frontend/src/pages/Contact.vue:515 frontend/src/pages/MobileContact.vue:523
#: frontend/src/pages/MobileOrganization.vue:467
#: frontend/src/pages/Organization.vue:474
#: frontend/src/pages/Organization.vue:488
msgid "Mobile no"
msgstr "手机号"
@ -3628,7 +3628,7 @@ msgstr "我负责的开放商机"
#: frontend/src/components/Settings/EmailTemplate/NewEmailTemplate.vue:42
#: frontend/src/components/ViewControls.vue:779
#: frontend/src/pages/MobileOrganization.vue:485
#: frontend/src/pages/Organization.vue:492
#: frontend/src/pages/Organization.vue:506
msgid "Name"
msgstr "名称"
@ -3866,7 +3866,7 @@ msgid "No users found"
msgstr ""
#: frontend/src/pages/MobileOrganization.vue:281
#: frontend/src/pages/Organization.vue:295
#: frontend/src/pages/Organization.vue:309
msgid "No website found"
msgstr ""
@ -3882,7 +3882,7 @@ msgstr "无可用{0}"
#: frontend/src/pages/Contacts.vue:58 frontend/src/pages/Deals.vue:234
#: frontend/src/pages/Leads.vue:260 frontend/src/pages/MobileContact.vue:147
#: frontend/src/pages/MobileOrganization.vue:139
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:151
#: frontend/src/pages/Notes.vue:95 frontend/src/pages/Organization.vue:152
#: frontend/src/pages/Organizations.vue:58 frontend/src/pages/Tasks.vue:184
msgid "No {0} Found"
msgstr "未找到{0}"
@ -4112,8 +4112,8 @@ msgstr "排序依据"
#: frontend/src/pages/MobileLead.vue:118
#: frontend/src/pages/MobileOrganization.vue:446
#: frontend/src/pages/MobileOrganization.vue:500
#: frontend/src/pages/Organization.vue:453
#: frontend/src/pages/Organization.vue:507
#: frontend/src/pages/Organization.vue:467
#: frontend/src/pages/Organization.vue:521
msgid "Organization"
msgstr "组织"
@ -4143,7 +4143,7 @@ msgstr "组织徽标"
#. Label of a shortcut in the Frappe CRM Workspace
#: crm/fcrm/workspace/frappe_crm/frappe_crm.json
#: frontend/src/pages/MobileOrganization.vue:205
#: frontend/src/pages/Organization.vue:233
#: frontend/src/pages/Organization.vue:234
msgid "Organizations"
msgstr "组织"
@ -4237,7 +4237,7 @@ msgstr "个人"
#: crm/fcrm/doctype/crm_lead/crm_lead.json
#: crm/fcrm/doctype/crm_telephony_agent/crm_telephony_agent.json
#: frontend/src/pages/MobileOrganization.vue:495
#: frontend/src/pages/Organization.vue:502
#: frontend/src/pages/Organization.vue:516
msgid "Phone"
msgstr "电话"
@ -5177,7 +5177,7 @@ msgstr ""
#: crm/fcrm/doctype/crm_task/crm_task.json frontend/src/pages/Contact.vue:505
#: frontend/src/pages/MobileContact.vue:513
#: frontend/src/pages/MobileOrganization.vue:457
#: frontend/src/pages/Organization.vue:464
#: frontend/src/pages/Organization.vue:478
msgid "Status"
msgstr "状态"

View File

@ -16,3 +16,4 @@ crm.patches.v1_0.create_default_scripts # 13-06-2025
crm.patches.v1_0.update_deal_status_probabilities
crm.patches.v1_0.update_deal_status_type
crm.patches.v1_0.create_default_lost_reasons
crm.patches.v1_0.add_fields_in_assignment_rule

View File

@ -0,0 +1,9 @@
from crm.install import (
add_assignment_rule_property_setters,
create_assignment_rule_custom_fields,
)
def execute():
create_assignment_rule_custom_fields()
add_assignment_rule_property_setters()

@ -1 +1 @@
Subproject commit 02fc126fd5c49f0ecf6cce117585f89c4ea585c3
Subproject commit c9a0fc937cc897864857271b3708a0c675379015

1
frontend/.gitignore vendored
View File

@ -3,3 +3,4 @@ node_modules
dist
dist-ssr
*.local
components.d.ts

View File

@ -33,7 +33,7 @@ declare module 'vue' {
Autocomplete: typeof import('./src/components/frappe-ui/Autocomplete.vue')['default']
AvatarIcon: typeof import('./src/components/Icons/AvatarIcon.vue')['default']
BrandLogo: typeof import('./src/components/BrandLogo.vue')['default']
BrandSettings: typeof import('./src/components/Settings/General/BrandSettings.vue')['default']
BrandSettings: typeof import('./src/components/Settings/BrandSettings.vue')['default']
BulkDeleteLinkedDocModal: typeof import('./src/components/BulkDeleteLinkedDocModal.vue')['default']
CalendarIcon: typeof import('./src/components/Icons/CalendarIcon.vue')['default']
CallArea: typeof import('./src/components/Activities/CallArea.vue')['default']
@ -63,7 +63,7 @@ declare module 'vue' {
CountUpTimer: typeof import('./src/components/CountUpTimer.vue')['default']
CreateDocumentModal: typeof import('./src/components/Modals/CreateDocumentModal.vue')['default']
CRMLogo: typeof import('./src/components/Icons/CRMLogo.vue')['default']
CurrencySettings: typeof import('./src/components/Settings/General/CurrencySettings.vue')['default']
CurrencySettings: typeof import('./src/components/Settings/CurrencySettings.vue')['default']
CustomActions: typeof import('./src/components/CustomActions.vue')['default']
DashboardGrid: typeof import('./src/components/Dashboard/DashboardGrid.vue')['default']
DashboardIcon: typeof import('./src/components/Icons/DashboardIcon.vue')['default']
@ -127,11 +127,10 @@ declare module 'vue' {
FileVideoIcon: typeof import('./src/components/Icons/FileVideoIcon.vue')['default']
Filter: typeof import('./src/components/Filter.vue')['default']
FilterIcon: typeof import('./src/components/Icons/FilterIcon.vue')['default']
ForecastingSettings: typeof import('./src/components/Settings/ForecastingSettings.vue')['default']
FormattedInput: typeof import('./src/components/Controls/FormattedInput.vue')['default']
FrappeCloudIcon: typeof import('./src/components/Icons/FrappeCloudIcon.vue')['default']
GenderIcon: typeof import('./src/components/Icons/GenderIcon.vue')['default']
GeneralSettings: typeof import('./src/components/Settings/General/GeneralSettings.vue')['default']
GeneralSettingsPage: typeof import('./src/components/Settings/General/GeneralSettingsPage.vue')['default']
GlobalModals: typeof import('./src/components/Modals/GlobalModals.vue')['default']
GoogleIcon: typeof import('./src/components/Icons/GoogleIcon.vue')['default']
Grid: typeof import('./src/components/Controls/Grid.vue')['default']
@ -142,7 +141,7 @@ declare module 'vue' {
GroupByIcon: typeof import('./src/components/Icons/GroupByIcon.vue')['default']
HeartIcon: typeof import('./src/components/Icons/HeartIcon.vue')['default']
HelpIcon: typeof import('./src/components/Icons/HelpIcon.vue')['default']
HomeActions: typeof import('./src/components/Settings/General/HomeActions.vue')['default']
HomeActions: typeof import('./src/components/Settings/HomeActions.vue')['default']
Icon: typeof import('./src/components/Icon.vue')['default']
IconPicker: typeof import('./src/components/IconPicker.vue')['default']
ImageUploader: typeof import('./src/components/Controls/ImageUploader.vue')['default']
@ -229,6 +228,7 @@ declare module 'vue' {
SmileIcon: typeof import('./src/components/Icons/SmileIcon.vue')['default']
SortBy: typeof import('./src/components/SortBy.vue')['default']
SortIcon: typeof import('./src/components/Icons/SortIcon.vue')['default']
SparkleIcon: typeof import('./src/components/Icons/SparkleIcon.vue')['default']
SquareAsterisk: typeof import('./src/components/Icons/SquareAsterisk.vue')['default']
StepsIcon: typeof import('./src/components/Icons/StepsIcon.vue')['default']
SuccessIcon: typeof import('./src/components/Icons/SuccessIcon.vue')['default']

View File

@ -13,7 +13,7 @@
"@tiptap/extension-paragraph": "^2.12.0",
"@twilio/voice-sdk": "^2.10.2",
"@vueuse/integrations": "^10.3.0",
"frappe-ui": "^0.1.197",
"frappe-ui": "^0.1.200",
"gemoji": "^8.1.0",
"lodash": "^4.17.21",
"mime": "^4.0.1",

View File

@ -0,0 +1,454 @@
<template>
<div
class="flex gap-2"
:class="[
{
'items-center': !props.isGroup,
},
]"
>
<div
class="flex gap-2 w-full"
:class="[
{
'items-center justify-between': !props.isGroup,
},
]"
>
<div :class="'text-end text-base text-gray-600'">
<div v-if="props.itemIndex == 0" class="min-w-[66px] text-start">
{{ __('Where') }}
</div>
<div v-else class="min-w-[66px] flex items-start">
<Button
variant="subtle"
class="w-max"
@click="toggleConjunction"
icon-right="refresh-cw"
:disabled="props.itemIndex > 2"
:label="conjunction"
/>
</div>
</div>
<div v-if="!props.isGroup" class="flex items-center gap-2 w-full">
<div id="fieldname" class="w-full">
<Autocomplete
:options="filterableFields.data"
v-model="props.condition[0]"
:placeholder="__('Field')"
@update:modelValue="updateField"
/>
</div>
<div id="operator">
<FormControl
v-if="!props.condition[0]"
disabled
type="text"
:placeholder="__('operator')"
class="w-[100px]"
/>
<FormControl
v-else
:disabled="!props.condition[0]"
type="select"
v-model="props.condition[1]"
@change="updateOperator"
:options="getOperators()"
class="w-max min-w-[100px]"
/>
</div>
<div id="value" class="w-full">
<FormControl
v-if="!props.condition[0]"
disabled
type="text"
:placeholder="__('condition')"
class="w-full"
/>
<component
v-else
:is="getValueControl()"
v-model="props.condition[2]"
@change="updateValue"
:placeholder="__('condition')"
/>
</div>
</div>
<CFConditions
v-if="props.isGroup && !(props.level == 2 || props.level == 4)"
:conditions="props.condition"
:isChild="true"
:level="props.level"
:disableAddCondition="props.disableAddCondition"
/>
<Button
variant="outline"
v-if="props.isGroup && (props.level == 2 || props.level == 4)"
@click="show = true"
:label="__('Open nested conditions')"
/>
</div>
<div :class="'w-max'">
<Dropdown placement="right" :options="dropdownOptions">
<Button variant="ghost" icon="more-horizontal" />
</Dropdown>
</div>
</div>
<Dialog
v-model="show"
:options="{ size: '3xl', title: __('Nested conditions') }"
>
<template #body-content>
<CFConditions
:conditions="props.condition"
:isChild="true"
:level="props.level"
:disableAddCondition="props.disableAddCondition"
/>
</template>
</Dialog>
</template>
<script setup>
import {
Autocomplete,
Button,
DatePicker,
DateRangePicker,
DateTimePicker,
Dialog,
Dropdown,
FormControl,
Rating,
} from 'frappe-ui'
import { computed, defineEmits, h, ref } from 'vue'
import GroupIcon from '~icons/lucide/group'
import UnGroupIcon from '~icons/lucide/ungroup'
import CFConditions from './CFConditions.vue'
import { filterableFields } from './filterableFields'
import Link from '@/components/Controls/Link.vue'
const show = ref(false)
const emit = defineEmits([
'remove',
'unGroupConditions',
'toggleConjunction',
'turnIntoGroup',
])
const props = defineProps({
condition: {
type: Array,
required: true,
},
isChild: {
type: Boolean,
default: false,
},
itemIndex: {
type: Number,
},
level: {
type: Number,
default: 0,
},
isGroup: {
type: Boolean,
default: false,
},
conjunction: {
type: String,
},
disableAddCondition: {
type: Boolean,
default: false,
},
})
const dropdownOptions = computed(() => {
const options = []
if (!props.isGroup && props.level < 4) {
options.push({
label: __('Turn into a group'),
icon: () => h(GroupIcon),
onClick: () => {
emit('turnIntoGroup')
},
})
}
if (props.isGroup) {
options.push({
label: __('Ungroup conditions'),
icon: () => h(UnGroupIcon),
onClick: () => {
emit('unGroupConditions')
},
})
}
options.push({
label: __('Remove'),
icon: 'trash-2',
variant: 'red',
onClick: () => emit('remove'),
condition: () => !props.isGroup,
})
options.push({
label: __('Remove group'),
icon: 'trash-2',
variant: 'red',
onClick: () => emit('remove'),
condition: () => props.isGroup,
})
return options
})
const typeCheck = ['Check']
const typeLink = ['Link', 'Dynamic Link']
const typeNumber = ['Float', 'Int', 'Currency', 'Percent']
const typeSelect = ['Select']
const typeString = ['Data', 'Long Text', 'Small Text', 'Text Editor', 'Text']
const typeDate = ['Date', 'Datetime']
const typeRating = ['Rating']
function toggleConjunction() {
emit('toggleConjunction', props.conjunction)
}
const updateField = (field) => {
props.condition[0] = field?.fieldname
resetConditionValue()
}
const resetConditionValue = () => {
props.condition[2] = ''
}
function getValueControl() {
const [field, operator] = props.condition
if (!field) return null
const fieldData = filterableFields.data?.find((f) => f.fieldname == field)
if (!fieldData) return null
const { fieldtype, options } = fieldData
if (operator == 'is') {
return h(FormControl, {
type: 'select',
options: [
{
label: 'Set',
value: 'set',
},
{
label: 'Not Set',
value: 'not set',
},
],
})
} else if (['like', 'not like', 'in', 'not in'].includes(operator)) {
return h(FormControl, { type: 'text' })
} else if (typeSelect.includes(fieldtype) || typeCheck.includes(fieldtype)) {
const _options =
fieldtype == 'Check' ? ['Yes', 'No'] : getSelectOptions(options)
return h(FormControl, {
type: 'select',
options: _options.map((o) => ({
label: o,
value: o,
})),
})
} else if (typeLink.includes(fieldtype)) {
if (fieldtype == 'Dynamic Link') {
return h(FormControl, { type: 'text' })
}
return h(Link, {
class: 'form-control',
doctype: options,
value: props.condition[2],
})
} else if (typeNumber.includes(fieldtype)) {
return h(FormControl, { type: 'number' })
} else if (typeDate.includes(fieldtype) && operator == 'between') {
return h(DateRangePicker, { value: props.condition[2], iconLeft: '' })
} else if (typeDate.includes(fieldtype)) {
return h(fieldtype == 'Date' ? DatePicker : DateTimePicker, {
value: props.condition[2],
iconLeft: '',
})
} else if (typeRating.includes(fieldtype)) {
return h(Rating, {
modelValue: props.condition[2] || 0,
class: 'truncate',
'update:modelValue': (v) => updateValue(v),
})
} else {
return h(FormControl, { type: 'text' })
}
}
function updateValue(value) {
value = value.target ? value.target.value : value
if (props.condition[1] === 'between') {
props.condition[2] = [value.split(',')[0], value.split(',')[1]]
} else {
props.condition[2] = value + ''
}
}
function getSelectOptions(options) {
return options.split('\n')
}
function updateOperator(event) {
let oldOperatorValue = event.target._value
let newOperatorValue = event.target.value
props.condition[1] = event.target.value
if (!isSameTypeOperator(oldOperatorValue, newOperatorValue)) {
props.condition[2] = getDefaultValue(props.condition[0])
}
resetConditionValue()
}
function getOperators() {
let options = []
const field = props.condition[0]
if (!field) return options
const fieldData = filterableFields.data?.find((f) => f.fieldname == field)
if (!fieldData) return options
const { fieldtype, fieldname } = fieldData
if (typeString.includes(fieldtype)) {
options.push(
...[
{ label: 'Equals', value: '==' },
{ label: 'Not Equals', value: '!=' },
{ label: 'Like', value: 'like' },
{ label: 'Not Like', value: 'not like' },
{ label: 'In', value: 'in' },
{ label: 'Not In', value: 'not in' },
{ label: 'Is', value: 'is' },
],
)
}
if (fieldname === '_assign') {
options = [
{ label: 'Like', value: 'like' },
{ label: 'Not Like', value: 'not like' },
{ label: 'Is', value: 'is' },
]
}
if (typeNumber.includes(fieldtype)) {
options.push(
...[
{ label: 'Equals', value: '==' },
{ label: 'Not Equals', value: '!=' },
{ label: 'Like', value: 'like' },
{ label: 'Not Like', value: 'not like' },
{ label: 'In', value: 'in' },
{ label: 'Not In', value: 'not in' },
{ label: 'Is', value: 'is' },
{ label: '<', value: '<' },
{ label: '>', value: '>' },
{ label: '<=', value: '<=' },
{ label: '>=', value: '>=' },
],
)
}
if (typeSelect.includes(fieldtype)) {
options.push(
...[
{ label: 'Equals', value: '==' },
{ label: 'Not Equals', value: '!=' },
{ label: 'In', value: 'in' },
{ label: 'Not In', value: 'not in' },
{ label: 'Is', value: 'is' },
],
)
}
if (typeLink.includes(fieldtype)) {
options.push(
...[
{ label: 'Equals', value: '==' },
{ label: 'Not Equals', value: '!=' },
{ label: 'Like', value: 'like' },
{ label: 'Not Like', value: 'not like' },
{ label: 'In', value: 'in' },
{ label: 'Not In', value: 'not in' },
{ label: 'Is', value: 'is' },
],
)
}
if (typeCheck.includes(fieldtype)) {
options.push(...[{ label: 'Equals', value: '==' }])
}
if (['Duration'].includes(fieldtype)) {
options.push(
...[
{ label: 'Like', value: 'like' },
{ label: 'Not Like', value: 'not like' },
{ label: 'In', value: 'in' },
{ label: 'Not In', value: 'not in' },
{ label: 'Is', value: 'is' },
],
)
}
if (typeDate.includes(fieldtype)) {
options.push(
...[
{ label: 'Equals', value: '==' },
{ label: 'Not Equals', value: '!=' },
{ label: 'Is', value: 'is' },
{ label: '>', value: '>' },
{ label: '<', value: '<' },
{ label: '>=', value: '>=' },
{ label: '<=', value: '<=' },
{ label: 'Between', value: 'between' },
],
)
}
if (typeRating.includes(fieldtype)) {
options.push(
...[
{ label: 'Equals', value: '==' },
{ label: 'Not Equals', value: '!=' },
{ label: 'Is', value: 'is' },
{ label: '>', value: '>' },
{ label: '<', value: '<' },
{ label: '>=', value: '>=' },
{ label: '<=', value: '<=' },
],
)
}
const op = options.find((o) => o.value == props.condition[1])
props.condition[1] = op?.value || options[0].value
return options
}
function getDefaultValue(field) {
if (typeSelect.includes(field.fieldtype)) {
return getSelectOptions(field.options)[0]
}
if (typeCheck.includes(field.fieldtype)) {
return 'Yes'
}
if (typeDate.includes(field.fieldtype)) {
return null
}
if (typeRating.includes(field.fieldtype)) {
return 0
}
return ''
}
function isSameTypeOperator(oldOperator, newOperator) {
let textOperators = ['==', '!=', 'in', 'not in', '>', '<', '>=', '<=']
if (
textOperators.includes(oldOperator) &&
textOperators.includes(newOperator)
)
return true
return false
}
</script>

View File

@ -0,0 +1,142 @@
<template>
<div class="rounded-lg border border-outline-gray-2 p-3 flex flex-col gap-4 w-full">
<template v-for="(condition, i) in props.conditions" :key="condition.field">
<CFCondition
v-if="Array.isArray(condition)"
:condition="condition"
:isChild="props.isChild"
:itemIndex="i"
@remove="removeCondition(condition)"
@unGroupConditions="unGroupConditions(condition)"
:level="props.level + 1"
@toggleConjunction="toggleConjunction"
:isGroup="isGroupCondition(condition[0])"
:conjunction="getConjunction()"
@turnIntoGroup="turnIntoGroup(condition)"
:disableAddCondition="props.disableAddCondition"
/>
</template>
<div v-if="props.isChild" class="flex">
<Dropdown v-slot="{ open }" :options="dropdownOptions">
<Button
:disabled="props.disableAddCondition"
:label="__('Add condition')"
icon-left="plus"
:icon-right="open ? 'chevron-up' : 'chevron-down'"
/>
</Dropdown>
</div>
</div>
</template>
<script setup>
import { Button, Dropdown } from 'frappe-ui'
import { computed, watch } from 'vue'
import CFCondition from './CFCondition.vue'
import { filterableFields } from './filterableFields'
const props = defineProps({
conditions: {
type: Array,
required: true,
},
isChild: {
type: Boolean,
default: false,
},
level: {
type: Number,
default: 0,
},
disableAddCondition: {
type: Boolean,
default: false,
},
doctype: {
type: String,
required: true,
},
})
const getConjunction = () => {
let conjunction = 'and'
props.conditions.forEach((condition) => {
if (typeof condition == 'string') {
conjunction = condition
}
})
return conjunction
}
const turnIntoGroup = (condition) => {
props.conditions.splice(props.conditions.indexOf(condition), 1, [condition])
}
const isGroupCondition = (condition) => {
return Array.isArray(condition)
}
const dropdownOptions = computed(() => {
const options = [
{
label: __('Add condition'),
onClick: () => {
const conjunction = getConjunction()
props.conditions.push(conjunction, ['', '', ''])
},
},
]
if (props.level < 3) {
options.push({
label: __('Add condition group'),
onClick: () => {
const conjunction = getConjunction()
props.conditions.push(conjunction, [[]])
},
})
}
return options
})
function removeCondition(condition) {
const conditionIndex = props.conditions.indexOf(condition)
if (conditionIndex == 0) {
props.conditions.splice(conditionIndex, 2)
} else {
props.conditions.splice(conditionIndex - 1, 2)
}
}
function unGroupConditions(condition) {
const conjunction = getConjunction()
const newConditions = condition.map((c) => {
if (typeof c == 'string') {
return conjunction
}
return c
})
const index = props.conditions.indexOf(condition)
if (index !== -1) {
props.conditions.splice(index, 1, ...newConditions)
}
}
function toggleConjunction(conjunction) {
for (let i = 0; i < props.conditions.length; i++) {
if (typeof props.conditions[i] == 'string') {
props.conditions[i] = conjunction == 'and' ? 'or' : 'and'
}
}
}
watch(
() => props.doctype,
(doctype) => {
filterableFields.submit({
doctype,
})
},
{ immediate: true },
)
</script>

View File

@ -0,0 +1,17 @@
import { createResource } from 'frappe-ui'
export const filterableFields = createResource({
url: 'crm.api.doc.get_filterable_fields',
transform: (data) => {
data = data
.filter((field) => !field.fieldname.startsWith('_'))
.map((field) => {
return {
label: field.label,
value: field.fieldname,
...field,
}
})
return data
},
})

View File

@ -1,7 +1,6 @@
<template>
<FileUploader
:file-types="image_type"
class="text-base"
@success="
(file) => {
$emit('upload', file.file_url)
@ -10,21 +9,28 @@
>
<template v-slot="{ progress, uploading, openFileSelector }">
<div class="flex items-end space-x-1">
<Button @click="openFileSelector">
{{
<Button
@click="openFileSelector"
:iconLeft="uploading ? 'cloud-upload' : ImageUpIcon"
:label="
uploading
? `Uploading ${progress}%`
? __('Uploading {0}%', [progress])
: image_url
? 'Change'
: 'Upload'
}}
</Button>
<Button v-if="image_url" @click="$emit('remove')">Remove</Button>
? __('Change')
: __('Upload')
"
/>
<Button
v-if="image_url"
:label="__('Remove')"
@click="$emit('remove')"
/>
</div>
</template>
</FileUploader>
</template>
<script setup>
import ImageUpIcon from '~icons/lucide/image-up'
import { FileUploader, Button } from 'frappe-ui'
const prop = defineProps({
@ -33,10 +39,6 @@ const prop = defineProps({
type: String,
default: 'image/*',
},
label: {
type: String,
default: '',
},
})
const emit = defineEmits(['upload', 'remove'])
</script>

View File

@ -0,0 +1,19 @@
<template>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24"
fill="none"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
class="lucide lucide-settings2-icon lucide-settings-2"
>
<path d="M14 17H5" />
<path d="M19 7h-9" />
<circle cx="17" cy="17" r="3" />
<circle cx="7" cy="7" r="3" />
</svg>
</template>

View File

@ -0,0 +1,16 @@
<template>
<svg
width="16"
height="16"
viewBox="0 0 16 16"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M3.37543 1.93494L4.21632 2.21494C4.35232 2.26027 4.44388 2.38738 4.44388 2.53138C4.44388 2.67538 4.35143 2.80249 4.21543 2.84783L3.37454 3.12783L3.09365 3.9696C3.04921 4.10472 2.92121 4.19716 2.7781 4.19716C2.63499 4.19716 2.50787 4.1056 2.46254 3.9696L2.18165 3.12783L1.34076 2.84783C1.20476 2.80249 1.11232 2.67538 1.11232 2.53138C1.11232 2.38738 1.20476 2.26027 1.34076 2.21494L2.18165 1.93494L2.46254 1.09316C2.55321 0.82116 3.00387 0.82116 3.09454 1.09316L3.37543 1.93494ZM8.44852 1.33394C8.3643 1.16325 8.19046 1.05518 8.00012 1.05518C7.80978 1.05518 7.63595 1.16325 7.55173 1.33394L5.67697 5.13368L1.48388 5.74214C1.29552 5.76947 1.13901 5.90137 1.08017 6.08238C1.02133 6.26339 1.07036 6.46211 1.20665 6.59497L4.24065 9.55281L3.52421 13.7284C3.49203 13.916 3.56913 14.1056 3.7231 14.2174C3.87706 14.3293 4.08119 14.3441 4.24966 14.2555L8.11188 12.2253C8.35631 12.0968 8.4503 11.7945 8.32181 11.5501C8.19333 11.3057 7.89102 11.2117 7.64659 11.3402L4.68114 12.899L5.2707 9.46284C5.29853 9.30065 5.24477 9.13514 5.12693 9.02027L2.63025 6.58626L6.08082 6.08555C6.24373 6.06191 6.38457 5.95959 6.45741 5.81196L8.00012 2.6852L9.54284 5.81196C9.61568 5.95959 9.75652 6.06191 9.91943 6.08555L13.37 6.58625L11.6235 8.2887C11.4258 8.48146 11.4218 8.79802 11.6145 8.99575C11.8073 9.19349 12.1239 9.19752 12.3216 9.00476L14.7936 6.59498C14.9299 6.46212 14.9789 6.2634 14.9201 6.08239C14.8612 5.90138 14.7047 5.76947 14.5164 5.74214L10.3233 5.13368L8.44852 1.33394ZM13.4744 11.9911L12.3517 11.6168L11.9775 10.4942C11.8557 10.1315 11.2557 10.1315 11.1339 10.4942L10.7597 11.6168L9.63702 11.9911C9.45569 12.0515 9.33302 12.2213 9.33302 12.4124C9.33302 12.6035 9.45569 12.7733 9.63702 12.8337L10.7597 13.2079L11.1339 14.3306C11.1944 14.5119 11.365 14.6346 11.5561 14.6346C11.7472 14.6346 11.917 14.5119 11.9784 14.3306L12.3526 13.2079L13.4752 12.8337C13.6566 12.7733 13.7792 12.6035 13.7792 12.4124C13.7792 12.2213 13.6566 12.0515 13.4752 11.9911H13.4744ZM13.3333 2.88883C13.3333 3.25702 13.0349 3.5555 12.6667 3.5555C12.2985 3.5555 12 3.25702 12 2.88883C12 2.52064 12.2985 2.22217 12.6667 2.22217C13.0349 2.22217 13.3333 2.52064 13.3333 2.88883Z"
fill="currentColor"
/>
</svg>
</template>

View File

@ -0,0 +1,159 @@
<template>
<div>
<div class="flex flex-col gap-1">
<span class="text-lg font-semibold text-ink-gray-8">{{
__('Assignee Rules')
}}</span>
<span class="text-p-sm text-ink-gray-6">
{{
__('Choose how {0} are assigned among salespeople.', [documentType])
}}
</span>
</div>
<div class="mt-8 flex items-center justify-between gap-2">
<div>
<div class="text-base font-medium text-ink-gray-8">
{{
__('{0} Routing', [
assignmentRuleData.documentType == 'CRM Lead'
? __('Lead')
: __('Deal'),
])
}}
</div>
<div class="text-p-sm text-ink-gray-6 mt-1">
{{
__('Choose how {0} are assigned among the selected assignees.', [
documentType,
])
}}
</div>
</div>
<div>
<Popover placement="bottom-end">
<template #target="{ togglePopover }">
<div
class="flex items-center justify-between text-base rounded h-7 py-1.5 pl-2 pr-2 border border-outline-gray-2 bg-surface-gray-2 placeholder-ink-gray-4 hover:border-outline-gray-modals hover:bg-surface-gray-3 focus:bg-surface-white focus:border-outline-gray-4 focus:shadow-sm focus:ring-0 focus-visible:ring-2 focus-visible:ring-outline-gray-3 text-ink-gray-8 transition-colors w-full dark:[color-scheme:dark] select-none min-w-40"
@click="togglePopover()"
>
<div>
{{
documentRoutingOptions.find(
(option) => option.value == assignmentRuleData.rule,
)?.label
}}
</div>
<FeatherIcon name="chevron-down" class="size-4" />
</div>
</template>
<template #body="{ togglePopover }">
<div
class="p-1 text-ink-gray-7 mt-1 w-48 bg-white shadow-xl rounded"
>
<div
v-for="option in documentRoutingOptions"
:key="option.value"
class="p-2 cursor-pointer hover:bg-gray-50 text-sm flex items-center justify-between rounded"
@click="
() => {
assignmentRuleData.rule = option.value
togglePopover()
}
"
>
<span>
{{ option.label }}
</span>
<FeatherIcon
v-if="assignmentRuleData.rule == option.value"
name="check"
class="size-4"
/>
</div>
</div>
</template>
</Popover>
</div>
</div>
<div class="mt-7 flex items-center justify-between gap-2">
<div>
<div class="text-base font-medium text-ink-gray-8">
{{ __('Assignees') }}
</div>
<div class="text-p-sm text-ink-gray-6 mt-1">
{{ __('Select the assignees for {0}.', [documentType]) }}
</div>
</div>
<AssigneeSearch @addAssignee="validateAssignmentRule('users')" />
</div>
<div class="mt-4 flex flex-wrap gap-2">
<div
v-for="user in users"
:key="user.name"
class="flex items-center gap-2 text-sm bg-surface-gray-2 rounded-md p-1 w-max px-2 select-none"
>
<Avatar :image="user.user_image" :label="user.full_name" size="sm" />
<div class="text-ink-gray-7">
{{ user.full_name }}
</div>
<Tooltip
v-if="user.email == assignmentRuleData.lastUser"
:text="__('Last user assigned by this rule')"
:hover-delay="0.35"
:placement="'top'"
>
<div
class="text-xs rounded-full select-none bg-blue-600 text-white p-0.5 px-2"
>
{{ __('Last') }}
</div>
</Tooltip>
<Button variant="ghost" icon="x" @click="removeAssignedUser(user)" />
</div>
</div>
<ErrorMessage :message="assignmentRuleErrors.users" />
</div>
</template>
<script setup>
import { Avatar, Button, ErrorMessage, Popover, Tooltip } from 'frappe-ui'
import AssigneeSearch from './AssigneeSearch.vue'
import { computed, inject } from 'vue'
import { usersStore } from '@/stores/users'
const { getUser } = usersStore()
const assignmentRuleData = inject('assignmentRuleData')
const assignmentRuleErrors = inject('assignmentRuleErrors')
const validateAssignmentRule = inject('validateAssignmentRule')
const documentType = computed(() =>
assignmentRuleData.value.documentType == 'CRM Lead'
? __('leads')
: __('deals'),
)
const documentRoutingOptions = [
{
label: 'Auto-rotate',
value: 'Round Robin',
},
{
label: 'Assign by workload',
value: 'Load Balancing',
},
]
const removeAssignedUser = (user) => {
assignmentRuleData.value.users = assignmentRuleData.value.users.filter(
(u) => u.user !== user.name,
)
validateAssignmentRule('users')
}
const users = computed(() => {
const _users = []
assignmentRuleData.value.users.forEach((user) => {
_users.push(getUser(user.user))
})
return _users
})
</script>

View File

@ -0,0 +1,166 @@
<template>
<Combobox :multiple="true">
<Popover placement="bottom-end">
<template #target="{ togglePopover }">
<Button
variant="subtle"
icon-left="plus"
@click="togglePopover()"
:label="__('Add Assignee')"
/>
</template>
<template #body="{ togglePopover }">
<div class="mt-1 rounded-lg bg-white py-1 text-base shadow-2xl w-60">
<div class="relative px-1.5 pt-0.5">
<ComboboxInput
ref="search"
class="form-input w-full"
type="text"
@change="(e) => debouncedQuery(e.target.value)"
:value="query"
autocomplete="off"
:placeholder="__('Search')"
/>
<button
class="absolute right-1.5 inline-flex h-7 w-7 items-center justify-center"
@click="query = ''"
>
<FeatherIcon name="x" class="w-4" />
</button>
</div>
<ComboboxOptions class="my-2 max-h-64 overflow-y-auto px-1.5" static>
<ComboboxOption
v-show="usersList.length > 0"
v-for="user in usersList"
:key="user.username"
:value="user"
as="template"
v-slot="{ active }"
@click="
(e) => {
e.stopPropagation()
addAssignee(user)
}
"
>
<li
class="flex items-center rounded p-1.5 w-full text-base"
:class="{ 'bg-gray-100': active }"
>
<div class="flex gap-2 items-center w-full select-none">
<Avatar
:shape="'circle'"
:image="user.user_image"
:label="user.full_name"
size="lg"
/>
<div class="flex flex-col gap-1">
<div class="font-semibold text-ink-gray-7">
{{ user.full_name }}
</div>
<div class="text-ink-gray-6">{{ user.email }}</div>
</div>
</div>
</li>
</ComboboxOption>
<li
v-if="usersList.length == 0"
class="mt-1.5 rounded-md p-1.5 text-base text-gray-600"
>
{{ __('No results found') }}
</li>
</ComboboxOptions>
<div class="border-t p-1.5 pb-0.5 *:w-full">
<Button
variant="ghost"
icon-left="plus"
class="w-full"
:label="__('Invite agent')"
@click="
() => {
inviteAgent()
togglePopover()
}
"
/>
</div>
</div>
</template>
</Popover>
</Combobox>
</template>
<script setup>
import {
Combobox,
ComboboxInput,
ComboboxOption,
ComboboxOptions,
} from '@headlessui/vue'
import { useDebounceFn } from '@vueuse/core'
import { Avatar, Popover } from 'frappe-ui'
import { computed, inject, ref } from 'vue'
import { usersStore } from '@/stores/users'
import { globalStore } from '@/stores/global'
import { activeSettingsPage } from '@/composables/settings'
const emit = defineEmits(['addAssignee'])
const query = ref('')
const { users } = usersStore()
const { $dialog } = globalStore()
const assignmentRuleData = inject('assignmentRuleData')
const debouncedQuery = useDebounceFn((val) => {
query.value = val
}, 300)
const usersList = computed(() => {
let filteredUsers =
users.data?.crmUsers?.filter((user) => user.name !== 'Administrator') || []
return filteredUsers
.filter(
(user) =>
user.name?.includes(query.value) ||
user.full_name?.includes(query.value),
)
.filter((user) => {
return !assignmentRuleData.value.users.some((u) => u.user === user.email)
})
})
const addAssignee = (user) => {
const userExists = assignmentRuleData.value.users.some(
(u) => u.user === user.user,
)
if (!userExists) {
assignmentRuleData.value.users.push({
full_name: user.full_name,
email: user.email,
user_image: user.user_image,
user: user.email,
})
emit('addAssignee', user)
}
}
const inviteAgent = () => {
$dialog({
title: __('Invite agent'),
message: __(
'You will be redirected to invite user page, unsaved changes will be lost.',
),
variant: 'solid',
actions: [
{
label: __('Go to invite page'),
variant: 'solid',
onClick: (close) => {
activeSettingsPage.value = 'Invite User'
close()
},
},
],
})
}
</script>

View File

@ -0,0 +1,193 @@
<template>
<div
class="flex p-3 items-center justify-between cursor-pointer hover:bg-surface-menu-bar rounded"
>
<div class="w-7/12" @click="updateStep('view', data)">
<div class="text-base text-ink-gray-7 font-medium">{{ data.name }}</div>
<div
v-if="data.description && data.description.length > 0"
class="text-p-base w-full text-ink-gray-5 mt-0.5 whitespace-nowrap overflow-ellipsis overflow-hidden"
>
{{ data.description }}
</div>
</div>
<div class="w-3/12">
<Select
class="w-max -ml-2 bg-transparent border-0 text-ink-gray-6 focus-visible:!ring-0 bg-none"
:options="priorityOptions"
v-model="data.priority"
@update:modelValue="onPriorityChange"
/>
</div>
<div class="flex justify-between items-center w-2/12">
<Switch
size="sm"
:modelValue="!data.disabled"
@update:modelValue="onToggle"
/>
<Dropdown placement="right" :options="dropdownOptions">
<Button
icon="more-horizontal"
variant="ghost"
@click="isConfirmingDelete = false"
/>
</Dropdown>
</div>
</div>
<Dialog
:options="{ title: __('Duplicate Assignment Rule') }"
v-model="duplicateDialog.show"
>
<template #body-content>
<div class="flex flex-col gap-4">
<FormControl
:label="__('New Assignment Rule Name')"
type="text"
v-model="duplicateDialog.name"
/>
</div>
</template>
<template #actions>
<div class="flex gap-2 justify-end">
<Button
variant="subtle"
:label="__('Close')"
@click="duplicateDialog.show = false"
/>
<Button variant="solid" :label="__('Duplicate')" @click="duplicate()" />
</div>
</template>
</Dialog>
</template>
<script setup>
import {
Button,
createResource,
Dialog,
Dropdown,
FormControl,
Select,
Switch,
toast,
} from 'frappe-ui'
import { inject, ref } from 'vue'
const assignmentRulesList = inject('assignmentRulesList')
const updateStep = inject('updateStep')
const props = defineProps({
data: {
type: Object,
required: true,
},
})
const priorityOptions = [
{ label: 'Low', value: '0' },
{ label: 'Low-Medium', value: '1' },
{ label: 'Medium', value: '2' },
{ label: 'Medium-High', value: '3' },
{ label: 'High', value: '4' },
]
const duplicateDialog = ref({
show: false,
name: '',
})
const isConfirmingDelete = ref(false)
const deleteAssignmentRule = () => {
createResource({
url: 'frappe.client.delete',
params: {
doctype: 'Assignment Rule',
name: props.data.name,
},
onSuccess: () => {
assignmentRulesList.reload()
isConfirmingDelete.value = false
toast.success(__('Assignment rule deleted'))
},
auto: true,
})
}
const dropdownOptions = [
{
label: __('Duplicate'),
onClick: () => {
duplicateDialog.value = {
show: true,
name: props.data.name + ' (Copy)',
}
},
icon: 'copy',
},
{
label: __('Delete'),
icon: 'trash-2',
onClick: (e) => {
e.preventDefault()
e.stopImmediatePropagation()
isConfirmingDelete.value = true
},
condition: () => !isConfirmingDelete.value,
},
{
label: __('Confirm Delete'),
icon: 'trash-2',
theme: 'red',
onClick: () => deleteAssignmentRule(),
condition: () => isConfirmingDelete.value,
},
]
const duplicate = () => {
createResource({
url: 'crm.api.assignment_rule.duplicate_assignment_rule',
params: {
docname: props.data.name,
new_name: duplicateDialog.value.name,
},
onSuccess: (data) => {
assignmentRulesList.reload()
toast.success(__('Assignment rule duplicated'))
duplicateDialog.value.show = false
duplicateDialog.value.name = ''
updateStep('view', data)
},
auto: true,
})
}
const onPriorityChange = () => {
setAssignmentRuleValue('priority', props.data.priority)
}
const onToggle = () => {
if (!props.data.users_exists && props.data.disabled) {
toast.error(__('Cannot enable rule without adding users in it'))
return
}
setAssignmentRuleValue('disabled', !props.data.disabled, 'status')
}
const setAssignmentRuleValue = (key, value, fieldName = undefined) => {
createResource({
url: 'frappe.client.set_value',
params: {
doctype: 'Assignment Rule',
name: props.data.name,
fieldname: key,
value: value,
},
onSuccess: () => {
assignmentRulesList.reload()
toast.success(__('Assignment rule {0} updated', [fieldName || key]))
},
auto: true,
})
}
</script>

View File

@ -0,0 +1,19 @@
<template>
<AssignmentRules v-if="step.screen === 'list'" />
<AssignmentRuleView v-else-if="step.screen === 'view'" />
</template>
<script setup>
import { ref, provide } from 'vue'
import AssignmentRules from './AssignmentRules.vue'
import AssignmentRuleView from './AssignmentRuleView.vue'
const step = ref({ screen: 'list', data: null })
provide('step', step)
provide('updateStep', updateStep)
function updateStep(newStep, data) {
step.value = { screen: newStep, data }
}
</script>

View File

@ -0,0 +1,782 @@
<template>
<div
v-if="!getAssignmentRuleData.loading"
class="flex flex-col h-full gap-6 px-6 py-8 text-ink-gray-8"
>
<div class="flex items-center justify-between px-2 w-full">
<div class="flex items-center gap-2">
<Button
variant="ghost"
icon-left="chevron-left"
:label="
assignmentRuleData.assignmentRuleName || __('New Assignment Rule')
"
size="md"
@click="goBack()"
class="cursor-pointer -ml-4 hover:bg-transparent focus:bg-transparent focus:outline-none focus:ring-0 focus:ring-offset-0 focus-visible:none active:bg-transparent active:outline-none active:ring-0 active:ring-offset-0 active:text-ink-gray-5 font-semibold text-xl hover:opacity-70 !pr-0 !max-w-96 !justify-start"
/>
<Badge
:variant="'subtle'"
:theme="'orange'"
size="sm"
:label="__('Unsaved')"
v-if="isDirty"
/>
</div>
<div class="flex items-center gap-4">
<div
class="flex items-center justify-between gap-2"
@click="assignmentRuleData.disabled = !assignmentRuleData.disabled"
>
<Switch size="sm" :model-value="!assignmentRuleData.disabled" />
<span class="text-sm text-ink-gray-7">{{ __('Enabled') }}</span>
</div>
<Button
:disabled="Boolean(!isDirty && step.data)"
:label="__('Save')"
theme="gray"
variant="solid"
@click="saveAssignmentRule()"
:loading="isLoading || getAssignmentRuleData.loading"
/>
</div>
</div>
<div class="overflow-y-auto px-2">
<div class="grid grid-cols-2 gap-5">
<div>
<FormControl
:type="'text'"
size="sm"
variant="subtle"
:placeholder="__('Name')"
:label="__('Name')"
v-model="assignmentRuleData.assignmentRuleName"
required
maxlength="50"
@change="validateAssignmentRule('assignmentRuleName')"
/>
<ErrorMessage
:message="assignmentRuleErrors.assignmentRuleName"
class="mt-2"
/>
</div>
<div class="flex flex-col gap-1.5">
<FormLabel :label="__('Priority')" />
<Popover>
<template #target="{ togglePopover }">
<div
class="flex items-center justify-between text-base rounded h-7 py-1.5 pl-2 pr-2 border border-outline-gray-2 bg-surface-gray-2 placeholder-ink-gray-4 hover:border-outline-gray-modals hover:bg-surface-gray-3 focus:bg-surface-white focus:border-outline-gray-4 focus:shadow-sm focus:ring-0 focus-visible:ring-2 focus-visible:ring-outline-gray-3 text-ink-gray-8 transition-colors w-full dark:[color-scheme:dark] cursor-default"
@click="togglePopover()"
>
<div>
{{
priorityOptions.find(
(option) => option.value == assignmentRuleData.priority,
)?.label
}}
</div>
<FeatherIcon name="chevron-down" class="size-4" />
</div>
</template>
<template #body="{ togglePopover }">
<div
class="p-1 text-ink-gray-6 top-1 absolute w-full bg-white shadow-2xl rounded"
>
<div
v-for="option in priorityOptions"
:key="option.value"
class="p-2 cursor-pointer hover:bg-gray-50 text-base flex items-center justify-between rounded"
@click="
() => {
assignmentRuleData.priority = option.value
togglePopover()
}
"
>
{{ option.label }}
<FeatherIcon
v-if="assignmentRuleData.priority == option.value"
name="check"
class="size-4"
/>
</div>
</div>
</template>
</Popover>
</div>
<div>
<FormControl
:type="'textarea'"
size="sm"
variant="subtle"
:placeholder="__('Description')"
:label="__('Description')"
required
maxlength="250"
@change="validateAssignmentRule('description')"
v-model="assignmentRuleData.description"
/>
<ErrorMessage
:message="assignmentRuleErrors.description"
class="mt-2"
/>
</div>
<div class="flex flex-col gap-1.5">
<FormLabel :label="__('Apply on')" />
<Select
:options="[
{
label: 'Lead',
value: 'CRM Lead',
},
{
label: 'Deal',
value: 'CRM Deal',
},
]"
v-model="assignmentRuleData.documentType"
/>
</div>
</div>
<hr class="my-8" />
<div>
<div class="flex flex-col gap-1">
<span class="text-lg font-semibold text-ink-gray-8">{{
__('Assignment condition')
}}</span>
<div class="flex items-center justify-between gap-6">
<span class="text-p-sm text-ink-gray-6">
{{
__('Choose which {0} are affected by this assignment rule.', [
documentType,
])
}}
<a
class="font-medium underline"
href="https://docs.frappe.io/crm/assignment-rule"
target="_blank"
>{{ __('Learn about conditions') }}</a
>
</span>
<div v-if="isOldSla && step.data">
<Popover trigger="hover" :hoverDelay="0.25" placement="top-end">
<template #target>
<div
class="text-sm text-ink-gray-6 flex gap-1 cursor-default text-nowrap items-center"
>
<span>{{ __('Old Condition') }}</span>
<FeatherIcon name="info" class="size-4" />
</div>
</template>
<template #body-main>
<div
class="text-sm text-ink-gray-6 p-2 bg-white rounded-md max-w-96 text-wrap whitespace-pre-wrap leading-5"
>
<code>{{ assignmentRuleData.assignCondition }}</code>
</div>
</template>
</Popover>
</div>
</div>
</div>
<div class="mt-5">
<div
class="flex flex-col gap-3 items-center text-center text-ink-gray-7 text-sm mb-2 border border-outline-gray-2 rounded-md p-3 py-4"
v-if="!useNewUI && assignmentRuleData.assignCondition"
>
<span class="text-p-sm">
{{ __('Conditions for this rule were created from') }}
<a :href="deskUrl" target="_blank" class="underline">{{
__('desk')
}}</a>
{{
__(
'which are not compatible with this UI, you will need to recreate the conditions here if you want to manage and add new conditions from this UI.',
)
}}
</span>
<Button
:label="__('I understand, add conditions')"
variant="subtle"
theme="gray"
@click="useNewUI = true"
/>
</div>
<AssignmentRulesSection
:conditions="assignmentRuleData.assignConditionJson"
name="assignCondition"
:errors="assignmentRuleErrors.assignConditionError"
:doctype="assignmentRuleData.documentType"
v-else
/>
<div class="flex justify-end">
<ErrorMessage
:message="assignmentRuleErrors.assignCondition"
class="mt-2"
/>
</div>
</div>
</div>
<hr class="my-8" />
<div>
<div class="flex flex-col gap-1">
<span class="text-lg font-semibold text-ink-gray-8">{{
__('Unassignment condition')
}}</span>
<div class="flex items-center justify-between gap-6">
<span class="text-p-sm text-ink-gray-6">
{{
__(
'Choose which {0} are affected by this un-assignment rule.',
[documentType],
)
}}
<a
class="font-medium underline"
href="https://docs.frappe.io/crm/assignment-rule"
target="_blank"
>{{ __('Learn about conditions') }}</a
>
</span>
<div
v-if="
isOldSla && step.data && assignmentRuleData.unassignCondition
"
>
<Popover trigger="hover" :hoverDelay="0.25" placement="top-end">
<template #target>
<div
class="text-sm text-ink-gray-6 flex gap-1 cursor-default text-nowrap items-center"
>
<span> {{ __('Old Condition') }} </span>
<FeatherIcon name="info" class="size-4" />
</div>
</template>
<template #body-main>
<div
class="text-sm text-ink-gray-6 p-2 bg-white rounded-md max-w-96 text-wrap whitespace-pre-wrap leading-5"
>
<code>{{ assignmentRuleData.unassignCondition }}</code>
</div>
</template>
</Popover>
</div>
</div>
</div>
<div class="mt-5">
<div
v-if="!useNewUI && assignmentRuleData.unassignCondition"
class="flex flex-col gap-3 items-center text-center text-ink-gray-7 text-sm mb-2 border border-outline-gray-2 rounded-md p-3 py-4"
>
<span class="text-p-sm">
{{ __('Conditions for this rule were created from') }}
<a :href="deskUrl" target="_blank" class="underline">
{{ __('desk') }}
</a>
{{
__(
'which are not compatible with this UI, you will need to recreate the conditions here if you want to manage and add new conditions from this UI.',
)
}}
</span>
<Button
:label="__('I understand, add conditions')"
variant="subtle"
theme="gray"
@click="useNewUI = true"
/>
</div>
<AssignmentRulesSection
v-else
:conditions="assignmentRuleData.unassignConditionJson"
name="unassignCondition"
:errors="assignmentRuleErrors.unassignConditionError"
:doctype="assignmentRuleData.documentType"
/>
</div>
</div>
<hr class="my-8" />
<div>
<div class="flex flex-col gap-1">
<span class="text-lg font-semibold text-ink-gray-8">{{
__('Assignment Schedule')
}}</span>
<span class="text-p-sm text-ink-gray-6">
{{
__('Choose the days of the week when this rule should be active.')
}}
</span>
</div>
<div class="mt-6">
<AssignmentSchedule />
</div>
</div>
<hr class="my-8" />
<AssigneeRules />
</div>
</div>
<div v-else class="flex items-center h-full justify-center">
<LoadingIndicator class="w-4" />
</div>
<ConfirmDialog
v-model="showConfirmDialog.show"
:title="showConfirmDialog.title"
:message="showConfirmDialog.message"
:onConfirm="showConfirmDialog.onConfirm"
:onCancel="() => (showConfirmDialog.show = false)"
/>
</template>
<script setup>
import {
Badge,
Button,
call,
createResource,
ErrorMessage,
FormControl,
FormLabel,
LoadingIndicator,
Popover,
Select,
Switch,
toast,
} from 'frappe-ui'
import {
onMounted,
onUnmounted,
ref,
inject,
watch,
provide,
computed,
} from 'vue'
import AssignmentRulesSection from './AssignmentRulesSection.vue'
import AssignmentSchedule from './AssignmentSchedule.vue'
import AssigneeRules from './AssigneeRules.vue'
import ConfirmDialog from 'frappe-ui/src/components/ConfirmDialog.vue'
import { globalStore } from '@/stores/global'
import { disableSettingModalOutsideClick } from '@/composables/settings'
import { convertToConditions, validateConditions } from '@/utils'
const isDirty = ref(false)
const initialData = ref(null)
const isLoading = ref(false)
const updateStep = inject('updateStep')
const step = inject('step')
const { $dialog } = globalStore()
const showConfirmDialog = ref({
show: false,
title: '',
message: '',
onConfirm: () => {},
})
const useNewUI = ref(true)
const isOldSla = ref(false)
const documentType = computed(() =>
assignmentRuleData.value.documentType == 'CRM Lead'
? __('leads')
: __('deals'),
)
const deskUrl = `${window.location.origin}/app/assignment-rule/${step.value.data?.name}`
const defaultAssignmentDays = [
'Monday',
'Tuesday',
'Wednesday',
'Thursday',
'Friday',
'Saturday',
'Sunday',
]
const assignmentRuleData = ref({
assignCondition: '',
unassignCondition: '',
assignConditionJson: [],
unassignConditionJson: [],
rule: 'Round Robin',
priority: 1,
users: [],
disabled: false,
description: '',
name: '',
assignmentRuleName: '',
assignmentDays: defaultAssignmentDays,
documentType: 'CRM Lead',
})
const validateAssignmentRule = (key, skipConditionCheck = false) => {
const validateField = (field) => {
if (key && field !== key) return
switch (field) {
case 'assignmentRuleName':
if (assignmentRuleData.value.assignmentRuleName?.length == 0) {
assignmentRuleErrors.value.assignmentRuleName = __('Name is required')
} else {
assignmentRuleErrors.value.assignmentRuleName = ''
}
break
case 'description':
assignmentRuleErrors.value.description =
assignmentRuleData.value.description?.length > 0
? ''
: __('Description is required')
break
case 'assignCondition':
if (skipConditionCheck) {
break
}
assignmentRuleErrors.value.assignCondition =
assignmentRuleData.value.assignConditionJson?.length > 0
? ''
: __('Assign condition is required')
if (!validateConditions(assignmentRuleData.value.assignConditionJson)) {
assignmentRuleErrors.value.assignConditionError = __(
'Assign conditions are invalid',
)
} else {
assignmentRuleErrors.value.assignConditionError = ''
}
break
case 'unassignCondition':
if (skipConditionCheck) {
break
}
if (
assignmentRuleData.value.unassignConditionJson?.length > 0 &&
!validateConditions(assignmentRuleData.value.unassignConditionJson)
) {
assignmentRuleErrors.value.unassignConditionError = __(
'Unassign conditions are invalid',
)
} else {
assignmentRuleErrors.value.unassignConditionError = ''
}
break
case 'users':
assignmentRuleErrors.value.users =
assignmentRuleData.value.users?.length > 0
? ''
: __('Users are required')
break
case 'assignmentDays':
assignmentRuleErrors.value.assignmentDays =
assignmentRuleData.value.assignmentDays?.length > 0
? ''
: __('Assignment days are required')
break
default:
break
}
}
if (key) {
validateField(key)
} else {
Object.keys(assignmentRuleErrors.value).forEach(validateField)
}
return assignmentRuleErrors.value
}
const resetAssignmentRuleData = () => {
assignmentRuleData.value = {
assignCondition: '',
unassignCondition: '',
assignConditionJson: [],
unassignConditionJson: [],
rule: 'Round Robin',
priority: 1,
users: [],
disabled: false,
description: '',
name: '',
assignmentRuleName: '',
assignmentDays: defaultAssignmentDays,
documentType: 'CRM Lead',
}
}
const assignmentRuleErrors = ref({
assignmentRuleName: '',
assignCondition: '',
assignConditionError: '',
unassignConditionError: '',
users: '',
description: '',
assignmentDays: '',
})
const resetAssignmentRuleErrors = () => {
Object.keys(assignmentRuleErrors.value).forEach((key) => {
assignmentRuleErrors.value[key] = ''
})
}
provide('assignmentRuleData', assignmentRuleData)
provide('assignmentRuleErrors', assignmentRuleErrors)
provide('validateAssignmentRule', validateAssignmentRule)
provide('resetAssignmentRuleData', resetAssignmentRuleData)
provide('resetAssignmentRuleErrors', resetAssignmentRuleErrors)
const getAssignmentRuleData = createResource({
url: 'frappe.client.get',
params: {
doctype: 'Assignment Rule',
name: step.value.data?.name,
},
auto: Boolean(step.value.data),
onSuccess(data) {
assignmentRuleData.value = {
assignCondition: data.assign_condition,
unassignCondition: data.unassign_condition,
assignConditionJson: JSON.parse(data.assign_condition_json || '[]'),
unassignConditionJson: JSON.parse(data.unassign_condition_json || '[]'),
rule: data.rule,
priority: data.priority,
users: data.users,
disabled: data.disabled,
description: data.description,
name: data.name,
assignmentRuleName: data.name,
assignmentDays: data.assignment_days.map((day) => day.day),
documentType: data.document_type,
}
initialData.value = JSON.stringify(assignmentRuleData.value)
const conditionsAvailable =
assignmentRuleData.value.assignCondition?.length > 0
const conditionsJsonAvailable =
assignmentRuleData.value.assignConditionJson?.length > 0
if (conditionsAvailable && !conditionsJsonAvailable) {
useNewUI.value = false
isOldSla.value = true
} else {
useNewUI.value = true
isOldSla.value = false
}
},
})
if (!step.value.data) {
initialData.value = JSON.stringify(assignmentRuleData.value)
}
const goBack = () => {
if (isDirty.value && !showConfirmDialog.value.show) {
$dialog({
title: __('Unsaved changes'),
message: __(
'Are you sure you want to go back? Unsaved changes will be lost.',
),
variant: 'solid',
actions: [
{
label: __('Go back'),
variant: 'solid',
onClick: (close) => {
updateStep('list', null)
close()
},
},
],
})
return
}
updateStep('list', null)
showConfirmDialog.value.show = false
}
const saveAssignmentRule = () => {
const validationErrors = validateAssignmentRule(undefined, !useNewUI.value)
if (Object.values(validationErrors).some((error) => error)) {
toast.error(
__('Invalid fields, check if all are filled in and values are correct.'),
)
return
}
if (step.value.data) {
if (isOldSla.value && useNewUI.value) {
showConfirmDialog.value = {
show: true,
title: __('Confirm overwrite'),
message: __(
'Your old condition will be overwritten. Are you sure you want to save?',
),
onConfirm: () => {
updateAssignmentRule()
showConfirmDialog.value.show = false
},
}
return
}
updateAssignmentRule()
} else {
createAssignmentRule()
}
}
const createAssignmentRule = () => {
isLoading.value = true
createResource({
url: 'frappe.client.insert',
params: {
doc: {
doctype: 'Assignment Rule',
document_type: assignmentRuleData.value.documentType,
rule: assignmentRuleData.value.rule,
priority: assignmentRuleData.value.priority,
users: assignmentRuleData.value.users,
disabled: assignmentRuleData.value.disabled,
description: assignmentRuleData.value.description,
assignment_days: assignmentRuleData.value.assignmentDays.map((day) => ({
day: day,
})),
name: assignmentRuleData.value.assignmentRuleName,
assignment_rule_name: assignmentRuleData.value.assignmentRuleName,
assign_condition: convertToConditions({
conditions: assignmentRuleData.value.assignConditionJson,
}),
unassign_condition: convertToConditions({
conditions: assignmentRuleData.value.unassignConditionJson,
}),
assign_condition_json: JSON.stringify(
assignmentRuleData.value.assignConditionJson,
),
unassign_condition_json: JSON.stringify(
assignmentRuleData.value.unassignConditionJson,
),
},
},
auto: true,
onSuccess(data) {
getAssignmentRuleData
.submit({
doctype: 'Assignment Rule',
name: data.name,
})
.then(() => {
isLoading.value = false
toast.success(__('Assignment rule created'))
})
updateStep('view', data)
},
onError: () => {
isLoading.value = false
},
})
}
const priorityOptions = [
{ label: 'Low', value: '0' },
{ label: 'Low-Medium', value: '1' },
{ label: 'Medium', value: '2' },
{ label: 'Medium-High', value: '3' },
{ label: 'High', value: '4' },
]
const updateAssignmentRule = async () => {
isLoading.value = true
await call('frappe.client.set_value', {
doctype: 'Assignment Rule',
name: assignmentRuleData.value.name,
fieldname: {
rule: assignmentRuleData.value.rule,
priority: assignmentRuleData.value.priority,
users: assignmentRuleData.value.users,
disabled: assignmentRuleData.value.disabled,
description: assignmentRuleData.value.description,
document_type: assignmentRuleData.value.documentType,
assignment_days: assignmentRuleData.value.assignmentDays.map((day) => ({
day: day,
})),
assign_condition: useNewUI.value
? convertToConditions({
conditions: assignmentRuleData.value.assignConditionJson,
})
: assignmentRuleData.value.assignCondition,
unassign_condition: useNewUI.value
? convertToConditions({
conditions: assignmentRuleData.value.unassignConditionJson,
})
: assignmentRuleData.value.unassignCondition,
assign_condition_json: useNewUI.value
? JSON.stringify(assignmentRuleData.value.assignConditionJson)
: null,
unassign_condition_json: useNewUI.value
? JSON.stringify(assignmentRuleData.value.unassignConditionJson)
: null,
},
}).catch((er) => {
const error =
er?.messages?.[0] ||
__('Some error occurred while updating assignment rule')
toast.error(error)
isLoading.value = false
})
if (
assignmentRuleData.value.name !==
assignmentRuleData.value.assignmentRuleName
) {
await call('frappe.client.rename_doc', {
doctype: 'Assignment Rule',
old_name: assignmentRuleData.value.name,
new_name: assignmentRuleData.value.assignmentRuleName,
}).catch(async (er) => {
const error =
er?.messages?.[0] ||
__('Some error occurred while renaming assignment rule')
toast.error(error)
// Reset assignment rule to previous state
await getAssignmentRuleData.reload()
isLoading.value = false
})
await getAssignmentRuleData.submit({
doctype: 'Assignment Rule',
name: assignmentRuleData.value.assignmentRuleName,
})
} else {
getAssignmentRuleData.reload()
}
isLoading.value = false
toast.success(__('Assignment rule updated'))
}
watch(
assignmentRuleData,
(newVal) => {
if (!initialData.value) return
isDirty.value = JSON.stringify(newVal) != initialData.value
if (isDirty.value) {
disableSettingModalOutsideClick.value = true
} else {
disableSettingModalOutsideClick.value = false
}
},
{ deep: true },
)
const beforeUnloadHandler = (event) => {
if (!isDirty.value) return
event.preventDefault()
event.returnValue = true
}
onMounted(() => {
addEventListener('beforeunload', beforeUnloadHandler)
})
onUnmounted(() => {
resetAssignmentRuleErrors()
resetAssignmentRuleData()
removeEventListener('beforeunload', beforeUnloadHandler)
disableSettingModalOutsideClick.value = false
})
</script>

View File

@ -0,0 +1,52 @@
<template>
<div class="flex h-full flex-col gap-6 p-6 text-ink-gray-8">
<!-- Header -->
<div class="flex justify-between px-2 pt-2">
<div class="flex flex-col gap-1 w-9/12">
<h2 class="flex gap-2 text-xl font-semibold leading-none h-5">
{{ __('Assignment rules') }}
</h2>
<p class="text-p-base text-ink-gray-6">
{{
__(
'Assignment rules automatically assign lead/deal to the right sales user based on predefined conditions',
)
}}
</p>
</div>
<div class="flex item-center space-x-2 w-3/12 justify-end">
<Button
:label="__('New')"
icon-left="plus"
variant="solid"
@click="goToNew()"
/>
</div>
</div>
<!-- Assignment rules list -->
<div class="overflow-y-auto">
<AssignmentRulesList />
</div>
</div>
</template>
<script setup>
import AssignmentRulesList from './AssignmentRulesList.vue'
import { createResource } from 'frappe-ui'
import { inject, provide } from 'vue'
const updateStep = inject('updateStep')
const assignmentRulesListData = createResource({
url: 'crm.api.assignment_rule.get_assignment_rules_list',
cache: ['assignmentRules', 'get_assignment_rules_list'],
auto: true,
})
provide('assignmentRulesList', assignmentRulesListData)
const goToNew = () => {
updateStep('view', null)
}
</script>

View File

@ -0,0 +1,43 @@
<template>
<div
v-if="assignmentRulesList.loading && !assignmentRulesList.data"
class="flex items-center justify-center mt-12"
>
<LoadingIndicator class="w-4" />
</div>
<div v-else>
<div
v-if="assignmentRulesList.data?.length === 0"
class="flex items-center justify-center rounded-md border border-outline-gray-2 p-4"
>
<div class="text-sm text-ink-gray-7">
{{ __('No items in the list') }}
</div>
</div>
<div v-else>
<div class="flex items-center py-2 px-4 text-sm text-ink-gray-5">
<div class="w-7/12">{{ __('Assignment rule') }}</div>
<div class="w-3/12">{{ __('Priority') }}</div>
<div class="w-2/12">{{ __('Enabled') }}</div>
</div>
<div class="h-px border-t mx-4 border-outline-gray-modals" />
<div class="overflow-y-auto px-2">
<template
v-for="(assignmentRule, i) in assignmentRulesList.data"
:key="assignmentRule.name"
>
<AssignmentRuleListItem :data="assignmentRule" />
<hr v-if="assignmentRulesList.data.length !== i + 1" class="mx-2" />
</template>
</div>
</div>
</div>
</template>
<script setup>
import { LoadingIndicator } from 'frappe-ui'
import { inject } from 'vue'
import AssignmentRuleListItem from './AssignmentRuleListItem.vue'
const assignmentRulesList = inject('assignmentRulesList')
</script>

View File

@ -0,0 +1,96 @@
<template>
<CFConditions
v-if="props.conditions.length > 0"
:conditions="props.conditions"
:level="0"
:disableAddCondition="props.errors !== ''"
:doctype="props.doctype"
/>
<div
v-if="props.conditions.length == 0"
class="flex p-4 items-center cursor-pointer justify-center gap-2 text-sm border border-outline-gray-2 text-gray-600 rounded-md"
@click="
() => {
props.conditions.push(['', '', ''])
validateAssignmentRule(props.name)
}
"
>
<FeatherIcon name="plus" class="h-4" />
{{ __('Add a condition') }}
</div>
<div class="flex items-center justify-between mt-2">
<div class="" v-if="props.conditions.length > 0">
<Dropdown v-slot="{ open }" :options="dropdownOptions">
<Button
:disabled="props.errors !== ''"
:icon-right="open ? 'chevron-up' : 'chevron-down'"
:label="__('Add condition')"
/>
</Dropdown>
</div>
<ErrorMessage v-if="props.conditions.length > 0" :message="props.errors" />
</div>
</template>
<script setup>
import { Button, Dropdown, ErrorMessage, FeatherIcon } from 'frappe-ui'
import { watchDebounced } from '@vueuse/core'
import { validateConditions } from '@/utils'
import CFConditions from '../../ConditionsFilter/CFConditions.vue'
import { inject } from 'vue'
const props = defineProps({
conditions: Array,
name: String,
errors: String,
doctype: String,
})
const validateAssignmentRule = inject('validateAssignmentRule')
const getConjunction = () => {
let conjunction = 'and'
props.conditions.forEach((condition) => {
if (typeof condition == 'string') {
conjunction = condition
}
})
return conjunction
}
const dropdownOptions = [
{
label: __('Add condition'),
onClick: () => {
addCondition()
},
},
{
label: __('Add condition group'),
onClick: () => {
const conjunction = getConjunction()
props.conditions.push(conjunction, [[]])
},
},
]
const addCondition = () => {
const isValid = validateConditions(props.conditions)
if (!isValid) {
return
}
const conjunction = getConjunction()
props.conditions.push(conjunction, ['', '', ''])
}
watchDebounced(
() => [...props.conditions],
() => {
validateAssignmentRule(props.name)
},
{ deep: true, debounce: 300 },
)
</script>

View File

@ -0,0 +1,84 @@
<template>
<div class="rounded-md border px-2 border-outline-gray-2 text-sm">
<div
class="grid p-2 px-4 items-center"
style="grid-template-columns: 3fr 1fr"
>
<div
v-for="column in columns"
:key="column.key"
class="text-gray-600 overflow-hidden whitespace-nowrap text-ellipsis"
>
{{ __(column.label) }}
</div>
</div>
<hr />
<AssignmentScheduleItem
v-for="(day, index) in days"
:key="day.day"
:data="day"
:isLast="index === days.length - 1"
/>
</div>
<ErrorMessage :message="assignmentRuleErrors.assignmentDays" class="mt-2" />
</template>
<script setup>
import AssignmentScheduleItem from './AssignmentScheduleItem.vue'
import { ErrorMessage } from 'frappe-ui'
import { onMounted, ref, inject } from 'vue'
const assignmentRuleData = inject('assignmentRuleData')
const assignmentRuleErrors = inject('assignmentRuleErrors')
const columns = [
{
label: 'Days',
key: 'day',
},
{
label: 'Active',
key: 'active',
},
]
const days = ref([
{
day: 'Monday',
active: false,
},
{
day: 'Tuesday',
active: false,
},
{
day: 'Wednesday',
active: false,
},
{
day: 'Thursday',
active: false,
},
{
day: 'Friday',
active: false,
},
{
day: 'Saturday',
active: false,
},
{
day: 'Sunday',
active: false,
},
])
onMounted(() => {
assignmentRuleData.value.assignmentDays.forEach((day) => {
const workDay = days.value.find((d) => d.day === day)
if (workDay) {
workDay.active = true
}
})
})
</script>

View File

@ -0,0 +1,42 @@
<template>
<div
class="grid py-3.5 px-4 items-center"
style="grid-template-columns: 3fr 1fr"
>
<div class="text-ink-gray-7 font-medium">{{ __(data.day) }}</div>
<div class="flex justify-start">
<Switch v-model="data.active" @update:model-value="toggleDay" />
</div>
</div>
<hr v-if="!isLast" />
</template>
<script setup>
import { Switch } from 'frappe-ui'
import { inject } from 'vue'
const assignmentRuleData = inject('assignmentRuleData')
const props = defineProps({
data: {
type: Object,
required: true,
},
isLast: {
type: Boolean,
default: false,
},
})
const toggleDay = (isActive) => {
const dayIndex = assignmentRuleData.value.assignmentDays.findIndex(
(d) => d === props.data.day,
)
if (isActive && dayIndex === -1) {
assignmentRuleData.value.assignmentDays.push(props.data.day)
} else {
assignmentRuleData.value.assignmentDays.splice(dayIndex, 1)
}
}
</script>

View File

@ -1,27 +1,18 @@
<template>
<div class="flex h-full flex-col gap-6 px-6 py-8 text-ink-gray-8">
<!-- Header -->
<div class="flex px-2 justify-between">
<div class="flex items-center gap-1 -ml-4 w-9/12">
<Button
variant="ghost"
icon-left="chevron-left"
:label="__('Brand settings')"
size="md"
@click="() => emit('updateStep', 'general-settings')"
class="text-xl !h-7 font-semibold hover:bg-transparent focus:bg-transparent focus:outline-none focus:ring-0 focus:ring-offset-0 focus-visible:none active:bg-transparent active:outline-none active:ring-0 active:ring-offset-0 active:text-ink-gray-5"
/>
<Badge
v-if="settings.isDirty"
:label="__('Not Saved')"
variant="subtle"
theme="orange"
/>
<div class="flex justify-between px-2 text-ink-gray-8">
<div class="flex flex-col gap-1">
<h2 class="flex gap-2 text-xl font-semibold leading-none h-5">
{{ __('Brand settings') }}
</h2>
<p class="text-p-base text-ink-gray-6">
{{ __('Configure your brand name, logo, and favicon') }}
</p>
</div>
<div class="flex item-center space-x-2 w-3/12 justify-end">
<Button
:label="__('Update')"
icon-left="plus"
variant="solid"
:disabled="!settings.isDirty"
:loading="settings.loading"
@ -36,35 +27,30 @@
<FormControl
type="text"
class="w-1/2"
size="md"
v-model="settings.doc.brand_name"
:label="__('Brand name')"
:placeholder="__('Enter brand name')"
/>
</div>
<!-- logo -->
<div class="flex flex-col justify-between gap-4">
<span class="text-base font-semibold text-ink-gray-8">
{{ __('Logo') }}
</span>
<div class="flex flex-1 gap-5">
<div class="flex items-center flex-1 gap-5">
<div
class="flex items-center justify-center rounded border border-outline-gray-modals px-10 py-2"
class="flex items-center justify-center rounded border border-outline-gray-modals size-20"
>
<img
:src="settings.doc?.brand_logo || '/assets/crm/images/logo.png'"
v-if="settings.doc?.brand_logo"
:src="settings.doc?.brand_logo"
alt="Logo"
class="size-8 rounded"
/>
<ImageIcon v-else class="size-5 text-ink-gray-4" />
</div>
<div class="flex flex-1 flex-col gap-2">
<ImageUploader
label="Favicon"
image_type="image/ico"
:image_url="settings.doc?.brand_logo"
@upload="(url) => (settings.doc.brand_logo = url)"
@remove="() => (settings.doc.brand_logo = '')"
/>
<span class="text-p-sm text-ink-gray-6">
<div class="flex flex-1 flex-col gap-1">
<span class="text-base font-medium">{{ __('Brand logo') }}</span>
<span class="text-p-base text-ink-gray-6">
{{
__(
'Appears in the left sidebar. Recommended size is 32x32 px in PNG or SVG',
@ -72,33 +58,34 @@
}}
</span>
</div>
<div>
<ImageUploader
image_type="image/ico"
:image_url="settings.doc?.brand_logo"
@upload="(url) => (settings.doc.brand_logo = url)"
@remove="() => (settings.doc.brand_logo = '')"
/>
</div>
</div>
</div>
<!-- favicon -->
<div class="flex flex-col justify-between gap-4">
<span class="text-base font-semibold text-ink-gray-8">
{{ __('Favicon') }}
</span>
<div class="flex flex-1 gap-5">
<div class="flex items-center flex-1 gap-5">
<div
class="flex items-center justify-center rounded border border-outline-gray-modals px-10 py-2"
class="flex items-center justify-center rounded border border-outline-gray-modals size-20"
>
<img
:src="settings.doc?.favicon || '/assets/crm/images/logo.png'"
v-if="settings.doc?.favicon"
:src="settings.doc?.favicon"
alt="Favicon"
class="size-8 rounded"
/>
<ImageIcon v-else class="size-5 text-ink-gray-4" />
</div>
<div class="flex flex-1 flex-col gap-2">
<ImageUploader
label="Favicon"
image_type="image/ico"
:image_url="settings.doc?.favicon"
@upload="(url) => (settings.doc.favicon = url)"
@remove="() => (settings.doc.favicon = '')"
/>
<span class="text-p-sm text-ink-gray-6">
<div class="flex flex-1 flex-col gap-1">
<span class="text-base font-medium">{{ __('Favicon') }}</span>
<span class="text-p-base text-ink-gray-6">
{{
__(
'Appears next to the title in your browser tab. Recommended size is 32x32 px in PNG or ICO',
@ -106,20 +93,25 @@
}}
</span>
</div>
<div>
<ImageUploader
image_type="image/ico"
:image_url="settings.doc?.favicon"
@upload="(url) => (settings.doc.favicon = url)"
@remove="() => (settings.doc.favicon = '')"
/>
</div>
</div>
</div>
<div v-if="errorMessage">
<ErrorMessage :message="__(errorMessage)" />
</div>
</div>
</template>
<script setup>
import ImageIcon from '~icons/lucide/image'
import ImageUploader from '@/components/Controls/ImageUploader.vue'
import { FormControl, ErrorMessage } from 'frappe-ui'
import { FormControl } from 'frappe-ui'
import { getSettings } from '@/stores/settings'
import { showSettings } from '@/composables/settings'
import { ref } from 'vue'
const { _settings: settings, setupBrand } = getSettings()
@ -131,7 +123,4 @@ function updateSettings() {
},
})
}
const emit = defineEmits(['updateStep'])
const errorMessage = ref('')
</script>

View File

@ -1,27 +1,20 @@
<template>
<div class="flex h-full flex-col gap-6 px-6 py-8 text-ink-gray-8">
<!-- Header -->
<div class="flex px-2 justify-between">
<div class="flex items-center gap-1 -ml-4 w-9/12">
<Button
variant="ghost"
icon-left="chevron-left"
:label="__('Currency & Exchange rate provider')"
size="md"
@click="() => emit('updateStep', 'general-settings')"
class="text-xl !h-7 font-semibold hover:bg-transparent focus:bg-transparent focus:outline-none focus:ring-0 focus:ring-offset-0 focus-visible:none active:bg-transparent active:outline-none active:ring-0 active:ring-offset-0 active:text-ink-gray-5"
/>
<Badge
v-if="settings.isDirty"
:label="__('Not Saved')"
variant="subtle"
theme="orange"
/>
<div class="flex justify-between px-2 text-ink-gray-8">
<div class="flex flex-col gap-1">
<h2 class="flex gap-2 text-xl font-semibold leading-none h-5">
{{ __('Currency & Exchange rate provider') }}
</h2>
<p class="text-p-base text-ink-gray-6">
{{
__('Configure the currency and exchange rate provider for your CRM')
}}
</p>
</div>
<div class="flex item-center space-x-2 w-3/12 justify-end">
<Button
:label="__('Update')"
icon-left="plus"
variant="solid"
:disabled="!settings.isDirty"
:loading="settings.loading"
@ -32,7 +25,7 @@
<!-- Fields -->
<div class="flex flex-1 flex-col overflow-y-auto">
<div class="flex items-center justify-between gap-8 p-3">
<div class="flex items-center justify-between gap-8 py-3 px-2">
<div class="flex flex-col">
<div class="text-p-base font-medium text-ink-gray-7 truncate">
{{ __('Currency') }}
@ -61,7 +54,7 @@
</div>
</div>
<div class="h-px border-t mx-2 border-outline-gray-modals" />
<div class="flex items-center justify-between gap-8 p-3">
<div class="flex items-center justify-between gap-8 py-3 px-2">
<div class="flex flex-col">
<div class="text-p-base font-medium text-ink-gray-7 truncate">
{{ __('Exchange rate provider') }}
@ -131,17 +124,15 @@
</div>
</template>
<script setup>
import { ErrorMessage, toast } from 'frappe-ui'
import { ErrorMessage, FormControl, toast } from 'frappe-ui'
import { getSettings } from '@/stores/settings'
import { globalStore } from '@/stores/global'
import { showSettings } from '@/composables/settings'
import { ref } from 'vue'
import FormControl from 'frappe-ui/src/components/FormControl/FormControl.vue'
const { _settings: settings } = getSettings()
const { $dialog } = globalStore()
const emit = defineEmits(['updateStep'])
const errorMessage = ref('')
function updateSettings() {

View File

@ -9,10 +9,14 @@
:label="__(template.name)"
size="md"
@click="() => emit('updateStep', 'template-list')"
class="text-xl !h-7 font-semibold hover:bg-transparent focus:bg-transparent focus:outline-none focus:ring-0 focus:ring-offset-0 focus-visible:none active:bg-transparent active:outline-none active:ring-0 active:ring-offset-0 active:text-ink-gray-5"
class="cursor-pointer hover:bg-transparent focus:bg-transparent focus:outline-none focus:ring-0 focus:ring-offset-0 focus-visible:none active:bg-transparent active:outline-none active:ring-0 active:ring-offset-0 active:text-ink-gray-5 font-semibold text-xl hover:opacity-70 !pr-0 !max-w-96 !justify-start"
/>
</div>
<div class="flex item-center space-x-2 w-3/12 justify-end">
<div class="flex item-center space-x-4 w-3/12 justify-end">
<div class="flex items-center space-x-2">
<Switch size="sm" v-model="template.enabled" />
<span class="text-sm text-ink-gray-7">{{ __('Enabled') }}</span>
</div>
<Button
:label="__('Update')"
icon-left="plus"
@ -26,13 +30,6 @@
<!-- Fields -->
<div class="flex flex-1 flex-col gap-4 overflow-y-auto">
<div
class="flex justify-between items-center cursor-pointer border-b py-3"
@click="() => (template.enabled = !template.enabled)"
>
<div class="text-base text-ink-gray-7">{{ __('Enabled') }}</div>
<Switch v-model="template.enabled" @click.stop />
</div>
<div class="flex sm:flex-row flex-col gap-4">
<div class="flex-1">
<FormControl

View File

@ -148,7 +148,6 @@
</div>
</template>
<script setup>
import { TemplateOption } from '@/utils'
import {
TextInput,
FormControl,
@ -223,43 +222,28 @@ function getDropdownOptions(template) {
let options = [
{
label: __('Duplicate'),
component: (props) =>
TemplateOption({
option: __('Duplicate'),
icon: 'copy',
active: props.active,
onClick: () => emit('updateStep', 'new-template', { ...template }),
}),
},
{
label: __('Delete'),
component: (props) =>
TemplateOption({
option: __('Delete'),
icon: 'trash-2',
active: props.active,
onClick: (e) => {
e.preventDefault()
e.stopPropagation()
confirmDelete.value = true
},
}),
condition: () => !confirmDelete.value,
},
{
label: __('Confirm Delete'),
component: (props) =>
TemplateOption({
option: __('Confirm Delete'),
icon: 'trash-2',
active: props.active,
theme: 'danger',
theme: 'red',
onClick: () => deleteTemplate(template),
}),
condition: () => confirmDelete.value,
},
]
return options.filter((option) => option.condition?.() || true)
return options
}
</script>

View File

@ -11,10 +11,14 @@
"
size="md"
@click="() => emit('updateStep', 'template-list')"
class="text-xl !h-7 font-semibold hover:bg-transparent focus:bg-transparent focus:outline-none focus:ring-0 focus:ring-offset-0 focus-visible:none active:bg-transparent active:outline-none active:ring-0 active:ring-offset-0 active:text-ink-gray-5"
class="cursor-pointer hover:bg-transparent focus:bg-transparent focus:outline-none focus:ring-0 focus:ring-offset-0 focus-visible:none active:bg-transparent active:outline-none active:ring-0 active:ring-offset-0 active:text-ink-gray-5 font-semibold text-xl hover:opacity-70 !pr-0 !max-w-96 !justify-start"
/>
</div>
<div class="flex item-center space-x-2 w-3/12 justify-end">
<div class="flex item-center space-x-4 w-3/12 justify-end">
<div class="flex items-center space-x-2">
<Switch size="sm" v-model="template.enabled" />
<span class="text-sm text-ink-gray-7">{{ __('Enabled') }}</span>
</div>
<Button
:label="templateData?.name ? __('Duplicate') : __('Create')"
icon-left="plus"
@ -26,13 +30,6 @@
<!-- Fields -->
<div class="flex flex-1 flex-col gap-4 overflow-y-auto">
<div
class="flex justify-between items-center cursor-pointer border-b py-3"
@click="() => (template.enabled = !template.enabled)"
>
<div class="text-base text-ink-gray-7">{{ __('Enabled') }}</div>
<Switch v-model="template.enabled" @click.stop />
</div>
<div class="flex sm:flex-row flex-col gap-4">
<div class="flex-1">
<FormControl

View File

@ -0,0 +1,93 @@
<template>
<div class="flex h-full flex-col gap-6 py-8 px-6 text-ink-gray-8">
<div class="flex flex-col gap-1 px-2">
<h2 class="flex gap-2 text-xl font-semibold leading-none h-5">
{{ __('Forecasting') }}
</h2>
<p class="text-p-base text-ink-gray-6">
{{
__(
'Configure forecasting feature to help predict sales performance and growth',
)
}}
</p>
</div>
<div class="flex-1 flex flex-col overflow-y-auto">
<div class="flex items-center justify-between py-3 px-2">
<div class="flex flex-col">
<div class="text-p-base font-medium text-ink-gray-7 truncate">
{{ __('Enable forecasting') }}
</div>
<div class="text-p-sm text-ink-gray-5 truncate">
{{
__(
'Makes "Expected Closure Date" and "Expected Deal Value" mandatory for deal value forecasting',
)
}}
</div>
</div>
<div>
<Switch
size="sm"
v-model="settings.doc.enable_forecasting"
@click.stop="toggleForecasting"
/>
</div>
</div>
<div class="h-px border-t mx-2 border-outline-gray-modals" />
<div class="flex items-center justify-between py-3 px-2">
<div class="flex flex-col">
<div class="text-p-base font-medium text-ink-gray-7 truncate">
{{ __('Auto update expected deal value') }}
</div>
<div class="text-p-sm text-ink-gray-5 truncate">
{{
__(
'Automatically update "Expected Deal Value" based on the total value of associated products in a deal',
)
}}
</div>
</div>
<div>
<Switch
size="sm"
v-model="settings.doc.auto_update_expected_deal_value"
@click.stop="autoUpdateExpectedDealValue"
/>
</div>
</div>
</div>
</div>
</template>
<script setup>
import { getSettings } from '@/stores/settings'
import { Switch, toast } from 'frappe-ui'
const { _settings: settings } = getSettings()
function toggleForecasting() {
settings.save.submit(null, {
onSuccess: () => {
toast.success(
settings.doc.enable_forecasting
? __('Forecasting enabled successfully')
: __('Forecasting disabled successfully'),
)
},
})
}
function autoUpdateExpectedDealValue() {
settings.save.submit(null, {
onSuccess: () => {
toast.success(
settings.doc.auto_update_expected_deal_value
? __('Auto update of expected deal value enabled')
: __('Auto update of expected deal value disabled'),
)
},
})
}
</script>

View File

@ -1,105 +0,0 @@
<template>
<div class="flex h-full flex-col gap-6 p-8 text-ink-gray-8">
<div class="flex flex-col gap-1">
<h2 class="flex gap-2 text-xl font-semibold leading-none h-5">
{{ __('General') }}
</h2>
<p class="text-p-base text-ink-gray-6">
{{ __('Configure general settings for your CRM') }}
</p>
</div>
<div class="flex-1 flex flex-col overflow-y-auto">
<div
class="flex items-center justify-between p-3 cursor-pointer hover:bg-surface-menu-bar rounded"
@click="toggleForecasting()"
>
<div class="flex flex-col">
<div class="text-p-base font-medium text-ink-gray-7 truncate">
{{ __('Enable forecasting') }}
</div>
<div class="text-p-sm text-ink-gray-5 truncate">
{{
__(
'Makes "Expected Closure Date" and "Expected Deal Value" mandatory for deal value forecasting',
)
}}
</div>
</div>
<div>
<Switch
size="sm"
v-model="settings.doc.enable_forecasting"
@click.stop="toggleForecasting(settings.doc.enable_forecasting)"
/>
</div>
</div>
<div class="h-px border-t mx-2 border-outline-gray-modals" />
<template v-for="(setting, i) in settingsList" :key="setting.name">
<li
class="flex items-center justify-between p-3 cursor-pointer hover:bg-surface-menu-bar rounded"
@click="() => emit('updateStep', setting.name)"
>
<div class="flex flex-col">
<div class="text-p-base font-medium text-ink-gray-7 truncate">
{{ __(setting.label) }}
</div>
<div class="text-p-sm text-ink-gray-5 truncate">
{{ __(setting.description) }}
</div>
</div>
<div>
<FeatherIcon name="chevron-right" class="text-ink-gray-7 size-4" />
</div>
</li>
<div
v-if="settingsList.length !== i + 1"
class="h-px border-t mx-2 border-outline-gray-modals"
/>
</template>
</div>
</div>
</template>
<script setup>
import { getSettings } from '@/stores/settings'
import { Switch, toast } from 'frappe-ui'
const emit = defineEmits(['updateStep'])
const { _settings: settings } = getSettings()
const settingsList = [
{
name: 'currency-settings',
label: 'Currency & Exchange rate provider',
description:
'Configure the currency and exchange rate provider for your CRM',
},
{
name: 'brand-settings',
label: 'Brand settings',
description: 'Configure your brand name, logo and favicon',
},
{
name: 'home-actions',
label: 'Home actions',
description: 'Configure actions that appear on the home dropdown',
},
]
function toggleForecasting(value) {
settings.doc.enable_forecasting =
value !== undefined ? value : !settings.doc.enable_forecasting
settings.save.submit(null, {
onSuccess: () => {
toast.success(
settings.doc.enable_forecasting
? __('Forecasting enabled successfully')
: __('Forecasting disabled successfully'),
)
},
})
}
</script>

View File

@ -1,34 +0,0 @@
<template>
<component :is="getComponent(step)" :data="data" @updateStep="updateStep" />
</template>
<script setup>
import GeneralSettings from './GeneralSettings.vue'
import CurrencySettings from './CurrencySettings.vue'
import BrandSettings from './BrandSettings.vue'
import HomeActions from './HomeActions.vue'
import { ref } from 'vue'
const step = ref('general-settings')
const data = ref(null)
function updateStep(newStep, _data) {
step.value = newStep
data.value = _data
}
function getComponent(step) {
switch (step) {
case 'general-settings':
return GeneralSettings
case 'currency-settings':
return CurrencySettings
case 'brand-settings':
return BrandSettings
case 'home-actions':
return HomeActions
default:
return null
}
}
</script>

View File

@ -1,21 +1,18 @@
<template>
<div class="flex h-full flex-col gap-6 p-8 text-ink-gray-8">
<!-- Header -->
<div class="flex justify-between">
<div class="flex gap-1 -ml-4 w-9/12">
<Button
variant="ghost"
icon-left="chevron-left"
:label="__('Home actions')"
size="md"
@click="() => emit('updateStep', 'general-settings')"
class="text-xl !h-7 font-semibold hover:bg-transparent focus:bg-transparent focus:outline-none focus:ring-0 focus:ring-offset-0 focus-visible:none active:bg-transparent active:outline-none active:ring-0 active:ring-offset-0 active:text-ink-gray-5"
/>
<div class="flex justify-between text-ink-gray-8">
<div class="flex flex-col gap-1">
<h2 class="flex gap-2 text-xl font-semibold leading-none h-5">
{{ __('Home actions') }}
</h2>
<p class="text-p-base text-ink-gray-6">
{{ __('Configure actions that appear on the home dropdown') }}
</p>
</div>
<div class="flex item-center space-x-2 w-3/12 justify-end">
<Button
:label="__('Update')"
icon-left="plus"
variant="solid"
:disabled="!document.isDirty"
:loading="document.loading"
@ -25,7 +22,7 @@
</div>
<!-- Fields -->
<div class="flex flex-1 flex-col gap-4 overflow-y-auto">
<div class="flex flex-1 flex-col overflow-y-auto">
<Grid
v-model="document.doc.dropdown_items"
doctype="CRM Dropdown Item"

View File

@ -1,6 +1,6 @@
<template>
<div class="flex h-full flex-col gap-6 p-8 text-ink-gray-8">
<div class="flex justify-between">
<div class="flex h-full flex-col gap-6 py-8 px-6 text-ink-gray-8">
<div class="flex px-2 justify-between">
<div class="flex flex-col gap-1 w-9/12">
<h2 class="flex gap-2 text-xl font-semibold leading-none h-5">
{{ __('Send invites to') }}
@ -23,26 +23,21 @@
/>
</div>
</div>
<div class="flex-1 flex flex-col gap-8 overflow-y-auto">
<div class="flex-1 flex flex-col px-2 gap-8 overflow-y-auto">
<div>
<label class="block text-xs text-ink-gray-5 mb-1.5">
{{ __('Invite by email') }}
</label>
<div
class="p-2 group bg-surface-gray-2 hover:bg-surface-gray-3 rounded"
>
<MultiSelectUserInput
class="flex-1"
inputClass="!bg-surface-gray-2 hover:!bg-surface-gray-3 group-hover:!bg-surface-gray-3"
:placeholder="__('john@doe.com')"
v-model="invitees"
:validate="validateEmail"
:error-message="
(value) => __('{0} is an invalid email address', [value])
<FormControl
type="textarea"
label="Invite by email"
placeholder="user1@example.com, user2@example.com, ..."
@input="updateInvitees($event.target.value)"
:debounce="100"
:disabled="inviteByEmail.loading"
:description="
__(
'You can invite multiple users by comma separating their email addresses',
)
"
:fetchUsers="false"
/>
</div>
<div
v-if="userExistMessage || inviteeExistMessage"
class="text-xs text-ink-red-3 mt-1.5"
@ -100,15 +95,9 @@
</div>
</template>
<script setup>
import MultiSelectUserInput from '@/components/Controls/MultiSelectUserInput.vue'
import { validateEmail, convertArrayToString } from '@/utils'
import { usersStore } from '@/stores/users'
import {
createListResource,
createResource,
FormControl,
Tooltip,
} from 'frappe-ui'
import { createListResource, createResource, FormControl } from 'frappe-ui'
import { useOnboarding } from 'frappe-ui/frappe'
import { ref, computed } from 'vue'
@ -208,6 +197,15 @@ const pendingInvitations = createListResource({
doctype: 'CRM Invitation',
filters: { status: 'Pending' },
fields: ['name', 'email', 'role'],
pageLength: 999,
auto: true,
})
function updateInvitees(value) {
const emails = value
.split(',')
.map((email) => email.trim())
.filter((email) => validateEmail(email))
invitees.value = emails
}
</script>

View File

@ -3,21 +3,23 @@
v-model="showSettings"
:options="{ size: '5xl' }"
@close="activeSettingsPage = ''"
:disableOutsideClickToClose="disableSettingModalOutsideClick"
>
<template #body>
<div class="flex h-[calc(100vh_-_8rem)]">
<div class="flex flex-col p-2 w-52 shrink-0 bg-surface-gray-2">
<h1 class="px-2 pt-2 mb-3 text-lg font-semibold text-ink-gray-8">
<div class="flex flex-col p-1 w-52 shrink-0 bg-surface-gray-2">
<h1 class="px-3 pt-3 pb-2 text-lg font-semibold text-ink-gray-8">
{{ __('Settings') }}
</h1>
<div v-for="tab in tabs">
<div class="flex flex-col overflow-y-auto">
<template v-for="tab in tabs" :key="tab.label">
<div
v-if="!tab.hideLabel"
class="mb-2 mt-3 flex cursor-pointer gap-1.5 px-1 text-base font-medium text-ink-gray-5 transition-all duration-300 ease-in-out"
class="py-[7px] px-2 my-1 flex cursor-pointer gap-1.5 text-base text-ink-gray-5 transition-all duration-300 ease-in-out"
>
<span>{{ __(tab.label) }}</span>
</div>
<nav class="space-y-1">
<nav class="space-y-1 px-1">
<SidebarLink
v-for="i in tab.items"
:icon="i.icon"
@ -31,6 +33,7 @@
@click="activeSettingsPage = i.label"
/>
</nav>
</template>
</div>
</div>
<div class="flex flex-col flex-1 overflow-y-auto bg-surface-modal">
@ -41,17 +44,24 @@
</Dialog>
</template>
<script setup>
import CircleDollarSignIcon from '~icons/lucide/circle-dollar-sign'
import TrendingUpDownIcon from '~icons/lucide/trending-up-down'
import SparkleIcon from '@/components/Icons/SparkleIcon.vue'
import WhatsAppIcon from '@/components/Icons/WhatsAppIcon.vue'
import ERPNextIcon from '@/components/Icons/ERPNextIcon.vue'
import PhoneIcon from '@/components/Icons/PhoneIcon.vue'
import Email2Icon from '@/components/Icons/Email2Icon.vue'
import EmailTemplateIcon from '@/components/Icons/EmailTemplateIcon.vue'
import SettingsIcon2 from '@/components/Icons/SettingsIcon2.vue'
import Users from '@/components/Settings/Users.vue'
import GeneralSettingsPage from '@/components/Settings/General/GeneralSettingsPage.vue'
import InviteUserPage from '@/components/Settings/InviteUserPage.vue'
import ProfileSettings from '@/components/Settings/ProfileSettings.vue'
import WhatsAppSettings from '@/components/Settings/WhatsAppSettings.vue'
import ERPNextSettings from '@/components/Settings/ERPNextSettings.vue'
import BrandSettings from '@/components/Settings/BrandSettings.vue'
import HomeActions from '@/components/Settings/HomeActions.vue'
import ForecastingSettings from '@/components/Settings/ForecastingSettings.vue'
import CurrencySettings from '@/components/Settings/CurrencySettings.vue'
import EmailTemplatePage from '@/components/Settings/EmailTemplate/EmailTemplatePage.vue'
import TelephonySettings from '@/components/Settings/TelephonySettings.vue'
import EmailConfig from '@/components/Settings/EmailConfig.vue'
@ -61,9 +71,11 @@ import {
isWhatsappInstalled,
showSettings,
activeSettingsPage,
disableSettingModalOutsideClick,
} from '@/composables/settings'
import { Dialog, Avatar } from 'frappe-ui'
import { ref, markRaw, computed, watch, h } from 'vue'
import AssignmentRulePage from './AssignmentRules/AssignmentRulePage.vue'
const { isManager, isTelephonyAgent, getUser } = usersStore()
@ -72,7 +84,7 @@ const user = computed(() => getUser() || {})
const tabs = computed(() => {
let _tabs = [
{
label: __('Settings'),
label: __('Personal Settings'),
hideLabel: true,
items: [
{
@ -85,12 +97,32 @@ const tabs = computed(() => {
}),
component: markRaw(ProfileSettings),
},
],
},
{
label: __('General'),
icon: 'settings',
component: markRaw(GeneralSettingsPage),
label: __('System Configuration'),
items: [
{
label: __('Forecasting'),
component: markRaw(ForecastingSettings),
icon: TrendingUpDownIcon,
},
{
label: __('Currency & Exchange Rate'),
icon: CircleDollarSignIcon,
component: markRaw(CurrencySettings),
},
{
label: __('Brand Settings'),
icon: SparkleIcon,
component: markRaw(BrandSettings),
},
],
condition: () => isManager(),
},
{
label: __('User Management'),
items: [
{
label: __('Users'),
icon: 'user',
@ -103,6 +135,12 @@ const tabs = computed(() => {
component: markRaw(InviteUserPage),
condition: () => isManager(),
},
],
condition: () => isManager(),
},
{
label: __('Email Settings'),
items: [
{
label: __('Email Accounts'),
icon: Email2Icon,
@ -116,6 +154,27 @@ const tabs = computed(() => {
},
],
},
{
label: __('Automation & Rules'),
items: [
{
label: __('Assignment rules'),
icon: markRaw(h(SettingsIcon2, { class: 'rotate-90' })),
component: markRaw(AssignmentRulePage),
},
],
},
{
label: __('Customization'),
items: [
{
label: __('Home Actions'),
component: markRaw(HomeActions),
icon: 'home',
},
],
condition: () => isManager(),
},
{
label: __('Integrations', null, 'FCRM'),
items: [

View File

@ -169,8 +169,16 @@
import AddExistingUserModal from '@/components/Modals/AddExistingUserModal.vue'
import { activeSettingsPage } from '@/composables/settings'
import { usersStore } from '@/stores/users'
import { TemplateOption, DropdownOption } from '@/utils'
import { Avatar, TextInput, toast, call, FeatherIcon, Tooltip } from 'frappe-ui'
import { DropdownOption } from '@/utils'
import {
Dropdown,
Avatar,
TextInput,
toast,
call,
FeatherIcon,
Tooltip,
} from 'frappe-ui'
import { ref, computed, onMounted } from 'vue'
const { users, isAdmin, isManager } = usersStore()
@ -208,29 +216,19 @@ function getMoreOptions(user) {
let options = [
{
label: __('Remove'),
component: (props) =>
TemplateOption({
option: __('Remove'),
icon: 'trash-2',
active: props.active,
onClick: (e) => {
e.preventDefault()
e.stopPropagation()
confirmRemove.value = true
},
}),
condition: () => !confirmRemove.value,
},
{
label: __('Confirm Remove'),
component: (props) =>
TemplateOption({
option: __('Confirm Remove'),
icon: 'trash-2',
active: props.active,
theme: 'danger',
theme: 'red',
onClick: () => removeUser(user, true),
}),
condition: () => confirmRemove.value,
},
]
@ -242,38 +240,35 @@ function getDropdownOptions(user) {
let options = [
{
label: __('Admin'),
component: (props) =>
component: () =>
DropdownOption({
option: __('Admin'),
icon: 'shield',
active: props.active,
selected: user.role === 'System Manager',
onClick: () => updateRole(user, 'System Manager'),
}),
onClick: () => updateRole(user, 'System Manager'),
condition: () => isAdmin(),
},
{
label: __('Manager'),
component: (props) =>
component: () =>
DropdownOption({
option: __('Manager'),
icon: 'briefcase',
active: props.active,
selected: user.role === 'Sales Manager',
onClick: () => updateRole(user, 'Sales Manager'),
}),
onClick: () => updateRole(user, 'Sales Manager'),
condition: () => isManager(),
},
{
label: __('Sales User'),
component: (props) =>
component: () =>
DropdownOption({
option: __('Sales User'),
icon: 'user-check',
active: props.active,
selected: user.role === 'Sales User',
onClick: () => updateRole(user, 'Sales User'),
}),
onClick: () => updateRole(user, 'Sales User'),
},
]

View File

@ -41,4 +41,7 @@ export const mobileSidebarOpened = ref(false)
export const isMobileView = computed(() => window.innerWidth < 768)
export const showSettings = ref(false)
export const disableSettingModalOutsideClick = ref(false)
export const activeSettingsPage = ref('')

View File

@ -462,23 +462,12 @@ export function runSequentially(functions) {
}, Promise.resolve())
}
export function DropdownOption({
active,
option,
theme,
icon,
onClick,
selected,
}) {
export function DropdownOption({ option, icon, selected }) {
return h(
'button',
{
class: [
active ? 'bg-surface-gray-2' : 'text-ink-gray-8',
'group flex w-full justify-between items-center rounded-md px-2 py-2 text-sm',
theme == 'danger' ? 'text-ink-red-3 hover:bg-ink-red-1' : '',
],
onClick: !selected ? onClick : null,
class:
'group flex w-full text-ink-gray-8 justify-between items-center rounded-md px-2 py-2 text-sm hover:bg-surface-gray-2',
},
[
h('div', { class: 'flex gap-2' }, [
@ -501,31 +490,167 @@ export function DropdownOption({
)
}
export function TemplateOption({ active, option, theme, icon, onClick }) {
return h(
'button',
{
class: [
active ? 'bg-surface-gray-2 text-ink-gray-8' : 'text-ink-gray-7',
'group flex w-full gap-2 items-center rounded-md px-2 py-2 text-sm',
theme == 'danger' ? 'text-ink-red-3 hover:bg-ink-red-1' : '',
],
onClick: onClick,
},
[
icon
? h(FeatherIcon, {
name: icon,
class: ['h-4 w-4 shrink-0'],
'aria-hidden': true,
})
: null,
h('span', { class: 'whitespace-nowrap' }, option),
],
)
}
export function copy(obj) {
if (!obj) return obj
return JSON.parse(JSON.stringify(obj))
}
export const convertToConditions = ({ conditions, fieldPrefix }) => {
if (!conditions || conditions.length === 0) {
return ''
}
const processCondition = (condition) => {
if (typeof condition === 'string') {
return condition.toLowerCase()
}
if (Array.isArray(condition)) {
// Nested condition group
if (Array.isArray(condition[0])) {
const nestedStr = convertToConditions({
conditions: condition,
fieldPrefix,
})
return `(${nestedStr})`
}
// Simple condition: [fieldname, operator, value]
const [field, operator, value] = condition
const fieldAccess = fieldPrefix ? `${fieldPrefix}.${field}` : field
const operatorMap = {
equals: '==',
'=': '==',
'==': '==',
'!=': '!=',
'not equals': '!=',
'<': '<',
'<=': '<=',
'>': '>',
'>=': '>=',
in: 'in',
'not in': 'not in',
like: 'like',
'not like': 'not like',
is: 'is',
'is not': 'is not',
between: 'between',
}
let op = operatorMap[operator.toLowerCase()] || operator
if (
(op === '==' || op === '!=') &&
(String(value).toLowerCase() === 'yes' ||
String(value).toLowerCase() === 'no')
) {
let checkVal = String(value).toLowerCase() === 'yes'
if (op === '!=') {
checkVal = !checkVal
}
return checkVal ? fieldAccess : `not ${fieldAccess}`
}
if (op === 'is' && String(value).toLowerCase() === 'set') {
return fieldAccess
}
if (
(op === 'is' && String(value).toLowerCase() === 'not set') ||
(op === 'is not' && String(value).toLowerCase() === 'set')
) {
return `not ${fieldAccess}`
}
if (op === 'like') {
return `(${fieldAccess} and "${value}" in ${fieldAccess})`
}
if (op === 'not like') {
return `(${fieldAccess} and "${value}" not in ${fieldAccess})`
}
if (
op === 'between' &&
typeof value === 'string' &&
value.includes(',')
) {
const [start, end] = value.split(',').map((v) => v.trim())
return `(${fieldAccess} >= "${start}" and ${fieldAccess} <= "${end}")`
}
let valueStr = ''
if (op === 'in' || op === 'not in') {
let items
if (Array.isArray(value)) {
items = value.map((v) => `"${String(v).trim()}"`)
} else if (typeof value === 'string') {
items = value.split(',').map((v) => `"${v.trim()}"`)
} else {
items = [`"${String(value).trim()}"`]
}
valueStr = `[${items.join(', ')}]`
return `(${fieldAccess} and ${fieldAccess} ${op} ${valueStr})`
}
if (typeof value === 'string') {
valueStr = `"${value.replace(/"/g, '\\"')}"`
} else if (typeof value === 'number' || typeof value === 'boolean') {
valueStr = String(value)
} else if (value === null || value === undefined) {
return op === '==' || op === 'is' ? `not ${fieldAccess}` : fieldAccess
} else {
valueStr = `"${String(value).replace(/"/g, '\\"')}"`
}
return `${fieldAccess} ${op} ${valueStr}`
}
return ''
}
const parts = conditions.map(processCondition)
return parts.join(' ')
}
export function validateConditions(conditions) {
if (!Array.isArray(conditions)) return false
// Handle simple condition [field, operator, value]
if (
conditions.length === 3 &&
typeof conditions[0] === 'string' &&
typeof conditions[1] === 'string'
) {
return conditions[0] !== '' && conditions[1] !== '' && conditions[2] !== ''
}
// Iterate through conditions and logical operators
for (let i = 0; i < conditions.length; i++) {
const item = conditions[i]
// Skip logical operators (they will be validated by their position)
if (item === 'and' || item === 'or') {
// Ensure logical operators are not at start/end and not consecutive
if (
i === 0 ||
i === conditions.length - 1 ||
conditions[i - 1] === 'and' ||
conditions[i - 1] === 'or'
) {
return false
}
continue
}
// Handle nested conditions (arrays)
if (Array.isArray(item)) {
if (!validateConditions(item)) {
return false
}
} else if (item !== undefined && item !== null) {
return false
}
}
return conditions.length > 0
}

View File

@ -2,72 +2,15 @@ import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
import vueJsx from '@vitejs/plugin-vue-jsx'
import path from 'path'
import fs from 'fs'
import frappeui from 'frappe-ui/vite'
import { VitePWA } from 'vite-plugin-pwa'
function appPath(app) {
const root = path.resolve(__dirname, '../..') // points to apps
const frontendPaths = [
// Standard frontend structure: appname/frontend/src
path.join(root, app, 'frontend', 'src'),
// Desk-based apps: appname/desk/src
path.join(root, app, 'desk', 'src'),
// Alternative frontend structures
path.join(root, app, 'client', 'src'),
path.join(root, app, 'ui', 'src'),
// Direct src structure: appname/src
path.join(root, app, 'src'),
]
return frontendPaths.find((srcPath) => fs.existsSync(srcPath)) || null
}
function hasApp(app) {
return fs.existsSync(appPath(app))
}
// List of frontend apps used in this project
let apps = []
const alias = [
// Default "@" for this app
{
find: '@',
replacement: path.resolve(__dirname, 'src'),
},
// App-specific aliases like @helpdesk, @hrms, etc.
...apps.map((app) =>
hasApp(app)
? { find: `@${app}`, replacement: appPath(app) }
: { find: `@${app}`, replacement: `virtual:${app}` },
),
]
const defineFlags = Object.fromEntries(
apps.map((app) => [
`__HAS_${app.toUpperCase()}__`,
JSON.stringify(hasApp(app)),
]),
)
const virtualStubPlugin = {
name: 'virtual-empty-modules',
resolveId(id) {
if (id.startsWith('virtual:')) return '\0' + id
},
load(id) {
if (id.startsWith('\0virtual:')) {
return 'export default {}; export const missing = true;'
}
},
}
console.log('Generated app aliases:', alias)
// https://vitejs.dev/config/
export default defineConfig({
define: defineFlags,
export default defineConfig(async ({ mode }) => {
const isDev = mode === 'development'
const frappeui = await importFrappeUIPlugin(isDev)
const config = {
plugins: [
frappeui({
frappeProxy: true,
@ -121,9 +64,12 @@ export default defineConfig({
],
},
}),
virtualStubPlugin,
],
resolve: { alias },
resolve: {
alias: {
'@': path.resolve(__dirname, 'src'),
},
},
optimizeDeps: {
include: [
'feather-icons',
@ -132,7 +78,46 @@ export default defineConfig({
'prosemirror-state',
'prosemirror-view',
'lowlight',
'interactjs'
'interactjs',
],
},
}
// Add local frappe-ui alias only in development if the local frappe-ui exists
if (isDev) {
try {
// Check if the local frappe-ui directory exists
const fs = await import('node:fs')
const localFrappeUIPath = path.resolve(__dirname, '../frappe-ui')
if (fs.existsSync(localFrappeUIPath)) {
config.resolve.alias['frappe-ui'] = localFrappeUIPath
} else {
console.warn('Local frappe-ui directory not found, using npm package')
}
} catch (error) {
console.warn(
'Error checking for local frappe-ui, using npm package:',
error.message,
)
}
}
return config
})
async function importFrappeUIPlugin(isDev) {
if (isDev) {
try {
const module = await import('../frappe-ui/vite')
return module.default
} catch (error) {
console.warn(
'Local frappe-ui not found, falling back to npm package:',
error.message,
)
}
}
// Fall back to npm package if local import fails
const module = await import('frappe-ui/vite')
return module.default
}

File diff suppressed because it is too large Load Diff

View File

@ -1,14 +1,10 @@
{
"private": true,
"type": "module",
"workspaces": ["frontend", "frappe-ui"],
"scripts": {
"postinstall": "cd frontend && yarn install",
"dev": "cd frontend && yarn dev",
"build": "cd frontend && yarn build",
"disable-workspaces": "sed -i '' 's/\"workspaces\"/\"aworkspaces\"/g' package.json",
"enable-workspaces": "sed -i '' 's/\"aworkspaces\"/\"workspaces\"/g' package.json && rm -rf node_modules ./frontend/node_modules/ frappe-ui/node_modules/ && yarn install",
"upgrade-frappeui": "cd frontend && yarn add frappe-ui@latest && cd ..",
"disable-workspaces-and-upgrade-frappeui": "yarn disable-workspaces && yarn upgrade-frappeui"
"upgrade-frappeui": "cd frontend && yarn add frappe-ui@latest && cd .."
}
}