snapshot of https://github.com/frappe/crm.git (develop, 2026-09-18; blobs > 131072B omitted)
Some checks failed
Frontend / Unit Tests & Coverage (push) Has been skipped
Server / Tests (frappe ${{ matrix.frappe-branch }}) (push) Has been skipped
Server / Resolve frappe matrix (push) Failing after 1s
Frontend / Lint (push) Failing after 1s
Frontend / Production Build (push) Failing after 1s
Server / Coverage Wrap Up (push) Has been skipped
Frontend / Coverage Wrap Up (push) Has been skipped
Regenerate POT file (translatable strings) / Regenerate POT file (develop) (push) Failing after 1s
Regenerate POT file (translatable strings) / Regenerate POT file (main-hotfix) (push) Failing after 1s
0
crm/public/.gitkeep
Normal file
BIN
crm/public/images/desk.png
Normal file
|
After Width: | Height: | Size: 11 KiB |
BIN
crm/public/images/logo.png
Normal file
|
After Width: | Height: | Size: 21 KiB |
4
crm/public/images/logo.svg
Normal file
@@ -0,0 +1,4 @@
|
||||
<svg width="300" height="300" viewBox="0 0 300 300" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M214.286 0H85.7143C38.3756 0 0 38.3756 0 85.7143V214.286C0 261.624 38.3756 300 85.7143 300H214.286C261.624 300 300 261.624 300 214.286V85.7143C300 38.3756 261.624 0 214.286 0Z" fill="#EF0BF5"/>
|
||||
<path d="M64.2141 90.301V111.862H214.339V140.214L160.187 193.146V208.993L139.705 208.885V193.146L85.6605 140.214H64.2141V149.269L118.259 202.202V230.23L181.634 230.769V202.202L235.786 149.269V90.301H64.2141Z" fill="white"/>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 534 B |
86
crm/public/js/domain_enrichment.js
Normal file
@@ -0,0 +1,86 @@
|
||||
// Domain Enrichment — desk form button + live progress.
|
||||
//
|
||||
// Adds an "Enrich from Website" button to CRM Lead / CRM Organization / CRM Deal.
|
||||
// Clicking it queues a background job; the progress steps stream back over realtime
|
||||
// and are shown to the user. When done, the form reloads to show the enriched fields.
|
||||
|
||||
frappe.provide("crm.domain_enrichment");
|
||||
|
||||
crm.domain_enrichment.setup = function (frm) {
|
||||
if (frm.is_new()) return;
|
||||
|
||||
frm.add_custom_button(__("Enrich from Website"), () => {
|
||||
const website = (frm.doc.website || "").trim();
|
||||
if (!website) {
|
||||
frappe.msgprint({
|
||||
title: __("No Website"),
|
||||
message: __("Set a Website on this record before enriching."),
|
||||
indicator: "orange",
|
||||
});
|
||||
return;
|
||||
}
|
||||
crm.domain_enrichment.run(frm, website);
|
||||
});
|
||||
};
|
||||
|
||||
crm.domain_enrichment.run = function (frm, website) {
|
||||
// A determinate progress dialog driven by realtime events.
|
||||
const total = 7; // pipeline.PROGRESS_STEPS; each event also carries data.total
|
||||
frappe.show_progress(__("Domain Enrichment"), 0, total, __("Queued…"));
|
||||
|
||||
const event = "domain_enrichment_progress";
|
||||
const handler = (data) => {
|
||||
if (
|
||||
!data ||
|
||||
data.reference_doctype !== frm.doctype ||
|
||||
data.reference_name !== frm.docname
|
||||
) {
|
||||
return; // not for this document
|
||||
}
|
||||
|
||||
frappe.show_progress(
|
||||
__("Domain Enrichment"),
|
||||
data.step,
|
||||
data.total,
|
||||
data.message
|
||||
);
|
||||
|
||||
if (data.status === "completed") {
|
||||
frappe.realtime.off(event, handler);
|
||||
frappe.hide_progress();
|
||||
frappe.show_alert(
|
||||
{ message: __("Enrichment complete"), indicator: "green" },
|
||||
5
|
||||
);
|
||||
frm.reload_doc();
|
||||
} else if (data.status === "error") {
|
||||
frappe.realtime.off(event, handler);
|
||||
frappe.hide_progress();
|
||||
frappe.msgprint({
|
||||
title: __("Enrichment Failed"),
|
||||
message: data.message || __("See Error Log."),
|
||||
indicator: "red",
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
frappe.realtime.on(event, handler);
|
||||
|
||||
frappe.call({
|
||||
method: "crm.domain_enrichment.api.enrich",
|
||||
args: {
|
||||
reference_doctype: frm.doctype,
|
||||
reference_name: frm.docname,
|
||||
},
|
||||
error: () => {
|
||||
frappe.realtime.off(event, handler);
|
||||
frappe.hide_progress();
|
||||
},
|
||||
});
|
||||
};
|
||||
|
||||
["CRM Lead", "CRM Organization", "CRM Deal"].forEach((doctype) => {
|
||||
frappe.ui.form.on(doctype, {
|
||||
refresh: crm.domain_enrichment.setup,
|
||||
});
|
||||
});
|
||||
40
crm/public/js/erpnext_quotation_prefill.js
Normal file
@@ -0,0 +1,40 @@
|
||||
frappe.ui.form.on('Quotation', {
|
||||
refresh(frm) {
|
||||
const field = frm.get_field('crm_deal')
|
||||
if (!field) return
|
||||
// Render as a link only works for read only display an editable data
|
||||
field.df.read_only = 1
|
||||
field.df.formatter = (value) =>
|
||||
value
|
||||
? `<a href="${window.location.origin}/crm/deals/${encodeURIComponent(value)}" target="_blank" rel="noopener">${frappe.utils.escape_html(value)}</a>`
|
||||
: value
|
||||
field.refresh()
|
||||
},
|
||||
onload(frm) {
|
||||
const crm_deal = frm.doc.crm_deal || frappe.route_options?.crm_deal
|
||||
if (!crm_deal) return
|
||||
if ((frm.doc.items || []).some((i) => i.item_code)) return
|
||||
|
||||
frappe.call({
|
||||
method: 'crm.fcrm.doctype.erpnext_crm_settings.erpnext_crm_settings.prefill_quotation_items',
|
||||
args: { crm_deal },
|
||||
callback: async (r) => {
|
||||
if (!r.message || !r.message.length) return
|
||||
if (!frm.doc.price_list_currency && frm.doc.currency) {
|
||||
await frm.set_value('price_list_currency', frm.doc.currency)
|
||||
}
|
||||
frm.clear_table('items')
|
||||
for (const item of r.message) {
|
||||
const row = frm.add_child('items')
|
||||
await frappe.model.set_value(row.doctype, row.name, 'item_code', item.item_code)
|
||||
await frappe.model.set_value(row.doctype, row.name, 'qty', item.qty)
|
||||
// price_list_rate must be set before discount_percentage: ERPNext
|
||||
// resets the discount to 0 when price_list_rate is falsy.
|
||||
await frappe.model.set_value(row.doctype, row.name, 'price_list_rate', item.price_list_rate)
|
||||
await frappe.model.set_value(row.doctype, row.name, 'discount_percentage', item.discount_percentage)
|
||||
}
|
||||
frm.refresh_field('items')
|
||||
},
|
||||
})
|
||||
},
|
||||
})
|
||||
17
crm/public/js/erpnext_sales_order_customer.js
Normal file
@@ -0,0 +1,17 @@
|
||||
frappe.ui.form.on('Sales Order', {
|
||||
refresh(frm) {
|
||||
// When a Sales Order is created from a CRM Deal quotation that has no
|
||||
// customer yet, create/fetch the customer and fill the mandatory field.
|
||||
if (frm.doc.docstatus !== 0 || frm.doc.customer || frm.__crm_customer_checked) return
|
||||
const item = (frm.doc.items || []).find((i) => i.prevdoc_docname)
|
||||
if (!item) return
|
||||
frm.__crm_customer_checked = true
|
||||
frappe.call({
|
||||
method: 'crm.fcrm.doctype.erpnext_crm_settings.erpnext_crm_settings.check_customer_for_quotation',
|
||||
args: { quotation: item.prevdoc_docname },
|
||||
callback: (r) => {
|
||||
if (r.message) frm.set_value('customer', r.message)
|
||||
},
|
||||
})
|
||||
},
|
||||
})
|
||||
BIN
crm/public/manifest/apple-icon-180.png
Normal file
|
After Width: | Height: | Size: 3.4 KiB |
BIN
crm/public/manifest/apple-splash-1125-2436.jpg
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
crm/public/manifest/apple-splash-1136-640.jpg
Normal file
|
After Width: | Height: | Size: 6.3 KiB |
BIN
crm/public/manifest/apple-splash-1170-2532.jpg
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
crm/public/manifest/apple-splash-1179-2556.jpg
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
crm/public/manifest/apple-splash-1242-2208.jpg
Normal file
|
After Width: | Height: | Size: 22 KiB |
BIN
crm/public/manifest/apple-splash-1242-2688.jpg
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
crm/public/manifest/apple-splash-1284-2778.jpg
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
crm/public/manifest/apple-splash-1290-2796.jpg
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
crm/public/manifest/apple-splash-1334-750.jpg
Normal file
|
After Width: | Height: | Size: 8.3 KiB |
BIN
crm/public/manifest/apple-splash-1488-2266.jpg
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
crm/public/manifest/apple-splash-1536-2048.jpg
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
crm/public/manifest/apple-splash-1620-2160.jpg
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
crm/public/manifest/apple-splash-1640-2360.jpg
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
crm/public/manifest/apple-splash-1668-2224.jpg
Normal file
|
After Width: | Height: | Size: 29 KiB |
BIN
crm/public/manifest/apple-splash-1668-2388.jpg
Normal file
|
After Width: | Height: | Size: 30 KiB |
BIN
crm/public/manifest/apple-splash-1792-828.jpg
Normal file
|
After Width: | Height: | Size: 12 KiB |
BIN
crm/public/manifest/apple-splash-2048-1536.jpg
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
crm/public/manifest/apple-splash-2048-2732.jpg
Normal file
|
After Width: | Height: | Size: 41 KiB |
BIN
crm/public/manifest/apple-splash-2160-1620.jpg
Normal file
|
After Width: | Height: | Size: 26 KiB |
BIN
crm/public/manifest/apple-splash-2208-1242.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
crm/public/manifest/apple-splash-2224-1668.jpg
Normal file
|
After Width: | Height: | Size: 27 KiB |
BIN
crm/public/manifest/apple-splash-2266-1488.jpg
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
crm/public/manifest/apple-splash-2360-1640.jpg
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
crm/public/manifest/apple-splash-2388-1668.jpg
Normal file
|
After Width: | Height: | Size: 28 KiB |
BIN
crm/public/manifest/apple-splash-2436-1125.jpg
Normal file
|
After Width: | Height: | Size: 19 KiB |
BIN
crm/public/manifest/apple-splash-2532-1170.jpg
Normal file
|
After Width: | Height: | Size: 21 KiB |
BIN
crm/public/manifest/apple-splash-2556-1179.jpg
Normal file
|
After Width: | Height: | Size: 20 KiB |
BIN
crm/public/manifest/apple-splash-2688-1242.jpg
Normal file
|
After Width: | Height: | Size: 23 KiB |
BIN
crm/public/manifest/apple-splash-2732-2048.jpg
Normal file
|
After Width: | Height: | Size: 39 KiB |
BIN
crm/public/manifest/apple-splash-2778-1284.jpg
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
crm/public/manifest/apple-splash-2796-1290.jpg
Normal file
|
After Width: | Height: | Size: 25 KiB |
BIN
crm/public/manifest/apple-splash-640-1136.jpg
Normal file
|
After Width: | Height: | Size: 7.2 KiB |
BIN
crm/public/manifest/apple-splash-750-1334.jpg
Normal file
|
After Width: | Height: | Size: 9.5 KiB |
BIN
crm/public/manifest/apple-splash-828-1792.jpg
Normal file
|
After Width: | Height: | Size: 13 KiB |
BIN
crm/public/manifest/manifest-icon-192.maskable.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
crm/public/manifest/manifest-icon-512.maskable.png
Normal file
|
After Width: | Height: | Size: 10 KiB |