Compare commits

...

1231 Commits

Author SHA1 Message Date
MochaMind
e9021e85b6 chore: Persian translations 2025-10-22 21:16:26 +05:30
MochaMind
904cfdb039 chore: Polish translations 2025-10-22 21:16:15 +05:30
MochaMind
1d3bd69a67 chore: Norwegian Bokmal translations 2025-10-21 21:12:39 +05:30
MochaMind
c48a8bbc76 chore: Persian translations 2025-10-19 20:02:09 +05:30
Shariq Ansari
2a9eb9fc42
Merge pull request #1310 from frappe/l10n_develop4 2025-10-15 04:06:38 -07:00
Shariq Ansari
d1473a8db4
Merge pull request #1318 from frappe/pot_develop_2025-10-12 2025-10-15 04:06:11 -07:00
MochaMind
c9eaa416eb chore: Polish translations 2025-10-13 19:14:35 +05:30
MochaMind
35fb35ad5f chore: Polish translations 2025-10-12 18:38:48 +05:30
frappe-pr-bot
cba91c5141 chore: update POT file 2025-10-12 09:34:51 +00:00
MochaMind
bf06a17397 chore: Burmese translations 2025-10-11 17:48:03 +05:30
MochaMind
cc8d30a00d chore: Persian translations 2025-10-10 17:29:04 +05:30
MochaMind
946b130449 chore: Burmese translations 2025-10-07 16:54:02 +05:30
MochaMind
dd57090677 chore: Persian translations 2025-10-07 16:53:52 +05:30
MochaMind
0f2d510a14 chore: Portuguese, Brazilian translations 2025-10-07 16:53:50 +05:30
Shariq Ansari
03c2b49a06
Merge pull request #1305 from frappe/l10n_develop4 2025-10-02 11:07:17 -07:00
MochaMind
3b7439d957 chore: Serbian (Latin) translations 2025-10-02 14:10:53 +05:30
MochaMind
91d5d36080 chore: Serbian (Cyrillic) translations 2025-10-02 14:10:41 +05:30
Shariq Ansari
67bc19bdaa
Merge pull request #1303 from frappe/l10n_develop4 2025-10-01 01:44:47 -07:00
MochaMind
5cd122172e chore: Tamil translations 2025-10-01 14:08:33 +05:30
MochaMind
1a3ed88240 chore: Esperanto translations 2025-10-01 14:08:31 +05:30
MochaMind
20773c07b4 chore: Serbian (Latin) translations 2025-10-01 14:08:30 +05:30
MochaMind
3d92c2bb57 chore: Norwegian Bokmal translations 2025-10-01 14:08:28 +05:30
MochaMind
548cf3b739 chore: Bosnian translations 2025-10-01 14:08:27 +05:30
MochaMind
65b305b652 chore: Croatian translations 2025-10-01 14:08:25 +05:30
MochaMind
92f93fcf21 chore: Thai translations 2025-10-01 14:08:23 +05:30
MochaMind
ef96d09bf6 chore: Persian translations 2025-10-01 14:08:22 +05:30
MochaMind
b27aae1906 chore: Indonesian translations 2025-10-01 14:08:20 +05:30
MochaMind
bc5024f0d7 chore: Portuguese, Brazilian translations 2025-10-01 14:08:19 +05:30
MochaMind
f8177eb597 chore: Vietnamese translations 2025-10-01 14:08:18 +05:30
MochaMind
2283b54b89 chore: Chinese Simplified translations 2025-10-01 14:08:16 +05:30
MochaMind
237e23e8d0 chore: Turkish translations 2025-10-01 14:08:15 +05:30
MochaMind
9dafb9ca91 chore: Swedish translations 2025-10-01 14:08:13 +05:30
MochaMind
6293a40431 chore: Serbian (Cyrillic) translations 2025-10-01 14:08:12 +05:30
MochaMind
31f1f07faf chore: Russian translations 2025-10-01 14:08:10 +05:30
MochaMind
9a08013766 chore: Portuguese translations 2025-10-01 14:08:09 +05:30
MochaMind
5e26026f00 chore: Polish translations 2025-10-01 14:08:07 +05:30
MochaMind
1d1d90d78b chore: Dutch translations 2025-10-01 14:08:06 +05:30
MochaMind
30d6e7eee5 chore: Italian translations 2025-10-01 14:08:05 +05:30
MochaMind
9a6d2b8e66 chore: Hungarian translations 2025-10-01 14:08:03 +05:30
MochaMind
98bb17b01c chore: German translations 2025-10-01 14:08:02 +05:30
MochaMind
80560afe7f chore: Danish translations 2025-10-01 14:08:00 +05:30
MochaMind
4681713262 chore: Czech translations 2025-10-01 14:07:59 +05:30
MochaMind
04da9f79cc chore: Arabic translations 2025-10-01 14:07:58 +05:30
MochaMind
29e5543951 chore: Spanish translations 2025-10-01 14:07:56 +05:30
MochaMind
7bc7f0f8dd chore: French translations 2025-10-01 14:07:55 +05:30
Shariq Ansari
5dbaec3322
Merge pull request #1301 from shariquerik/frappe-ui-setup 2025-10-01 00:11:51 -07:00
Shariq Ansari
6055111cdb
Merge branch 'develop' into frappe-ui-setup 2025-10-01 00:10:46 -07:00
Shariq Ansari
01a37cdc60 refactor: update Vite configuration to check for local frappe-ui plugin 2025-10-01 00:09:35 -07:00
Shariq Ansari
cee25b47ab
Merge pull request #1298 from frappe/l10n_develop4 2025-10-01 00:00:49 -07:00
Shariq Ansari
c04e3866d3
Merge pull request #1294 from frappe/pot_develop_2025-09-28 2025-09-30 17:12:34 +05:30
MochaMind
bce5450095 chore: Persian translations 2025-09-30 14:07:42 +05:30
frappe-pr-bot
c6b0d5674e chore: update POT file 2025-09-28 09:35:03 +00:00
Shariq Ansari
addad3735b
Merge pull request #1292 from frappe/l10n_develop4 2025-09-28 13:25:11 +05:30
MochaMind
7b41b6dfed chore: Norwegian Bokmal translations 2025-09-28 13:20:55 +05:30
MochaMind
174413b3eb chore: Swedish translations 2025-09-28 13:20:46 +05:30
MochaMind
9c2f5d1005 chore: Hungarian translations 2025-09-28 13:20:39 +05:30
Shariq Ansari
c00964da0b
Merge pull request #1289 from frappe/l10n_develop3 2025-09-27 08:20:38 +05:30
Shariq Ansari
e336d0ce38 chore: Norwegian Bokmal translations 2025-09-27 03:19:54 +05:30
Shariq Ansari
b1b7c5d246
Merge pull request #1279 from frappe/l10n_develop3 2025-09-25 21:52:44 +05:30
Shariq Ansari
4b6d2fb9b6
Merge pull request #1284 from shariquerik/upgrade-frappe-ui 2025-09-25 21:52:06 +05:30
Shariq Ansari
171060df8a build(deps): bump frappeui to 0.1.201 2025-09-25 21:51:02 +05:30
Shariq Ansari
96b28cf11a
Merge pull request #1282 from shariquerik/validate-mandatory-field 2025-09-25 21:47:43 +05:30
Shariq Ansari
dbcda4c548 fix: add validation for mandatory fields in useDocument 2025-09-25 21:41:02 +05:30
Shariq Ansari
9e92282e25 chore: Norwegian Bokmal translations 2025-09-25 02:59:56 +05:30
Shariq Ansari
0138716e07 chore: Serbian (Latin) translations 2025-09-25 02:59:42 +05:30
Shariq Ansari
589c95e263 chore: Serbian (Cyrillic) translations 2025-09-25 02:59:37 +05:30
Shariq Ansari
a4e2663b24 chore: Norwegian Bokmal translations 2025-09-24 02:56:03 +05:30
Shariq Ansari
f91ac266ca chore: Norwegian Bokmal translations 2025-09-23 02:12:50 +05:30
Shariq Ansari
415d5410ba chore: Danish translations 2025-09-23 02:12:49 +05:30
Shariq Ansari
9fc20a3078 chore: Esperanto translations 2025-09-23 02:12:47 +05:30
Shariq Ansari
43dadfe746 chore: Croatian translations 2025-09-23 02:12:46 +05:30
Shariq Ansari
56071d5e0d chore: Thai translations 2025-09-23 02:12:44 +05:30
Shariq Ansari
b0e79d0aef chore: Persian translations 2025-09-23 02:12:43 +05:30
Shariq Ansari
5848649955 chore: Vietnamese translations 2025-09-23 02:12:42 +05:30
Shariq Ansari
3c5ee979f8 chore: Chinese Simplified translations 2025-09-23 02:12:40 +05:30
Shariq Ansari
2acd7476c8 chore: Turkish translations 2025-09-23 02:12:39 +05:30
Shariq Ansari
66c5865828 chore: Russian translations 2025-09-23 02:12:37 +05:30
Shariq Ansari
103a137af1 chore: Portuguese translations 2025-09-23 02:12:36 +05:30
Shariq Ansari
52cc70d704 chore: Dutch translations 2025-09-23 02:12:35 +05:30
Shariq Ansari
d72dcee7b6 chore: Hungarian translations 2025-09-23 02:12:33 +05:30
Shariq Ansari
b473b27f9a chore: Czech translations 2025-09-23 02:12:32 +05:30
Shariq Ansari
8805560144 chore: Arabic translations 2025-09-23 02:12:30 +05:30
Shariq Ansari
3f0c4e9614 chore: Spanish translations 2025-09-23 02:12:29 +05:30
Shariq Ansari
2b13c3f277 chore: French translations 2025-09-23 02:12:27 +05:30
Shariq Ansari
b6fa3bf32b chore: German translations 2025-09-23 02:12:26 +05:30
Shariq Ansari
ae9e59aa00 chore: Serbian (Latin) translations 2025-09-23 02:12:25 +05:30
Shariq Ansari
4533becc62 chore: Bosnian translations 2025-09-23 02:12:23 +05:30
Shariq Ansari
57bd9fe70a chore: Indonesian translations 2025-09-23 02:12:22 +05:30
Shariq Ansari
013c21a5d1 chore: Portuguese, Brazilian translations 2025-09-23 02:12:21 +05:30
Shariq Ansari
9a780039e5 chore: Swedish translations 2025-09-23 02:12:19 +05:30
Shariq Ansari
1bd62289dc chore: Serbian (Cyrillic) translations 2025-09-23 02:12:18 +05:30
Shariq Ansari
f7382f40ac chore: Polish translations 2025-09-23 02:12:17 +05:30
Shariq Ansari
3c870ce042 chore: Italian translations 2025-09-23 02:12:15 +05:30
Shariq Ansari
c05c2393f8
Merge pull request #1266 from frappe/pot_develop_2025-09-21 2025-09-22 15:10:14 +05:30
Shariq Ansari
c16f2a286f
Merge pull request #1262 from frappe/l10n_develop3 2025-09-22 15:09:58 +05:30
Shariq Ansari
07994ec071
Merge pull request #1272 from shariquerik/timezone-fix 2025-09-22 15:09:15 +05:30
Shariq Ansari
96c0c99939 build(deps): bump frappeui to 0.1.200 2025-09-22 15:01:48 +05:30
Shariq Ansari
ce632c69c1 chore: Norwegian Bokmal translations 2025-09-22 02:17:19 +05:30
frappe-pr-bot
625e472303 chore: update POT file 2025-09-21 09:35:13 +00:00
Shariq Ansari
93ed6fcddd chore: Norwegian Bokmal translations 2025-09-21 01:59:49 +05:30
Shariq Ansari
e3eff7f78d chore: Norwegian Bokmal translations 2025-09-20 02:02:45 +05:30
Shariq Ansari
394da5e002 chore: Norwegian Bokmal translations 2025-09-19 02:05:23 +05:30
Shariq Ansari
887ae4ef57
Merge pull request #1256 from shariquerik/better-settings 2025-09-18 15:28:46 +05:30
Shariq Ansari
536d657e5b
Merge pull request #1257 from frappe/l10n_develop3 2025-09-18 15:11:59 +05:30
Shariq Ansari
d687a2eb56 refactor: adjust padding and improve layout for Settings component 2025-09-18 14:43:44 +05:30
Shariq Ansari
1044adc494 refactor: adjust padding and improve layout for Currency and Forecasting settings components 2025-09-18 13:36:06 +05:30
Shariq Ansari
9f95a3a2b2 refactor: update styling and improve layout for assignment rules components 2025-09-18 13:29:44 +05:30
Shariq Ansari
fca831b92e chore: Portuguese translations 2025-09-18 01:57:09 +05:30
Shariq Ansari
69f8090311 refactor: replace EmailMultiSelect with FormControl for inviting users by email 2025-09-17 13:14:27 +05:30
Shariq Ansari
ac34ac9b87 refactor: remove TemplateOption component usage and simplify dropdown options in multiple components 2025-09-17 13:01:49 +05:30
Shariq Ansari
129f8a00b6 refactor: update Vite configuration to support dynamic loading of frappe-ui in development mode 2025-09-17 12:27:55 +05:30
Shariq Ansari
6328b6941b revert: create dynamic alias to use components from frontend vue apps 2025-09-17 12:27:55 +05:30
Shariq Ansari
fbc9e37036 refactor: reduce gap in Brand logo and Favicon sections for improved layout 2025-09-17 12:27:55 +05:30
Shariq Ansari
149901f605 refactor: remove icon-left from Update button in multiple settings components 2025-09-17 12:27:55 +05:30
Shariq Ansari
7e21a5fee2 feat: Auto update expected deal value based on products value 2025-09-17 12:27:17 +05:30
Shariq Ansari
f4ff6bbdf3 refactor: add ForecastingSettings component and remove GeneralSettingsPage component 2025-09-17 12:27:17 +05:30
Shariq Ansari
9150233173 fix: add auto-update expected deal value checkbox in FCRM settings 2025-09-17 12:27:17 +05:30
Shariq Ansari
186584c1ac refactor: CurrencySettings component 2025-09-17 12:27:17 +05:30
Shariq Ansari
3752c61157 refactor: update BrandSettings component to improve logo and favicon handling 2025-09-17 12:27:04 +05:30
Shariq Ansari
a6ecc5cfed refactor: HomeActions component 2025-09-17 12:27:04 +05:30
Shariq Ansari
84e0fe30a9 refactor: BrandSettings component 2025-09-17 12:26:46 +05:30
Shariq Ansari
03acea69b1 refactor: enhance Settings component structure 2025-09-17 12:23:03 +05:30
Shariq Ansari
e19f750831 refactor: clean up ImageUploader component and improve label handling 2025-09-17 12:23:03 +05:30
Shariq Ansari
a52bfee98d
Merge pull request #1252 from pratikb64/fix/assignment-rule-ui 2025-09-17 12:17:14 +05:30
Pratik Badhe
41ef219d0a revert: yarn.lock file 2025-09-17 06:29:00 +00:00
Shariq Ansari
0a2f9e31c0
Merge branch 'develop' into fix/assignment-rule-ui 2025-09-17 11:42:23 +05:30
Shariq Ansari
69bcf0846c
Merge pull request #1253 from frappe/l10n_develop3 2025-09-17 11:37:33 +05:30
Shariq Ansari
b6e3cdfc37 chore: Norwegian Bokmal translations 2025-09-17 01:33:08 +05:30
Shariq Ansari
c0171c0555 chore: Danish translations 2025-09-17 01:33:07 +05:30
Shariq Ansari
6f154e191a chore: Esperanto translations 2025-09-17 01:33:06 +05:30
Shariq Ansari
552e500a31 chore: Croatian translations 2025-09-17 01:33:04 +05:30
Shariq Ansari
bf6940a6ff chore: Thai translations 2025-09-17 01:33:03 +05:30
Shariq Ansari
dc9b07b02a chore: Persian translations 2025-09-17 01:33:01 +05:30
Shariq Ansari
0a45094c33 chore: Vietnamese translations 2025-09-17 01:33:00 +05:30
Shariq Ansari
247d8e043e chore: Chinese Simplified translations 2025-09-17 01:32:58 +05:30
Shariq Ansari
73a1ecd418 chore: Turkish translations 2025-09-17 01:32:57 +05:30
Shariq Ansari
77e7bb011b chore: Russian translations 2025-09-17 01:32:55 +05:30
Shariq Ansari
9233e77ab8 chore: Portuguese translations 2025-09-17 01:32:54 +05:30
Shariq Ansari
32e5d56ef1 chore: Dutch translations 2025-09-17 01:32:52 +05:30
Shariq Ansari
cea6b6c6b4 chore: Hungarian translations 2025-09-17 01:32:51 +05:30
Shariq Ansari
2d636d7ffb chore: Czech translations 2025-09-17 01:32:49 +05:30
Shariq Ansari
9d9caf2856 chore: Arabic translations 2025-09-17 01:32:48 +05:30
Shariq Ansari
4ff4f3c5b5 chore: Spanish translations 2025-09-17 01:32:46 +05:30
Shariq Ansari
8167e1388d chore: French translations 2025-09-17 01:32:45 +05:30
Shariq Ansari
8e3cf3846a chore: German translations 2025-09-17 01:32:43 +05:30
Shariq Ansari
2d8ada04c8 chore: Serbian (Latin) translations 2025-09-17 01:32:42 +05:30
Shariq Ansari
4fba2353cf chore: Bosnian translations 2025-09-17 01:32:41 +05:30
Shariq Ansari
f251d83e97 chore: Indonesian translations 2025-09-17 01:32:39 +05:30
Shariq Ansari
283b34662e chore: Portuguese, Brazilian translations 2025-09-17 01:32:38 +05:30
Shariq Ansari
9bcfcf4ac7 chore: Swedish translations 2025-09-17 01:32:36 +05:30
Shariq Ansari
d80bbcd33d chore: Serbian (Cyrillic) translations 2025-09-17 01:32:34 +05:30
Shariq Ansari
42ee5ea64d chore: Polish translations 2025-09-17 01:32:33 +05:30
Shariq Ansari
1472a7f33d chore: Italian translations 2025-09-17 01:32:32 +05:30
Shariq Ansari
aabcb9b7ce
Merge pull request #1242 from frappe/l10n_develop3 2025-09-16 14:19:05 +05:30
Shariq Ansari
9e8a247dee
Merge pull request #1245 from frappe/pot_develop_2025-09-14 2025-09-16 14:18:32 +05:30
Shariq Ansari
2e5f4a9d22 chore: Danish translations 2025-09-16 01:17:10 +05:30
Shariq Ansari
100d01334a chore: Persian translations 2025-09-16 01:17:07 +05:30
Shariq Ansari
03ab96d94f chore: Portuguese translations 2025-09-16 01:17:02 +05:30
Shariq Ansari
6f640f5eee chore: Norwegian Bokmal translations 2025-09-15 00:48:54 +05:30
frappe-pr-bot
1627cf1e54 chore: update POT file 2025-09-14 09:35:17 +00:00
Shariq Ansari
376917bc75 chore: Norwegian Bokmal translations 2025-09-14 00:49:30 +05:30
Shariq Ansari
54753d3274 chore: Portuguese translations 2025-09-14 00:49:28 +05:30
Shariq Ansari
3c3108a9c1 chore: Turkish translations 2025-09-12 00:21:46 +05:30
Shariq Ansari
e0cfae1eb3 chore: Norwegian Bokmal translations 2025-09-11 00:24:54 +05:30
Shariq Ansari
fa03245eff chore: Norwegian Bokmal translations 2025-09-09 23:38:04 +05:30
Shariq Ansari
f253392ba7 chore: Serbian (Latin) translations 2025-09-09 23:38:03 +05:30
Shariq Ansari
6e608d845b chore: Serbian (Cyrillic) translations 2025-09-09 23:38:02 +05:30
Pratik Badhe
db577afc56 fix: paddings and labels 2025-09-09 09:00:31 +00:00
Shariq Ansari
3b32b9a766
Merge pull request #1240 from frappe/l10n_develop3 2025-09-09 14:27:02 +05:30
Shariq Ansari
ffd2452675 chore: Norwegian Bokmal translations 2025-09-08 23:35:30 +05:30
Shariq Ansari
b2949afd33
Merge pull request #1237 from frappe/l10n_develop3 2025-09-08 11:19:09 +05:30
Shariq Ansari
097c58b991 chore: Norwegian Bokmal translations 2025-09-07 23:04:40 +05:30
Shariq Ansari
64bf702b62 chore: Danish translations 2025-09-07 23:04:39 +05:30
Shariq Ansari
7e27e9f45e chore: Esperanto translations 2025-09-07 23:04:37 +05:30
Shariq Ansari
ee19b344ec chore: Croatian translations 2025-09-07 23:04:36 +05:30
Shariq Ansari
eb70553fea chore: Thai translations 2025-09-07 23:04:35 +05:30
Shariq Ansari
9e4d268b50 chore: Persian translations 2025-09-07 23:04:34 +05:30
Shariq Ansari
d92c25ab4e chore: Vietnamese translations 2025-09-07 23:04:33 +05:30
Shariq Ansari
9975be4ff7 chore: Chinese Simplified translations 2025-09-07 23:04:31 +05:30
Shariq Ansari
2442f6f2ad chore: Turkish translations 2025-09-07 23:04:30 +05:30
Shariq Ansari
e39a20f652 chore: Russian translations 2025-09-07 23:04:29 +05:30
Shariq Ansari
dcca47f3ca chore: Portuguese translations 2025-09-07 23:04:28 +05:30
Shariq Ansari
df8aaea374 chore: Dutch translations 2025-09-07 23:04:26 +05:30
Shariq Ansari
c3ac80afa8 chore: Hungarian translations 2025-09-07 23:04:25 +05:30
Shariq Ansari
8d59359ef5 chore: Czech translations 2025-09-07 23:04:24 +05:30
Shariq Ansari
53202f4a5b chore: Arabic translations 2025-09-07 23:04:23 +05:30
Shariq Ansari
792db27252 chore: Spanish translations 2025-09-07 23:04:22 +05:30
Shariq Ansari
c9bcbcf1d0 chore: French translations 2025-09-07 23:04:20 +05:30
Shariq Ansari
79a0c02f03 chore: German translations 2025-09-07 23:04:19 +05:30
Shariq Ansari
2a5dbfb75d chore: Serbian (Latin) translations 2025-09-07 23:04:18 +05:30
Shariq Ansari
b7443ff1bb chore: Bosnian translations 2025-09-07 23:04:17 +05:30
Shariq Ansari
5ee9d5787a chore: Indonesian translations 2025-09-07 23:04:15 +05:30
Shariq Ansari
426dc836ca chore: Portuguese, Brazilian translations 2025-09-07 23:04:14 +05:30
Shariq Ansari
d528710379 chore: Swedish translations 2025-09-07 23:04:13 +05:30
Shariq Ansari
0a4cfa6055 chore: Serbian (Cyrillic) translations 2025-09-07 23:04:12 +05:30
Shariq Ansari
1ca85157ab chore: Polish translations 2025-09-07 23:04:10 +05:30
Shariq Ansari
d8162a1dc4 chore: Italian translations 2025-09-07 23:04:09 +05:30
Shariq Ansari
9487edf05f
Merge pull request #1234 from shariquerik/org-fix 2025-09-07 19:25:19 +05:30
Shariq Ansari
30d95a6582 fix: remove unnecessary class from Button component in TaskModal and add click.stop to Notes dropdown 2025-09-07 18:56:31 +05:30
Shariq Ansari
24b580150a fix: add 'interactjs' to optimizeDeps include list in vite.config.js 2025-09-07 18:50:58 +05:30
Shariq Ansari
1b7af2096f fix: update organization logo handling and add beforeFieldChange functionality to rename organization 2025-09-07 18:50:43 +05:30
Shariq Ansari
843f844e2c
Merge pull request #1230 from frappe/l10n_develop3 2025-09-07 17:59:20 +05:30
Shariq Ansari
ed7d739291
Merge pull request #1231 from frappe/pot_develop_2025-09-07 2025-09-07 17:49:48 +05:30
frappe-pr-bot
591076bf27 chore: update POT file 2025-09-07 09:35:13 +00:00
Shariq Ansari
891d78c3b6 chore: Norwegian Bokmal translations 2025-09-06 22:31:01 +05:30
Shariq Ansari
4baee8351b chore: Norwegian Bokmal translations 2025-09-05 22:35:31 +05:30
Shariq Ansari
0653c2293c
Merge pull request #1225 from shariquerik/calendar-fixes 2025-09-05 19:13:54 +05:30
Shariq Ansari
509bdd08dd
Merge pull request #1224 from frappe/l10n_develop3 2025-09-05 16:16:59 +05:30
Shariq Ansari
93db75b835
Merge pull request #1226 from shariquerik/contact-fix 2025-09-05 15:45:13 +05:30
Shariq Ansari
af6970569f Revert "fix: add PrimaryDropdown and PrimaryDropdownItem components for enhanced dropdown functionality in forms"
This reverts commit 816bc700ede63c2e9d12f70cea1e90c26f11acc1.
2025-09-05 15:42:51 +05:30
Shariq Ansari
50708ebe32 fix: if contact email is updated it is updating previously opened contact 2025-09-05 15:34:36 +05:30
Shariq Ansari
816bc700ed fix: add PrimaryDropdown and PrimaryDropdownItem components for enhanced dropdown functionality in forms 2025-09-05 15:29:30 +05:30
Shariq Ansari
6e8228a82c fix: inject events resource into CalendarEventPanel for improved event handling 2025-09-05 12:24:46 +05:30
Shariq Ansari
54e4819c71 fix: prevent saving event if no changes were made 2025-09-05 12:06:14 +05:30
Shariq Ansari
f573db2fe0 fix: add isDialogOpen utility function and update keyboard shortcuts to respect dialog state 2025-09-05 11:56:24 +05:30
Shariq Ansari
a45c150a3d fix: format event times to HH:mm on update 2025-09-05 11:47:34 +05:30
Shariq Ansari
46a7a9c495 fix: refactor attendee input to use Combobox component for improved UX 2025-09-05 11:40:17 +05:30
Shariq Ansari
09ff459751 fix: remove unused daily header template from Calendar component 2025-09-04 23:00:06 +05:30
Shariq Ansari
1d249b8fff fix: disable create button when event data is not modified 2025-09-04 22:44:32 +05:30
Shariq Ansari
5eaf828758 fix: only show non converted leads 2025-09-04 22:37:34 +05:30
Shariq Ansari
0eb07f0242 fix: remove unused link reference fields from EventModal component 2025-09-04 22:32:05 +05:30
Shariq Ansari
023d949577 chore: Portuguese translations 2025-09-04 22:29:29 +05:30
Shariq Ansari
abec857dd2 fix: enable double-click to edit details in CalendarEventPanel component 2025-09-04 22:27:31 +05:30
Shariq Ansari
58914d7053 fix: remove conditional rendering for Calendar component when events are present 2025-09-04 22:23:53 +05:30
Shariq Ansari
c93909523d fix: update button visibility on hover in KanbanView component 2025-09-04 22:23:42 +05:30
Shariq Ansari
800f3f1453
Merge pull request #1220 from frappe/l10n_develop3 2025-09-04 17:51:30 +05:30
Shariq Ansari
9c1d0b3d56
Merge pull request #1221 from aftabshaikh-agkiya/fix/address-modal 2025-09-04 17:50:54 +05:30
Shariq Ansari
f9f405cc00
chore: removed commented code 2025-09-04 17:49:52 +05:30
Shariq Ansari
181439be1d
Merge pull request #748 from shariquerik/google-calendar 2025-09-04 13:34:48 +05:30
Shariq Ansari
1d2328ced1 build(deps): bump frappeui to 0.1.197 2025-09-04 13:23:36 +05:30
Shariq Ansari
b9b073601b build(deps): bump frappeui to 0.1.196 2025-09-04 13:12:12 +05:30
Shariq Ansari
feec676632 fix: change default size of Autocomplete component from 'md' to 'sm' 2025-09-04 11:57:38 +05:30
Shariq Ansari
2b0c43677e fix: add TimePicker component support for Time fieldtype in Grid and Field components 2025-09-03 23:09:18 +05:30
Shariq Ansari
c51ee63008 fix: update subtle variant classes in Autocomplete component for improved styling 2025-09-03 23:08:19 +05:30
Shariq Ansari
0cd527f6ef chore: Norwegian Bokmal translations 2025-09-03 21:49:47 +05:30
Shariq Ansari
fead8c3876 chore: Danish translations 2025-09-03 21:49:45 +05:30
Shariq Ansari
1e6270df44 chore: Esperanto translations 2025-09-03 21:49:43 +05:30
Shariq Ansari
7c9e9b954d chore: Croatian translations 2025-09-03 21:49:41 +05:30
Shariq Ansari
6b2a1e7ff1 chore: Thai translations 2025-09-03 21:49:39 +05:30
Shariq Ansari
4aa506985f chore: Persian translations 2025-09-03 21:49:37 +05:30
Shariq Ansari
496659af0a chore: Vietnamese translations 2025-09-03 21:49:35 +05:30
Shariq Ansari
9669b6d54c chore: Chinese Simplified translations 2025-09-03 21:49:33 +05:30
Shariq Ansari
d406f7345c chore: Turkish translations 2025-09-03 21:49:31 +05:30
Shariq Ansari
f838ef56a6 chore: Russian translations 2025-09-03 21:49:29 +05:30
Shariq Ansari
77c5cb40e9 chore: Portuguese translations 2025-09-03 21:49:28 +05:30
Shariq Ansari
0e1a4f0006 chore: Dutch translations 2025-09-03 21:49:25 +05:30
Shariq Ansari
c4b5c56fe4 chore: Hungarian translations 2025-09-03 21:49:24 +05:30
Shariq Ansari
9066ed0688 chore: Czech translations 2025-09-03 21:49:22 +05:30
Shariq Ansari
9a189aa586 chore: Arabic translations 2025-09-03 21:49:20 +05:30
Shariq Ansari
aa28206f57 chore: Spanish translations 2025-09-03 21:49:18 +05:30
Shariq Ansari
628be7cb7c chore: French translations 2025-09-03 21:49:16 +05:30
Shariq Ansari
b74f92c86e chore: German translations 2025-09-03 21:49:14 +05:30
Shariq Ansari
9190974293 chore: Serbian (Latin) translations 2025-09-03 21:49:12 +05:30
Shariq Ansari
ffae4b10b9 chore: Bosnian translations 2025-09-03 21:49:10 +05:30
Shariq Ansari
b64baa2390 chore: Indonesian translations 2025-09-03 21:49:09 +05:30
Shariq Ansari
87c4d38c77 chore: Portuguese, Brazilian translations 2025-09-03 21:49:07 +05:30
Shariq Ansari
bf32cbd3e8 chore: Swedish translations 2025-09-03 21:49:05 +05:30
Shariq Ansari
6d929d0e7e chore: Serbian (Cyrillic) translations 2025-09-03 21:49:03 +05:30
Shariq Ansari
df31d8820c chore: Polish translations 2025-09-03 21:49:01 +05:30
Shariq Ansari
4bd5e5a9cc chore: Italian translations 2025-09-03 21:48:59 +05:30
Shariq Ansari
f38775bbe5 fix: update EmailMultiSelect styles for better responsiveness and layout 2025-09-03 19:11:21 +05:30
Shariq Ansari
7a6caf2389 fix: update fetchEvent function to handle oldMode parameter and improve event duplication logic 2025-09-03 18:59:25 +05:30
Shariq Ansari
bbb2f8757e fix: remove Popover component and update type declarations 2025-09-03 18:42:21 +05:30
Shariq Ansari
1effb6bc58 fix: remove unused watch import from Tasks.vue 2025-09-03 18:38:12 +05:30
Shariq Ansari
20318d0d13 refactor: replace MultiSelectEmailInput and MultiSelectUserInput with EmailMultiSelect component
- Removed MultiSelectEmailInput.vue and MultiSelectUserInput.vue components.
- Introduced EmailMultiSelect.vue component for handling email selection.
- Updated EmailEditor.vue, AddExistingUserModal.vue, InviteUserPage.vue, and Users.vue to use EmailMultiSelect.
- Adjusted props and validation logic in the new EmailMultiSelect component.
- Removed unused Dropdown.vue component.
2025-09-03 18:30:49 +05:30
Shariq Ansari
610a5cd40b fix: update component imports and improve Dropdown properties in AudioPlayer and ViewBreadcrumbs 2025-09-03 17:02:09 +05:30
Shariq Ansari
6c30596dd1 fix: handle empty state for events 2025-09-03 16:27:04 +05:30
Shariq Ansari
5eddfbe9b3 fix: remove theme management from theme store and update UserDropdown to use useTheme composable from frappe-ui 2025-09-03 15:29:30 +05:30
Shariq Ansari
ed1c448fd7 fix: remove email templates routes from the router configuration 2025-09-03 13:37:44 +05:30
Aftab Shaikh
32993af090 fix: address creation not returning to organization modal 2025-09-03 13:08:26 +05:30
Shariq Ansari
346643bc6d fix: add ShortcutTooltip component and integrate it for keyboard shortcuts in CalendarEventPanel and Calendar pages 2025-09-03 13:05:54 +05:30
Shariq Ansari
f2ce3165dd fix: created keyboard shortcut composable to handle shortcut implementations 2025-09-03 13:05:54 +05:30
Shariq Ansari
11d1b3a67a fix: update duplicate event title logic 2025-09-03 13:05:54 +05:30
Shariq Ansari
74f6f65210 fix: enhance button tooltips and refactor button structure in CalendarEventPanel 2025-09-03 13:05:54 +05:30
Shariq Ansari
557dc1f94c fix: add keyboard shortcuts for event creation and management in Calendar components 2025-09-03 13:05:54 +05:30
Shariq Ansari
1e99192448 fix: refactor event handling and validation logic in CalendarEventPanel and EventModal components 2025-09-03 13:05:54 +05:30
Shariq Ansari
8031964d3d fix: added attendee, color, link in event modal and fixed existing bug 2025-09-03 13:05:54 +05:30
Shariq Ansari
52d99ebf20 fix: refactor Attendee component for improved search functionality and option selection 2025-09-03 13:04:37 +05:30
Shariq Ansari
da7ee0926f fix: refactor EventArea to improve event rendering and participant handling 2025-09-03 13:04:37 +05:30
Shariq Ansari
ae5a1ceae5 fix: use TimePicker from frappeui 2025-09-03 13:04:37 +05:30
Shariq Ansari
2503dea30f fix: update date formatting in DatePicker components and remove unused formatter imports 2025-09-03 13:04:37 +05:30
Shariq Ansari
92b79c2195 fix: reload event after editing event 2025-09-03 13:04:37 +05:30
Shariq Ansari
c69a468e35 fix: synchronize event updates and expose updateEvent method in CalendarEventPanel 2025-09-03 13:04:37 +05:30
Shariq Ansari
4b4b188827 fix: enhance TimePicker to support HH:MM:SS input and truncate seconds 2025-09-03 13:04:37 +05:30
Shariq Ansari
223cbf4020 fix: handle syncing of event 2025-09-03 13:04:37 +05:30
Shariq Ansari
0d1a4effdb refactor: enhance CalendarEventPanel layout with transition effects 2025-09-03 13:04:37 +05:30
Shariq Ansari
369d9fcd63 fix: update DateMonthYearPicker formatter to use currentMonthYear 2025-09-03 13:04:37 +05:30
Shariq Ansari
8af4a4ecf2 refactor: remove DateMonthYearPicker component and use it from frappe-ui 2025-09-03 13:04:37 +05:30
Shariq Ansari
b6a15ab96e fix: add 'Today' button to quickly reset calendar date 2025-09-03 13:04:37 +05:30
Shariq Ansari
0386df262e feat: refactor TimePicker and CalendarEventPanel for improved time selection and validation 2025-09-03 13:04:37 +05:30
Shariq Ansari
032b0d3723 fix: adjust pageLength for event resource 2025-09-03 13:04:37 +05:30
Shariq Ansari
4cb8789786 feat: integrate DateMonthYearPicker into Calendar for improved date selection 2025-09-03 13:04:36 +05:30
Shariq Ansari
957aa4e2e2 feat: add DateMonthYearPicker component for enhanced date selection 2025-09-03 13:04:36 +05:30
Shariq Ansari
65f11d7c8f feat: enhance attendee display with toggle for showing all participants 2025-09-03 13:04:36 +05:30
Shariq Ansari
2950e8c993 fix: enhance attendee list styling with max height and overflow 2025-09-03 13:04:36 +05:30
Shariq Ansari
9976b9617f feat: add Attendee component and integrate into CalendarEventPanel
- Introduced Attendee component for managing event participants.
- Updated CalendarEventPanel to include Attendee component for adding participants.
- Enhanced event creation and updating logic to handle event participants.
- Updated Calendar.vue to ensure participant contacts are created if missing.
2025-09-03 13:04:36 +05:30
Shariq Ansari
eada826503 fix: make timepicker working with custom options 2025-09-03 13:04:36 +05:30
Shariq Ansari
bff1b6156f feat: duplicate event from lead/deal events tab 2025-09-03 13:04:36 +05:30
Shariq Ansari
9cd6b142d7 fix: delete event from lead/deal 2025-09-03 13:04:36 +05:30
Shariq Ansari
ea644c22f1 feat: added events tab in lead/deal page
create & update events from lead/deal page
link events with lead or deal
2025-09-03 13:04:36 +05:30
Shariq Ansari
b6e8d83c3b fix: enhance event submission logic to show details after successful insert and update 2025-09-03 13:04:36 +05:30
Shariq Ansari
68ac2b80ff feat: keep event in sync and show discard changes option if dirty 2025-09-03 13:04:36 +05:30
Shariq Ansari
3f4601efa0 refactor: update event title logic and improve saveEvent function structure 2025-09-03 13:04:36 +05:30
Shariq Ansari
6ec2c1e805 fix: use single click instead of double click to open new event panel 2025-09-03 13:04:36 +05:30
Shariq Ansari
202ba3c856 chore: rearrange code 2025-09-03 13:04:36 +05:30
Shariq Ansari
aa7d9affdb feat: enhance event creation and updating logic in Calendar component 2025-09-03 13:04:36 +05:30
Shariq Ansari
10e3adfd18 refactor: remove CalendarEventDetails component and update CalendarEventPanel for improved event handling 2025-09-03 13:04:36 +05:30
Shariq Ansari
682e445288 refactor: remove redundant logic in updateEvent function in Calendar component 2025-09-03 13:04:36 +05:30
Shariq Ansari
38b838ec97 feat: add duplicate functionality to CalendarEventDetails and CalendarEventPanel components 2025-09-03 13:04:36 +05:30
Shariq Ansari
1cc972ea8b feat: improve event description display in CalendarEventDetails component 2025-09-03 13:04:36 +05:30
Shariq Ansari
f9f1c2a437 refactor: streamline event handling and improve onSuccess callbacks in Calendar 2025-09-03 13:04:36 +05:30
Shariq Ansari
1c432d8610 feat: add CalendarEventDetails component and integrate it into Calendar for event management 2025-09-03 13:04:36 +05:30
Shariq Ansari
55c61cbd80 feat: enhance CalendarEventPanel and TimePicker with improved date and time selection UI 2025-09-03 13:04:36 +05:30
Shariq Ansari
27c54461de feat: refactor color selection in CalendarEventPanel to use a computed colors array 2025-09-03 13:04:36 +05:30
Shariq Ansari
2162ed588a fix: reset active event before showing event panel in Calendar 2025-09-03 13:04:36 +05:30
Shariq Ansari
593cf4ab5a feat: enhance CalendarEventPanel with color selection and improve event handling in Calendar 2025-09-03 13:04:36 +05:30
Shariq Ansari
b73bca354a fix: update event handling in CalendarEventPanel and adjust button action in Calendar 2025-09-03 13:04:36 +05:30
Shariq Ansari
60b5665981 feat: add CalendarEventPanel and TimePicker components for event management in Calendar 2025-09-03 13:04:36 +05:30
Shariq Ansari
e109b59a55 refactor: update component declarations and improve Calendar daily header styling 2025-09-03 13:04:36 +05:30
Shariq Ansari
09c48d76ce fix: comment out TimePicker and ColorPicker components in CalendarModal 2025-09-03 13:04:13 +05:30
Shariq Ansari
f73fbcafdd fix: validate time and date before setting 2025-09-03 13:04:13 +05:30
Shariq Ansari
02da09633d fix: converted snake_case to camelCase 2025-09-03 13:04:13 +05:30
Shariq Ansari
32d8dcf80a fix: reload events on create, update & delete 2025-09-03 13:04:13 +05:30
Shariq Ansari
d520586e87 fix: added color picker 2025-09-03 13:04:13 +05:30
Shariq Ansari
28217968e1 fix: added eventType in modal 2025-09-03 13:04:13 +05:30
Shariq Ansari
21bd24f614 fix: made title required 2025-09-03 13:04:12 +05:30
Shariq Ansari
8f8235e9d9 fix: edit and add event modal with title, description, timepicker & datepicker 2025-09-03 13:02:11 +05:30
Shariq Ansari
85b4f63bc7 fix: get from to time in 24 hour format 2025-09-03 13:02:11 +05:30
Shariq Ansari
743ffc0cf2 fix: show new/edit event modal 2025-09-03 13:02:11 +05:30
Shariq Ansari
7ea8c60e5d fix: confirm before deleting event 2025-09-03 13:02:11 +05:30
Shariq Ansari
19e699ea54 fix: calculate from & to date and create/update with more details 2025-09-03 13:02:11 +05:30
Shariq Ansari
fa105079d7 fix: get more event details and cache request 2025-09-03 13:02:11 +05:30
Shariq Ansari
8d79956f3c fix: added daily header title slot to fix margin 2025-09-03 13:02:11 +05:30
Shariq Ansari
bfba0258ba fix: only get logged in users events 2025-09-03 13:02:11 +05:30
Shariq Ansari
15e8bf06fd fix: removed static events 2025-09-03 13:02:11 +05:30
Shariq Ansari
0f0becd096 feat: Calendar View 2025-09-03 13:02:11 +05:30
Shariq Ansari
9040d50c3c
Merge pull request #1192 from patleYashpal/fix-popup-deletion 2025-09-03 12:46:36 +05:30
Shariq Ansari
899481d752
chore: indentation fix 2025-09-03 12:42:19 +05:30
Shariq Ansari
8a1ebeb52d
chore: indentation fix 2025-09-03 12:42:08 +05:30
Shariq Ansari
4f08cb95e8
Merge pull request #1198 from anup-dh/anup-dh-patch-1 2025-09-03 12:09:52 +05:30
Shariq Ansari
736c956ec2
Merge pull request #1206 from pratikb64/feat/assignment-rule 2025-09-03 12:08:36 +05:30
Shariq Ansari
eb787b2d6f
Merge pull request #1125 from naaa760/bulk-delete-leads 2025-09-03 12:08:21 +05:30
Shariq Ansari
8d0d234ac1
chore: removed comment 2025-09-03 12:06:21 +05:30
Shariq Ansari
7fda0db51b
chore: removed comment 2025-09-03 12:06:08 +05:30
Shariq Ansari
a1d4853d1c
Merge pull request #1202 from frappe/l10n_develop3 2025-09-03 11:55:08 +05:30
Shariq Ansari
6c41a4d0a0
Merge pull request #1204 from frappe/pot_develop_2025-08-31 2025-09-03 11:55:01 +05:30
Shariq Ansari
cedafc82dc
Discard changes to yarn.lock 2025-09-03 11:47:04 +05:30
Shariq Ansari
443070886e
fix: delete yarn.lock 2025-09-03 11:46:06 +05:30
Pratik Badhe
3d6111627b fix: handle notification deletion 2025-09-03 05:24:45 +00:00
Shariq Ansari
33a7f50fed chore: Norwegian Bokmal translations 2025-09-02 21:52:21 +05:30
Shariq Ansari
6ca2f83c05 chore: Danish translations 2025-09-02 21:52:20 +05:30
Shariq Ansari
c4f76cea6c chore: Hungarian translations 2025-09-02 21:52:18 +05:30
Pratik Badhe
26d49d7ae0 Merge remote-tracking branch 'upstream/develop' into bulk-delete-leads 2025-09-02 05:26:14 +00:00
Shariq Ansari
22369825e8 chore: Norwegian Bokmal translations 2025-09-01 21:50:25 +05:30
Shariq Ansari
27b286c6de chore: Hungarian translations 2025-09-01 21:50:14 +05:30
Pratik Badhe
0c5684905f feat: add assignment rule 2025-09-01 06:22:56 +00:00
Shariq Ansari
3fb888561b chore: Norwegian Bokmal translations 2025-08-31 21:39:41 +05:30
frappe-pr-bot
f2f0a4ba2b chore: update POT file 2025-08-31 09:35:10 +00:00
Shariq Ansari
50bf6be95f chore: Norwegian Bokmal translations 2025-08-29 20:11:45 +05:30
anup-dh
486a06baf0
Added support for outgoing whatsapp messages from other apps
made changes so that:
1. whatsapp message is created (app: frappe_whatsapp) even if no phone number match is found in CRM Deal & CRM Lead.
2. Also assigns reference doctype and name for Outgoing whatsappe messages which are not sent via CRM app.
3. added a "if doctype and" check to make sure notify_agent does not fail whatsapp message creation if whatsapp message is being created as per step 1.
2025-08-29 17:37:18 +05:45
Shariq Ansari
214b91a64b
Merge pull request #1196 from frappe/l10n_develop3
chore: sync translations from crowdin
2025-08-29 13:13:58 +05:30
Shariq Ansari
84aacb0717 chore: Norwegian Bokmal translations 2025-08-28 19:17:13 +05:30
Shariq Ansari
4c1a4f956e chore: Danish translations 2025-08-28 19:17:11 +05:30
Shariq Ansari
9f1d75817e chore: Swedish translations 2025-08-28 19:17:05 +05:30
Shariq Ansari
3b61c0ba8f
Merge pull request #1191 from frappe/l10n_develop3 2025-08-28 12:07:06 +05:30
Shariq Ansari
1706c05f93 chore: Norwegian Bokmal translations 2025-08-27 19:17:35 +05:30
Shariq Ansari
f3bd3de81c chore: Danish translations 2025-08-27 19:17:33 +05:30
Shariq Ansari
91187f4db0 chore: Croatian translations 2025-08-27 19:17:32 +05:30
Shariq Ansari
0d5ad337f6 chore: Thai translations 2025-08-27 19:17:30 +05:30
Shariq Ansari
d3fa9cf98a chore: Persian translations 2025-08-27 19:17:28 +05:30
Shariq Ansari
2251d46711 chore: Turkish translations 2025-08-27 19:17:24 +05:30
Shariq Ansari
962418c37d chore: Spanish translations 2025-08-27 19:17:15 +05:30
Shariq Ansari
1d633eabdc chore: German translations 2025-08-27 19:17:12 +05:30
Shariq Ansari
5a0e68b0e8 chore: Bosnian translations 2025-08-27 19:17:09 +05:30
Shariq Ansari
76f9843251 chore: Portuguese, Brazilian translations 2025-08-27 19:17:05 +05:30
Shariq Ansari
1a6a1854fc chore: Polish translations 2025-08-27 19:17:00 +05:30
Yashpal Patle
b55bf0918f fixed popup deletion 2025-08-26 18:18:39 +00:00
Shariq Ansari
5f9fb5a68f chore: Esperanto translations 2025-08-26 19:20:55 +05:30
Shariq Ansari
469177182a chore: Croatian translations 2025-08-26 19:20:54 +05:30
Shariq Ansari
a72e580e1f chore: Thai translations 2025-08-26 19:20:52 +05:30
Shariq Ansari
9c88ba879d chore: Persian translations 2025-08-26 19:20:50 +05:30
Shariq Ansari
9d45dea8b3 chore: Vietnamese translations 2025-08-26 19:20:48 +05:30
Shariq Ansari
f1732780cc chore: Chinese Simplified translations 2025-08-26 19:20:47 +05:30
Shariq Ansari
ae70eee7e0 chore: Turkish translations 2025-08-26 19:20:45 +05:30
Shariq Ansari
03277e240e chore: Russian translations 2025-08-26 19:20:43 +05:30
Shariq Ansari
510f7301fd chore: Portuguese translations 2025-08-26 19:20:41 +05:30
Shariq Ansari
32f42a4009 chore: Dutch translations 2025-08-26 19:20:40 +05:30
Shariq Ansari
267016cff9 chore: Hungarian translations 2025-08-26 19:20:38 +05:30
Shariq Ansari
fc02800a35 chore: Czech translations 2025-08-26 19:20:37 +05:30
Shariq Ansari
b33f09c76b chore: Arabic translations 2025-08-26 19:20:35 +05:30
Shariq Ansari
2d68d1d29a chore: Spanish translations 2025-08-26 19:20:33 +05:30
Shariq Ansari
ec14798d9c chore: French translations 2025-08-26 19:20:31 +05:30
Shariq Ansari
a2e438ceea chore: German translations 2025-08-26 19:20:30 +05:30
Shariq Ansari
e606e56ce7 chore: Serbian (Latin) translations 2025-08-26 19:20:28 +05:30
Shariq Ansari
a8a75f6e97 chore: Bosnian translations 2025-08-26 19:20:27 +05:30
Shariq Ansari
35e07b321c chore: Indonesian translations 2025-08-26 19:20:25 +05:30
Shariq Ansari
28ce5762f8 chore: Portuguese, Brazilian translations 2025-08-26 19:20:24 +05:30
Shariq Ansari
97367afed1 chore: Swedish translations 2025-08-26 19:20:22 +05:30
Shariq Ansari
d1b229c459 chore: Serbian (Cyrillic) translations 2025-08-26 19:20:20 +05:30
Shariq Ansari
335f73a0e6 chore: Polish translations 2025-08-26 19:20:19 +05:30
Shariq Ansari
ef38c4a882 chore: Italian translations 2025-08-26 19:20:17 +05:30
Shariq Ansari
132b631a36
Merge pull request #1182 from shariquerik/kanban-public-save 2025-08-26 12:25:53 +05:30
Shariq Ansari
d1ccbc6541
Merge pull request #1185 from pratikb64/fix/deal-read-only-fields 2025-08-26 12:23:59 +05:30
Pratik Badhe
7807c12114 fix: remove "read only" flag for primary email, mobile & phone no 2025-08-26 06:46:54 +00:00
Shariq Ansari
779032be50
Merge pull request #1179 from frappe/l10n_develop3 2025-08-26 12:12:10 +05:30
Shariq Ansari
e78d08a6d4
Merge pull request #1178 from frappe/pot_develop_2025-08-24 2025-08-26 12:11:56 +05:30
Shariq Ansari
4301cd4806 fix: do not allow saving public view kanban changes for non managers 2025-08-26 12:09:26 +05:30
Shariq Ansari
5ab41a5ebb chore: Indonesian translations 2025-08-24 19:03:52 +05:30
Shariq Ansari
e7c09b6f2f chore: Italian translations 2025-08-24 19:03:48 +05:30
frappe-pr-bot
bf63bd54df chore: update POT file 2025-08-24 09:35:30 +00:00
Shariq Ansari
f486a664ca
Merge pull request #1173 from shariquerik/dropdown-item-fix-1 2025-08-21 11:32:45 +05:30
Shariq Ansari
41118eda97 fix: update button state to use document properties 2025-08-21 11:27:24 +05:30
Shariq Ansari
cd96171a4c fix: reorder idx if grid row is reordered 2025-08-21 11:27:12 +05:30
Shariq Ansari
83c1abd707
Merge pull request #1133 from wasim3357/develop 2025-08-20 14:34:13 +05:30
Shariq Ansari
574d3ec70e
Merge pull request #1167 from frappe/l10n_develop3 2025-08-20 13:20:20 +05:30
Shariq Ansari
18c1bb1ad4
Merge pull request #1169 from shariquerik/dropdown-item-fix 2025-08-20 13:14:29 +05:30
Shariq Ansari
8ea94765ce fix: dropdown item is not updating 2025-08-20 12:46:30 +05:30
Shariq Ansari
8d7a5f22fd chore: Esperanto translations 2025-08-19 18:10:04 +05:30
Shariq Ansari
a31ff74999 chore: Croatian translations 2025-08-19 18:10:02 +05:30
Shariq Ansari
c60979f1ab chore: Thai translations 2025-08-19 18:10:00 +05:30
Shariq Ansari
b5739efbbc chore: Persian translations 2025-08-19 18:09:58 +05:30
Shariq Ansari
96e014e6ca chore: Vietnamese translations 2025-08-19 18:09:57 +05:30
Shariq Ansari
d0020b8a90 chore: Chinese Simplified translations 2025-08-19 18:09:55 +05:30
Shariq Ansari
f32b86e7e7 chore: Turkish translations 2025-08-19 18:09:54 +05:30
Shariq Ansari
7cab5d9815 chore: Russian translations 2025-08-19 18:09:52 +05:30
Shariq Ansari
a6a22aa393 chore: Portuguese translations 2025-08-19 18:09:51 +05:30
Shariq Ansari
fd098a0766 chore: Dutch translations 2025-08-19 18:09:49 +05:30
Shariq Ansari
36326526d5 chore: Hungarian translations 2025-08-19 18:09:48 +05:30
Shariq Ansari
f20a903e78 chore: Czech translations 2025-08-19 18:09:47 +05:30
Shariq Ansari
0f0564066d chore: Arabic translations 2025-08-19 18:09:45 +05:30
Shariq Ansari
7b6a4d3b30 chore: Spanish translations 2025-08-19 18:09:44 +05:30
Shariq Ansari
175c450559 chore: French translations 2025-08-19 18:09:42 +05:30
Shariq Ansari
5b79141dd5 chore: German translations 2025-08-19 18:09:41 +05:30
Shariq Ansari
97de6543c2 chore: Serbian (Latin) translations 2025-08-19 18:09:40 +05:30
Shariq Ansari
bc424265e0 chore: Bosnian translations 2025-08-19 18:09:38 +05:30
Shariq Ansari
15d057b63c chore: Indonesian translations 2025-08-19 18:09:37 +05:30
Shariq Ansari
27a121c270 chore: Portuguese, Brazilian translations 2025-08-19 18:09:35 +05:30
Shariq Ansari
d99a4bc3ff chore: Swedish translations 2025-08-19 18:09:34 +05:30
Shariq Ansari
d6251adae3 chore: Serbian (Cyrillic) translations 2025-08-19 18:09:32 +05:30
Shariq Ansari
388d3e9369 chore: Polish translations 2025-08-19 18:09:31 +05:30
Shariq Ansari
f8f0800f97 chore: Italian translations 2025-08-19 18:09:29 +05:30
Shariq Ansari
9b9d87757c
Merge pull request #1164 from shariquerik/fixes-6 2025-08-19 13:37:29 +05:30
Shariq Ansari
247a7c4da6 fix: remove read-only attribute from TwiML SID field 2025-08-19 13:36:38 +05:30
Shariq Ansari
f2d87fa801 fix: add immediate execution to watch for assignees updates 2025-08-19 13:33:48 +05:30
Shariq Ansari
e7534c9b15
Merge pull request #1161 from shariquerik/fixes-5 2025-08-19 12:26:32 +05:30
Shariq Ansari
edd0ec5f68 fix: update Dropdown styling in SLASection component 2025-08-19 12:21:30 +05:30
Shariq Ansari
a76bd2cab2 fix: align action buttons in GridFieldsEditorModal 2025-08-19 11:56:24 +05:30
Shariq Ansari
25d9d562e6 fix: convert to deal modals's convert button 2025-08-19 11:53:28 +05:30
Shariq Ansari
e8c331dfff
Merge pull request #1158 from shariquerik/twilio-fix-1 2025-08-19 11:12:30 +05:30
Shariq Ansari
afa96c330b fix: reject button is rotated 2025-08-19 11:11:50 +05:30
Shariq Ansari
4992cdda74
Merge pull request #1155 from shariquerik/dashboard-cache-fix 2025-08-19 10:47:17 +05:30
Shariq Ansari
c2a1a1b1d2 fix: remove unnecessary cache from dashboardItems resource 2025-08-19 10:46:31 +05:30
Shariq Ansari
89cce5160c
Merge pull request #1152 from shariquerik/fixes-4 2025-08-19 02:18:51 +05:30
Shariq Ansari
5f0bb46bf4 fix: prevent adding a column with undefined value in ColumnSettings 2025-08-19 01:51:57 +05:30
Shariq Ansari
f4551a92c5 refactor: note/task modal 2025-08-19 01:28:57 +05:30
Shariq Ansari
e9c197f46e fix: minor fix 2025-08-19 01:18:34 +05:30
Shariq Ansari
3a756630f3 fix: grid settings/edit-row button alignment 2025-08-19 00:59:24 +05:30
Shariq Ansari
a77bfd2aca refactor: update layout structure for CRM Deal-Data Fields to show products table 2025-08-19 00:58:52 +05:30
Shariq Ansari
1cebc1fed8 fix: ensure reactive access to document title in Lead component 2025-08-19 00:40:34 +05:30
Shariq Ansari
1a90876500 refactor: improve layout and structure of quick filter components 2025-08-19 00:30:30 +05:30
Shariq Ansari
c4065b95b8 patch: create default loast reasons 2025-08-19 00:03:52 +05:30
Shariq Ansari
1a74d6a280
Merge pull request #1130 from frappe/pot_develop_2025-08-10 2025-08-18 22:51:35 +05:30
Shariq Ansari
0523920fd0
Merge branch 'develop' into pot_develop_2025-08-10 2025-08-18 22:50:51 +05:30
Shariq Ansari
a8ae2e551e
Merge pull request #1129 from frappe/l10n_develop3 2025-08-18 22:48:41 +05:30
Shariq Ansari
aa0df7be79
Merge pull request #1142 from frappe/pot_develop_2025-08-17 2025-08-18 22:48:04 +05:30
Shariq Ansari
49ddcda2b6
Merge pull request #1145 from shariquerik/frappeui-update-1 2025-08-18 22:42:03 +05:30
Shariq Ansari
d173d5584a
Merge pull request #1144 from shariquerik/helpdesk-integration 2025-08-18 22:41:21 +05:30
Shariq Ansari
1679a67dc6 build(deps): bump frappeui to 0.1.189 2025-08-18 22:36:31 +05:30
Shariq Ansari
31163a1b2e
Merge branch 'develop' into helpdesk-integration 2025-08-18 22:20:14 +05:30
Shariq Ansari
5f32e46759 feat: add customer creation and invitation functionality in Helpdesk CRM 2025-08-18 22:17:58 +05:30
Shariq Ansari
91bdb02867
Merge pull request #1143 from shariquerik/fixes-3 2025-08-18 21:54:33 +05:30
Shariq Ansari
f8aa6cab78 fix: update ordering in deals by territory and salesperson queries 2025-08-18 17:57:10 +05:30
Shariq Ansari
8a62ff38af feat: implement validation and script creation for Helpdesk CRM settings 2025-08-18 17:51:14 +05:30
Shariq Ansari
8350752f56 feat: add Helpdesk icon and settings page 2025-08-18 17:35:19 +05:30
Shariq Ansari
a182bee57f feat: add Helpdesk CRM Settings doctype 2025-08-18 17:34:50 +05:30
Shariq Ansari
c5a8df19ae refactor: update tooltip bindings to use translation function and improve dropdown actions 2025-08-18 16:05:07 +05:30
Shariq Ansari
38b6674cc1 refactor: replace NestedPopover with Popover component across multiple files 2025-08-18 15:02:05 +05:30
frappe-pr-bot
73b2c36bbc chore: update POT file 2025-08-17 09:36:55 +00:00
Shariq Ansari
672c5eb733 refactor: Button components across multiple files to use icon/left-icon/right-icon prop 2025-08-16 00:12:12 +05:30
Shariq Ansari
948ce99482 fix: show dashboard to all 2025-08-15 20:27:57 +05:30
Shariq Ansari
3791e2ae70 fix: lead/deal status dropdown is not renderring 2025-08-15 20:24:44 +05:30
Shariq Ansari
68d1172b8f fix: add toast import to CurrencySettings component 2025-08-15 19:58:01 +05:30
Shariq Ansari
c94e61bfce fix: adjust UserDropdown padding in AppSidebar 2025-08-15 19:57:10 +05:30
Shariq Ansari
8b557a5963 fix: doc was not associated with value 2025-08-15 19:56:34 +05:30
Shariq Ansari
d4f99a411c chore: Persian translations 2025-08-12 16:52:02 +05:30
wasim3357
ea2e44a2be
fix(Org Modal): Setting loading false in case of Validation Error
In this case user can add the details and save the form again instead of refreshing and then trying again for fresh.
2025-08-11 17:42:38 +05:30
Shariq Ansari
4884ca0bd6 chore: Persian translations 2025-08-11 16:09:13 +05:30
Shariq Ansari
2a7c9ef9e8 chore: Italian translations 2025-08-11 16:08:56 +05:30
Shariq Ansari
cb3f67f231 chore: Italian translations 2025-08-10 16:08:37 +05:30
frappe-pr-bot
00e3bd12cc chore: update POT file 2025-08-10 09:37:28 +00:00
Shariq Ansari
d539bc075f chore: German translations 2025-08-09 15:35:45 +05:30
Shariq Ansari
818fd6fcdd chore: Italian translations 2025-08-09 15:35:44 +05:30
Shariq Ansari
5dc3a364a4
Merge pull request #1126 from frappe/l10n_develop3 2025-08-08 16:59:37 +05:30
Shariq Ansari
840eb664ce chore: Italian translations 2025-08-08 15:37:59 +05:30
naaa760
51823d1b88 Added input validation
Added document existence checks
Added reference field validation
Changed None to empty strings for reference fields
2025-08-08 14:12:36 +05:30
Shariq Ansari
8e0536ee11
Merge pull request #1121 from pratikb64/fix/create-quotation 2025-08-08 14:05:17 +05:30
Shariq Ansari
5648e5eb77
Merge pull request #1116 from frappe/l10n_develop3 2025-08-08 13:57:55 +05:30
Pratik Badhe
940e8d24c7 fix: create quotation 2025-08-08 08:22:33 +00:00
Shariq Ansari
4813a861a6 chore: Serbian (Latin) translations 2025-08-07 15:37:29 +05:30
Shariq Ansari
afb30a256e chore: Serbian (Cyrillic) translations 2025-08-07 15:37:28 +05:30
Shariq Ansari
499888b4a7
Merge pull request #1112 from frappe/l10n_develop3 2025-08-06 12:42:22 +05:30
Shariq Ansari
227359da62 chore: Croatian translations 2025-08-05 14:47:19 +05:30
Shariq Ansari
022b14c830 chore: Bosnian translations 2025-08-05 14:47:01 +05:30
Shariq Ansari
58f970c6b1 chore: Swedish translations 2025-08-05 14:46:57 +05:30
Shariq Ansari
d83ce2f276 chore: Esperanto translations 2025-08-04 14:05:04 +05:30
Shariq Ansari
0c8f36bc36 chore: Croatian translations 2025-08-04 14:05:03 +05:30
Shariq Ansari
1286ecfc8f chore: Thai translations 2025-08-04 14:05:01 +05:30
Shariq Ansari
24ebe94730 chore: Persian translations 2025-08-04 14:05:00 +05:30
Shariq Ansari
90b0e0d7b6 chore: Vietnamese translations 2025-08-04 14:04:58 +05:30
Shariq Ansari
ebd115c129 chore: Chinese Simplified translations 2025-08-04 14:04:57 +05:30
Shariq Ansari
5f544416ef chore: Turkish translations 2025-08-04 14:04:56 +05:30
Shariq Ansari
5a7a7a7257 chore: Russian translations 2025-08-04 14:04:54 +05:30
Shariq Ansari
8e8bf4ed5e chore: Portuguese translations 2025-08-04 14:04:52 +05:30
Shariq Ansari
7244f69c7f chore: Dutch translations 2025-08-04 14:04:51 +05:30
Shariq Ansari
d5b992d736 chore: Hungarian translations 2025-08-04 14:04:49 +05:30
Shariq Ansari
38cb777458 chore: Czech translations 2025-08-04 14:04:48 +05:30
Shariq Ansari
1a569d45de chore: Arabic translations 2025-08-04 14:04:46 +05:30
Shariq Ansari
93a710f8c5 chore: Spanish translations 2025-08-04 14:04:45 +05:30
Shariq Ansari
5414bbb190 chore: French translations 2025-08-04 14:04:43 +05:30
Shariq Ansari
c70aac4f31 chore: German translations 2025-08-04 14:04:42 +05:30
Shariq Ansari
9471966bee chore: Serbian (Latin) translations 2025-08-04 14:04:40 +05:30
Shariq Ansari
055a39cc0d chore: Bosnian translations 2025-08-04 14:04:39 +05:30
Shariq Ansari
4f075d4b23 chore: Indonesian translations 2025-08-04 14:04:37 +05:30
Shariq Ansari
526c43c655 chore: Portuguese, Brazilian translations 2025-08-04 14:04:36 +05:30
Shariq Ansari
084b446ae1 chore: Swedish translations 2025-08-04 14:04:35 +05:30
Shariq Ansari
de9c04ff18 chore: Serbian (Cyrillic) translations 2025-08-04 14:04:33 +05:30
Shariq Ansari
2fb09126c0 chore: Polish translations 2025-08-04 14:04:32 +05:30
Shariq Ansari
8944295474 chore: Italian translations 2025-08-04 14:04:31 +05:30
Shariq Ansari
85348188d2
Merge pull request #1108 from frappe/pot_develop_2025-08-03 2025-08-04 12:33:25 +05:30
Shariq Ansari
a68b405c61
Merge pull request #1104 from shariquerik/assign-to-refactor 2025-08-04 12:33:02 +05:30
Shariq Ansari
2a18a556bf refactor: update Activities component for improved z-index layering 2025-08-04 12:30:48 +05:30
frappe-pr-bot
fa14d4ad15 chore: update POT file 2025-08-03 09:38:21 +00:00
Shariq Ansari
44deb5878c
Merge pull request #1103 from frappe/l10n_develop3
chore: sync translations from crowdin
2025-08-03 13:59:40 +05:30
Shariq Ansari
2601c1d059 chore: Persian translations 2025-08-03 13:43:25 +05:30
Shariq Ansari
7e51d96379 chore: Indonesian translations 2025-08-03 13:43:12 +05:30
Shariq Ansari
4c1eaf507d refactor: update z-index values for activity components for better layering 2025-08-01 17:56:07 +05:30
Shariq Ansari
76149b0c79 refactor: update Activities component to scroll on success 2025-08-01 17:44:35 +05:30
Shariq Ansari
564d2b1ac5 refactor: update AssignTo component to use correct doctype for CRM Deal 2025-08-01 17:37:02 +05:30
Shariq Ansari
faef5cb866 refactor: update AssignTo component to use docname prop and streamline assignment logic 2025-08-01 16:56:06 +05:30
Shariq Ansari
3ed2c4812a refactor: do not update modified field 2025-08-01 16:52:51 +05:30
Shariq Ansari
4c53dd6ea3 chore: Persian translations 2025-08-01 13:09:10 +05:30
Shariq Ansari
5010cccc71 refactor: replace json.loads with frappe.parse_json for assignees in remove_assignments function 2025-08-01 13:03:14 +05:30
Shariq Ansari
aeb3f150c5 refactor: assignment modal for bulk assign 2025-08-01 12:54:16 +05:30
Shariq Ansari
995f356419 refactor: Assign to as popover instead of dialog 2025-08-01 12:50:22 +05:30
Shariq Ansari
c64dcb43b4
Merge pull request #1095 from frappe/l10n_develop3 2025-07-31 16:38:53 +05:30
Shariq Ansari
7dafba9fc3
Merge pull request #1100 from shariquerik/bug-fix 2025-07-31 16:32:03 +05:30
Shariq Ansari
abc501825a fix: update delete button click handler in Deal component 2025-07-31 16:30:25 +05:30
Shariq Ansari
3ad2a56efb
Merge pull request #1094 from C-L-STARK/patch-1 2025-07-31 16:28:38 +05:30
Shariq Ansari
c53e486bf0 fix: update init scripts for consistent Redis configuration and branch usage 2025-07-31 16:02:00 +05:30
Shariq Ansari
819a669922 refactor: simplify AssignmentModal component by streamlining dialog options and enhancing assignee management 2025-07-31 13:32:31 +05:30
Shariq Ansari
d852fe1e9f
Merge pull request #1096 from shariquerik/refactor-2 2025-07-30 18:13:41 +05:30
Shariq Ansari
d431d5b4b1 refactor: remove unused get_lead function and related imports from api.py 2025-07-30 17:55:47 +05:30
Shariq Ansari
ba99d14f68 refactor: clean up unused variables and streamline tab management in Deal, Lead, and MobileLead components 2025-07-30 17:50:16 +05:30
Shariq Ansari
7e42599b49 refactor: update mobile lead/deal components 2025-07-30 17:31:22 +05:30
Shariq Ansari
c38c190d42 fix: update docname references to use dealId and leadId in Deal and Lead components 2025-07-30 16:43:40 +05:30
Shariq Ansari
6e8d869afb fix: update whatsappMessages auto property based on whatsappEnabled state 2025-07-30 16:24:19 +05:30
Shariq Ansari
63d6062673 refactor: update button icon rendering in AttachmentArea component 2025-07-30 16:12:21 +05:30
Shariq Ansari
af830b8782 refactor: use doc in activity & child components 2025-07-30 16:11:49 +05:30
Shariq Ansari
0605cf5fd0 refactor: updateField & deleteDeal/Lead 2025-07-30 15:16:13 +05:30
Shariq Ansari
4acb4dd3a7 fix: remount on route change with param and hash change 2025-07-30 15:13:38 +05:30
Shariq Ansari
72c31b9f21 chore: Croatian translations 2025-07-30 13:11:43 +05:30
Shariq Ansari
f2b1c24d19 chore: Serbian (Latin) translations 2025-07-30 13:11:28 +05:30
Shariq Ansari
f86bb0ada2 chore: Bosnian translations 2025-07-30 13:11:27 +05:30
Shariq Ansari
ec4866f39a chore: Indonesian translations 2025-07-30 13:11:26 +05:30
Shariq Ansari
7961b614f1 chore: Swedish translations 2025-07-30 13:11:24 +05:30
Shariq Ansari
901d84d070 chore: Serbian (Cyrillic) translations 2025-07-30 13:11:22 +05:30
Shariq Ansari
0144bc109a fix: use document.doc instead of lead.data/deal.data 2025-07-30 12:56:27 +05:30
Shariq Ansari
ca5d82f5be fix: handle errors when creating document resources 2025-07-30 12:50:35 +05:30
C.L.STARK
b6a6152a49
Update init.sh
Fixed: docker setup error in crm-frappe container.
2025-07-30 05:11:40 +08:00
Shariq Ansari
5e19a83f8a
Merge pull request #1090 from frappe/l10n_develop3 2025-07-29 16:10:10 +05:30
Shariq Ansari
cd30e9d533
Merge pull request #1091 from shariquerik/modified-error 2025-07-29 14:13:59 +05:30
Shariq Ansari
ea0011771b fix: reload doc after sending email 2025-07-29 14:08:11 +05:30
Shariq Ansari
94b0077b2a chore: Esperanto translations 2025-07-29 12:32:06 +05:30
Shariq Ansari
ea815d0147 chore: Croatian translations 2025-07-29 12:32:04 +05:30
Shariq Ansari
0ae048d396 chore: Thai translations 2025-07-29 12:32:03 +05:30
Shariq Ansari
972558396e chore: Persian translations 2025-07-29 12:32:02 +05:30
Shariq Ansari
c218241e80 chore: Vietnamese translations 2025-07-29 12:32:00 +05:30
Shariq Ansari
e616e69aa4 chore: Chinese Simplified translations 2025-07-29 12:31:59 +05:30
Shariq Ansari
2627471b23 chore: Turkish translations 2025-07-29 12:31:58 +05:30
Shariq Ansari
a2c42ee5a7 chore: Russian translations 2025-07-29 12:31:56 +05:30
Shariq Ansari
8d89caeba7 chore: Portuguese translations 2025-07-29 12:31:55 +05:30
Shariq Ansari
b0393b532c chore: Dutch translations 2025-07-29 12:31:54 +05:30
Shariq Ansari
2ea875f2cb chore: Hungarian translations 2025-07-29 12:31:53 +05:30
Shariq Ansari
d1d2900847 chore: Czech translations 2025-07-29 12:31:51 +05:30
Shariq Ansari
98d851d76d chore: Arabic translations 2025-07-29 12:31:50 +05:30
Shariq Ansari
30fdc1db4c chore: Spanish translations 2025-07-29 12:31:49 +05:30
Shariq Ansari
12df15154d chore: French translations 2025-07-29 12:31:47 +05:30
Shariq Ansari
0bf6c01f91 chore: German translations 2025-07-29 12:31:46 +05:30
Shariq Ansari
497263f367 chore: Serbian (Latin) translations 2025-07-29 12:31:44 +05:30
Shariq Ansari
cd458d6d22 chore: Bosnian translations 2025-07-29 12:31:43 +05:30
Shariq Ansari
a2b55166ed chore: Indonesian translations 2025-07-29 12:31:41 +05:30
Shariq Ansari
570d31b6d1 chore: Portuguese, Brazilian translations 2025-07-29 12:31:40 +05:30
Shariq Ansari
2483dd6828 chore: Swedish translations 2025-07-29 12:31:38 +05:30
Shariq Ansari
1adef98c57 chore: Serbian (Cyrillic) translations 2025-07-29 12:31:37 +05:30
Shariq Ansari
dfd3c8f2bf chore: Polish translations 2025-07-29 12:31:36 +05:30
Shariq Ansari
015c592978 chore: Italian translations 2025-07-29 12:31:34 +05:30
Shariq Ansari
8984cea367
Merge pull request #1087 from shariquerik/bug 2025-07-29 11:34:25 +05:30
Shariq Ansari
c3cf63dfb7 fix: format NumberChart component for better readability 2025-07-29 11:32:49 +05:30
Shariq Ansari
c532b61ef6 fix: fields should not be mandatory in single doctype 2025-07-29 11:32:37 +05:30
Shariq Ansari
491fbb7801
Merge pull request #1084 from shariquerik/exchange_rate_fix-1 2025-07-28 18:05:34 +05:30
Shariq Ansari
4c7a40d8bc fix: fixed labels 2025-07-28 18:01:36 +05:30
Shariq Ansari
c866d1e836
Merge pull request #1082 from shariquerik/exchange_rate_fix 2025-07-28 17:57:59 +05:30
Shariq Ansari
c72160b2a4 fix: remove unused Link component import from GeneralSettings.vue 2025-07-28 17:52:58 +05:30
Shariq Ansari
3143f14e0b
Merge branch 'develop' into exchange_rate_fix 2025-07-28 17:51:03 +05:30
Shariq Ansari
e06a365029 fix: update description for mandatory fields in deal value forecasting 2025-07-28 17:49:52 +05:30
Shariq Ansari
36e79e49da fix: added exchange rate provider & currency together in settings modal 2025-07-28 17:48:26 +05:30
Shariq Ansari
5bee7022b2 fix: removed currency exchange rate settings and moved it to crm settings 2025-07-28 17:47:20 +05:30
Shariq Ansari
e578513eaf fix: Improve error handling in document update process 2025-07-28 16:43:46 +05:30
Meer Uzair
8de2a69a99 fix: Correct field name from 'agent' to 'user' in CRM Telephony Agent creation
- The `CRM Telephony Agent` doctype requires the field `user` (not `agent`) as per its schema (`reqd: 1` + `autoname: field:user`).
- This fixes the `ValidationError: User is required` by using the correct field name when creating a new agent.
2025-07-28 16:23:52 +05:30
frappe-pr-bot
890299c2f3 chore: update POT file 2025-07-28 16:23:52 +05:30
Shariq Ansari
2a6f1c402b chore: Serbian (Latin) translations 2025-07-28 16:23:52 +05:30
Shariq Ansari
25d2b1889f chore: Serbian (Cyrillic) translations 2025-07-28 16:23:52 +05:30
Shariq Ansari
ee843fae26 chore: Serbian (Latin) translations 2025-07-28 16:23:52 +05:30
Shariq Ansari
fea35205b7 chore: Bosnian translations 2025-07-28 16:23:52 +05:30
Shariq Ansari
ee28543180 chore: Indonesian translations 2025-07-28 16:23:52 +05:30
Shariq Ansari
4d7a66f1d8 chore: Swedish translations 2025-07-28 16:23:52 +05:30
Shariq Ansari
3b9ff8d58f chore: Serbian (Cyrillic) translations 2025-07-28 16:23:52 +05:30
Shariq Ansari
b46d5a4e5e fix: update exchange rate fetching logic to include service provider context and improve error handling 2025-07-28 16:20:08 +05:30
Shariq Ansari
23a823f2bb feat: enhance document handling with error triggering and settings helpers via app 2025-07-28 16:19:49 +05:30
Shariq Ansari
56ef00536a
Merge pull request #1077 from MeerUzairWasHere/patch-1 2025-07-28 15:56:07 +05:30
Shariq Ansari
0081006a64
Merge pull request #1076 from frappe/pot_develop_2025-07-27 2025-07-28 15:53:51 +05:30
Shariq Ansari
1c98d81c2c
Merge pull request #1074 from frappe/l10n_develop3 2025-07-28 15:53:33 +05:30
Shariq Ansari
7e9d9a5fed fix: moved get_exchange_rate api to exchange rate settings 2025-07-28 13:00:31 +05:30
Shariq Ansari
45826e0a88 fix: added currency exchange rate settings 2025-07-28 12:59:34 +05:30
Shariq Ansari
8815433962 chore: Serbian (Latin) translations 2025-07-28 12:31:04 +05:30
Shariq Ansari
e4261820d4 chore: Serbian (Cyrillic) translations 2025-07-28 12:31:03 +05:30
Shariq Ansari
5bfcaf4809 fix: get latest exchange rate 2025-07-28 12:12:34 +05:30
Meer Uzair
7f4f6ff651
fix: Correct field name from 'agent' to 'user' in CRM Telephony Agent creation
- The `CRM Telephony Agent` doctype requires the field `user` (not `agent`) as per its schema (`reqd: 1` + `autoname: field:user`).
- This fixes the `ValidationError: User is required` by using the correct field name when creating a new agent.
2025-07-27 22:58:43 +05:30
frappe-pr-bot
7d9b7e92fb chore: update POT file 2025-07-27 09:38:13 +00:00
Shariq Ansari
63963414c1 chore: Serbian (Latin) translations 2025-07-26 12:04:14 +05:30
Shariq Ansari
f0ee245f75 chore: Bosnian translations 2025-07-26 12:04:13 +05:30
Shariq Ansari
a4710a8b85 chore: Indonesian translations 2025-07-26 12:04:12 +05:30
Shariq Ansari
201ad61e6d chore: Swedish translations 2025-07-26 12:04:10 +05:30
Shariq Ansari
bbb9eefc9a chore: Serbian (Cyrillic) translations 2025-07-26 12:04:08 +05:30
Shariq Ansari
d53b503805
Merge pull request #1070 from shariquerik/log-call-fix 2025-07-24 13:14:47 +05:30
Shariq Ansari
b1d90952c4 refactor: MultiActionButton dropdown 2025-07-24 13:10:58 +05:30
Shariq Ansari
742bd6e213 fix: update label for call log actions to "Log a Call" 2025-07-24 12:47:14 +05:30
Shariq Ansari
e0abb53d4c
Merge pull request #1068 from shariquerik/primary-mobile-no-fix 2025-07-24 12:32:26 +05:30
Shariq Ansari
8e08e6f415 fix: make mobile no primary on create of contact 2025-07-24 12:29:54 +05:30
Shariq Ansari
e883ea1346
Merge pull request #1066 from shariquerik/compatibility 2025-07-24 11:56:24 +05:30
Shariq Ansari
0327b37d2f docs: add compatibility section with supported Frappe and ERPNext versions in README 2025-07-24 11:54:01 +05:30
Shariq Ansari
699feead15
Merge pull request #1064 from frappe/l10n_develop3 2025-07-24 11:28:50 +05:30
Shariq Ansari
a08fabaed9 chore: Bosnian translations 2025-07-24 11:26:11 +05:30
Shariq Ansari
61e276df37 chore: Croatian translations 2025-07-24 11:26:09 +05:30
Shariq Ansari
076762e2f3
Merge pull request #1059 from shariquerik/refactor-1 2025-07-23 13:35:55 +05:30
Shariq Ansari
9761989ea4 fix: improve exchange rate fetching with retry logic and default return value 2025-07-23 13:33:41 +05:30
Shariq Ansari
5ae7698704
Merge pull request #1057 from frappe/l10n_develop3 2025-07-23 13:23:30 +05:30
Shariq Ansari
c84ac29332 refactor: rename update_close_date to update_closed_date and adjust related logic 2025-07-23 13:21:02 +05:30
Shariq Ansari
cf8a1ce8a3 refactor: cache assignees 2025-07-23 13:12:12 +05:30
Shariq Ansari
1507701981 chore: Serbian (Latin) translations 2025-07-23 10:58:29 +05:30
Shariq Ansari
b4796efed1 chore: Bosnian translations 2025-07-23 10:58:28 +05:30
Shariq Ansari
273f7d7f07 chore: Croatian translations 2025-07-23 10:58:26 +05:30
Shariq Ansari
8474630f4c chore: Thai translations 2025-07-23 10:58:25 +05:30
Shariq Ansari
907ec5fa3c chore: Persian translations 2025-07-23 10:58:24 +05:30
Shariq Ansari
43001bee9f chore: Indonesian translations 2025-07-23 10:58:22 +05:30
Shariq Ansari
5479a6b885 chore: Portuguese, Brazilian translations 2025-07-23 10:58:21 +05:30
Shariq Ansari
594f7922f9 chore: Vietnamese translations 2025-07-23 10:58:19 +05:30
Shariq Ansari
7aa9f768ea chore: Chinese Simplified translations 2025-07-23 10:58:18 +05:30
Shariq Ansari
b796a30e1f chore: Turkish translations 2025-07-23 10:58:16 +05:30
Shariq Ansari
5508eb013a chore: Swedish translations 2025-07-23 10:58:14 +05:30
Shariq Ansari
a3c7af7c8c chore: Serbian (Cyrillic) translations 2025-07-23 10:58:13 +05:30
Shariq Ansari
d689bf21d2 chore: Russian translations 2025-07-23 10:58:12 +05:30
Shariq Ansari
05ea067361 chore: Portuguese translations 2025-07-23 10:58:10 +05:30
Shariq Ansari
2af8710a6f chore: Polish translations 2025-07-23 10:58:08 +05:30
Shariq Ansari
6abc9f7f9f chore: Dutch translations 2025-07-23 10:58:07 +05:30
Shariq Ansari
7de21b7015 chore: Italian translations 2025-07-23 10:58:06 +05:30
Shariq Ansari
f9bae5d8ff chore: Hungarian translations 2025-07-23 10:58:04 +05:30
Shariq Ansari
29322577aa chore: German translations 2025-07-23 10:58:03 +05:30
Shariq Ansari
a4f96c7c5b chore: Czech translations 2025-07-23 10:58:01 +05:30
Shariq Ansari
b3fe85b8a0 chore: Arabic translations 2025-07-23 10:58:00 +05:30
Shariq Ansari
efc4213363 chore: Spanish translations 2025-07-23 10:57:59 +05:30
Shariq Ansari
b983648f35 chore: French translations 2025-07-23 10:57:57 +05:30
Shariq Ansari
e62eac91d1
Merge pull request #1054 from frappe/l10n_develop3 2025-07-22 10:53:04 +05:30
Shariq Ansari
e6f1bd50db chore: Esperanto translations 2025-07-22 10:52:15 +05:30
Shariq Ansari
c5458fb29c chore: Serbian (Latin) translations 2025-07-22 10:52:14 +05:30
Shariq Ansari
8e3daf482d chore: Bosnian translations 2025-07-22 10:52:13 +05:30
Shariq Ansari
03edd1a011 chore: Croatian translations 2025-07-22 10:52:11 +05:30
Shariq Ansari
246ed83a3d chore: Thai translations 2025-07-22 10:52:10 +05:30
Shariq Ansari
53440476c4 chore: Persian translations 2025-07-22 10:52:09 +05:30
Shariq Ansari
14f3fd3cd7 chore: Indonesian translations 2025-07-22 10:52:08 +05:30
Shariq Ansari
6c9d56808b chore: Portuguese, Brazilian translations 2025-07-22 10:52:06 +05:30
Shariq Ansari
08b3107d92 chore: Vietnamese translations 2025-07-22 10:52:05 +05:30
Shariq Ansari
dc8fa27ea1 chore: Chinese Simplified translations 2025-07-22 10:52:04 +05:30
Shariq Ansari
445d7050b7 chore: Turkish translations 2025-07-22 10:52:02 +05:30
Shariq Ansari
bfe0df4df3 chore: Swedish translations 2025-07-22 10:52:01 +05:30
Shariq Ansari
71bcca71cd chore: Serbian (Cyrillic) translations 2025-07-22 10:52:00 +05:30
Shariq Ansari
53864ac12c chore: Russian translations 2025-07-22 10:51:59 +05:30
Shariq Ansari
f438500a57 chore: Portuguese translations 2025-07-22 10:51:57 +05:30
Shariq Ansari
cef8aacf2f chore: Polish translations 2025-07-22 10:51:56 +05:30
Shariq Ansari
1ab414c4bf chore: Dutch translations 2025-07-22 10:51:54 +05:30
Shariq Ansari
fdffd7bf3a chore: Italian translations 2025-07-22 10:51:53 +05:30
Shariq Ansari
6fc52aba6d chore: Hungarian translations 2025-07-22 10:51:52 +05:30
Shariq Ansari
dfd4cc068a chore: German translations 2025-07-22 10:51:51 +05:30
Shariq Ansari
5ae21c8580 chore: Czech translations 2025-07-22 10:51:49 +05:30
Shariq Ansari
178a934fa3 chore: Arabic translations 2025-07-22 10:51:48 +05:30
Shariq Ansari
1ce508a4b1 chore: Spanish translations 2025-07-22 10:51:47 +05:30
Shariq Ansari
d0678ec7c2 chore: French translations 2025-07-22 10:51:46 +05:30
Shariq Ansari
8036ffeafc
Merge pull request #1053 from shariquerik/updated-crowdin-yml 2025-07-22 10:39:58 +05:30
Shariq Ansari
a5a37c6181 fix: updated crowdin.yml 2025-07-22 10:38:28 +05:30
Shariq Ansari
945cdc0ae3
Merge pull request #1050 from frappe/pot_develop_2025-07-20 2025-07-22 10:22:17 +05:30
frappe-pr-bot
8de2e89b68 chore: update POT file 2025-07-20 09:37:27 +00:00
Shariq Ansari
0f49470bf6
Merge pull request #1041 from shariquerik/dashboard-fix-1 2025-07-15 15:11:01 +05:30
Shariq Ansari
7826565ce7 fix: reset to default 2025-07-15 15:09:48 +05:30
Shariq Ansari
713571469b fix: only show edit button to system manager 2025-07-15 14:55:10 +05:30
Shariq Ansari
2f34fdd409 fix: set status correctly 2025-07-15 14:52:19 +05:30
Shariq Ansari
6fefa16ac3
Merge pull request #1033 from shariquerik/editable-dashboard 2025-07-15 13:28:50 +05:30
Shariq Ansari
b344f412c9 fix: forecasting chart is breaking if no data 2025-07-15 13:21:46 +05:30
Shariq Ansari
1e245e7719
Merge pull request #1038 from shariquerik/to-status-type-1 2025-07-15 12:39:07 +05:30
Shariq Ansari
28facd66c4 fix: to status type is not accessible 2025-07-15 12:37:44 +05:30
Shariq Ansari
c8f01f08ed fix: updated default manager dashboard 2025-07-15 12:33:54 +05:30
Shariq Ansari
a89525f77e
Merge pull request #1036 from shariquerik/to-status-type 2025-07-15 12:18:21 +05:30
Shariq Ansari
38a2fa87c3 fix: to status type is not accessible 2025-07-15 12:17:00 +05:30
Shariq Ansari
46e6ed2e6f fix: minor fix 2025-07-15 12:11:08 +05:30
Shariq Ansari
266952c404 fix: decreased rowHeight to 42 2025-07-15 12:07:19 +05:30
Shariq Ansari
b77e59589a build(deps): bump frappeui to 0.1.171 2025-07-15 12:06:41 +05:30
Shariq Ansari
1a5ae397dc
Merge pull request #1034 from shariquerik/exchange_rate_org 2025-07-15 11:51:21 +05:30
Shariq Ansari
7c4718ad02 fix: removed currency exchange and added exchange rate field 2025-07-15 11:41:02 +05:30
Shariq Ansari
d79341b6d9 fix: renamed blank card to spacer 2025-07-14 20:29:46 +05:30
Shariq Ansari
84738ba00c fix: allow force reset manager dashboard 2025-07-14 20:22:43 +05:30
Shariq Ansari
3b0a8d8e4b fix: updated default manager dashboard 2025-07-14 20:16:06 +05:30
Shariq Ansari
2584cca128 fix: minor fixes 2025-07-14 20:12:52 +05:30
Shariq Ansari
05b8cea206 fix: create default manager dashboard if not exists 2025-07-14 19:14:18 +05:30
Shariq Ansari
6e3d23a8e1 fix: add default Manager Dashboard on install 2025-07-14 18:28:51 +05:30
Shariq Ansari
2a38d0fb5f fix: disabel save button if not dirty, reset to old items if cancel 2025-07-14 18:15:04 +05:30
Shariq Ansari
97724c776b build(deps): bump frappeui to 0.1.170 2025-07-14 17:58:01 +05:30
Shariq Ansari
9b072058cc build(deps): bump frappeui to 0.1.170 2025-07-14 17:57:43 +05:30
Shariq Ansari
d2e65feaa6 fix: save edited dashboard 2025-07-14 17:41:00 +05:30
Shariq Ansari
37c2d3a2b0 feat: allow adding existing charts 2025-07-14 17:40:13 +05:30
Shariq Ansari
0909423fe9 fix: rename card to chart 2025-07-14 17:38:17 +05:30
Shariq Ansari
139bcb101c fix: added remove chart button 2025-07-14 17:37:36 +05:30
Shariq Ansari
0f06715d0c fix: use tooltip from data 2025-07-14 17:36:50 +05:30
Shariq Ansari
4a783fcba8 fix: show edit button to manager 2025-07-14 14:22:53 +05:30
Shariq Ansari
fd38f0ac98 fix: load dashboard layout from CRM Dashboard doctype and render 2025-07-14 14:16:10 +05:30
Shariq Ansari
ed2208fe75 fix: added crm dashboard doctype to store dashboard layout 2025-07-14 14:13:50 +05:30
Shariq Ansari
4320142132 fix: update status type patch was not working 2025-07-14 12:27:14 +05:30
Shariq Ansari
160649bf97 fix: use GridLayout from frappe-ui to display dashboard 2025-07-14 12:18:14 +05:30
Shariq Ansari
e7a2efd14a
Merge pull request #1029 from frappe/pot_develop_2025-07-13 2025-07-13 15:21:23 +05:30
Shariq Ansari
81614418d4
Merge pull request #1030 from shariquerik/deal-status-type 2025-07-13 15:15:19 +05:30
frappe-pr-bot
bb08f3d377 chore: update POT file 2025-07-13 09:38:02 +00:00
Shariq Ansari
5232da6ec3 fix: updated funnel query to get status change count 2025-07-13 13:07:31 +05:30
Shariq Ansari
e59547da30 fix: store deal status type in status log 2025-07-13 12:43:03 +05:30
Shariq Ansari
de85ccfc51 fix: added deals by ongoing & won stages bar 2025-07-13 12:35:16 +05:30
Shariq Ansari
f82019e510 fix: used closed_date instead of closed_on and set closed_date if status type is Won 2025-07-13 12:11:50 +05:30
Shariq Ansari
7fc26a5202 fix: used expected closed date & deal value for forecasting 2025-07-13 12:09:35 +05:30
Shariq Ansari
dcb1e47564 fix: added closed_date removed closed_on & added expected_deal_value & expected_closure_date field 2025-07-13 12:02:34 +05:30
Shariq Ansari
61259f3d2e fix: avg time to close a deal number card 2025-07-13 11:52:04 +05:30
Shariq Ansari
2dd2608c09 fix: added two more number cards 2025-07-13 11:35:14 +05:30
Shariq Ansari
81dc4e1138 fix: get ongoing deals and won deals based on closed_on date 2025-07-11 17:09:21 +05:30
Shariq Ansari
cb1f9f760c fix: use status.type instead of status in all query 2025-07-11 17:00:59 +05:30
Shariq Ansari
51530b7608 fix: show lost reason modal if status of type Lost is set 2025-07-11 16:35:47 +05:30
Shariq Ansari
4e6d4a1d77 patch: added patch to update deal status type 2025-07-11 16:16:40 +05:30
Shariq Ansari
efc5dd93e9 fix: added type in default deak status while installing 2025-07-11 16:07:52 +05:30
Shariq Ansari
210a9d8d06 fix: added type of deal status field 2025-07-11 16:05:57 +05:30
Shariq Ansari
9bd855ee2e
Merge pull request #1024 from shariquerik/save-lead 2025-07-10 18:33:18 +05:30
Shariq Ansari
970c215f40 fix: cannot save data fields in lead page 2025-07-10 18:27:01 +05:30
Shariq Ansari
7d157046ac
Merge pull request #1022 from shariquerik/dashboard-fix 2025-07-10 17:39:14 +05:30
Shariq Ansari
1ae7018f79 fix: apply user filter if sales user 2025-07-10 17:38:36 +05:30
Shariq Ansari
6802567291
Merge pull request #979 from nextchamp-saqib/dashboard 2025-07-10 17:21:58 +05:30
Shariq Ansari
cbc127e947 fix: better description 2025-07-10 17:20:25 +05:30
Shariq Ansari
d91d4765b5 fix: make autocomplete non clickable if disabled 2025-07-10 17:06:58 +05:30
Shariq Ansari
328959cc39 style: better spacing 2025-07-10 16:59:09 +05:30
Shariq Ansari
36320f61ab fix: remove mandatory from currency field in crm settings 2025-07-10 16:36:02 +05:30
Shariq Ansari
faeacb9a7d chore: minor fix 2025-07-10 16:27:00 +05:30
Shariq Ansari
5dcd416007 fix: added forecasting & currency setting in general settings 2025-07-10 16:15:27 +05:30
Shariq Ansari
33e4072430 fix: added disabled & placement prop in Link component 2025-07-10 16:14:32 +05:30
Shariq Ansari
c7fbd6f8f1 refactor: general settings 2025-07-10 15:27:55 +05:30
Shariq Ansari
a5d3694386 refactor: get exchange rate api 2025-07-10 15:23:59 +05:30
Shariq Ansari
b3075416e2 fix: show dashboard to manager only 2025-07-10 13:59:30 +05:30
Shariq Ansari
743d97d690
Merge pull request #1018 from zaqouttahir/fix-bug-edit-bulk 2025-07-10 12:29:07 +05:30
Shariq Ansari
2cb09dde4b fix: use exchange rate in deal to calculate the deal value 2025-07-09 18:22:52 +05:30
Shariq Ansari
d7ba5a5f62 fix: store current day exchange rate when currency is updated in deal & organization 2025-07-09 18:22:13 +05:30
Shariq Ansari
a00bba35f8 fix: remove crm currency exchange doctype 2025-07-09 18:20:49 +05:30
Shariq Ansari
71db65d21c fix: make currency read only once set 2025-07-09 17:49:44 +05:30
Shariq Ansari
37d820a67c chore: updated/added number card tooltip 2025-07-09 17:47:56 +05:30
Shariq Ansari
4f02f0a4d7 fix: convert to system currency and show deal value 2025-07-09 15:53:06 +05:30
Shariq Ansari
f4b81b3761 fix: added date field in currency exchange doctype 2025-07-09 14:48:49 +05:30
Shariq Ansari
0be737914a fix: store currency exchange in deal & organization 2025-07-09 14:38:56 +05:30
Shariq Ansari
1b0d966db0 fix: created currency exchange doctype 2025-07-09 14:37:16 +05:30
Shariq Ansari
27f87883f7 fix: fieldtype of value is not changing based on selected field's fieldtype 2025-07-08 19:16:58 +05:30
Shariq Ansari
f747e076ab fix: only show sales user filter to manager 2025-07-08 12:58:46 +05:30
Shariq Ansari
4b12918ba5 fix: added filters and translated titles 2025-07-08 12:29:20 +05:30
zaqouttahir
c104b1b8b4 fix: set fieldname to handle edit value modal 2025-07-07 13:13:04 +03:00
Shariq Ansari
9d4106cd81 chore: cleanup 2025-07-07 14:33:11 +05:30
Shariq Ansari
eddf8c9295 fix: show avg time number card based on closed_on date 2025-07-07 14:30:29 +05:30
Shariq Ansari
6b3e42a44e
Merge pull request #1015 from frappe/pot_develop_2025-07-06 2025-07-07 14:16:21 +05:30
Shariq Ansari
9b1d4832b6
Merge branch 'develop' into dashboard 2025-07-06 15:25:40 +05:30
Shariq Ansari
4d2f054e40 fix: added avg time to close number card 2025-07-06 15:24:43 +05:30
Shariq Ansari
6450b69ae7 fix: capture closed on datetime when deal marked as Won 2025-07-06 15:24:23 +05:30
frappe-pr-bot
223187c7ea chore: update POT file 2025-07-06 09:36:54 +00:00
Shariq Ansari
3b34f73cb3 fix: added more charts for dashboard 2025-07-06 14:44:12 +05:30
Shariq Ansari
40c5c92230
Merge pull request #1013 from shariquerik/primary-mobile-no 2025-07-05 14:33:10 +05:30
Shariq Ansari
6760798f18 fix: useDocument in organization page 2025-07-05 14:17:26 +05:30
Shariq Ansari
42ea1ad16e fix: useDocument in contact page 2025-07-05 14:09:37 +05:30
Shariq Ansari
96200aebe6 fix: update primary mobile_no & email in deal if contact is updated 2025-07-05 13:21:21 +05:30
Shariq Ansari
bcfe4b6a49 fix: made mobile_no, email & phone readonly since it captures primary contacts data 2025-07-05 12:30:40 +05:30
Shariq Ansari
cb92e5e68d
Merge branch 'develop' into dashboard 2025-07-03 14:28:28 +05:30
Shariq Ansari
1fa6b5bb51 fix: added first cut queries for some charts and number cards 2025-07-03 14:27:21 +05:30
Shariq Ansari
cafc4fb22f
Merge pull request #1009 from shariquerik/products-table-fix 2025-07-02 17:50:58 +05:30
Shariq Ansari
39eb5600d9 fix: grid field is not getting set 2025-07-02 17:45:46 +05:30
Shariq Ansari
0b97462dc9
Merge pull request #1007 from shariquerik/lost-reason-fix 2025-07-02 17:26:54 +05:30
Shariq Ansari
cab80edf60 fix: check reason.reason not reason 2025-07-02 17:15:59 +05:30
Shariq Ansari
6f3b58d1a5
Merge pull request #1005 from shariquerik/frappeui-update 2025-07-02 17:09:33 +05:30
Shariq Ansari
fc89c7b93c build(deps): bump frappeui to 0.1.166 2025-07-02 17:03:28 +05:30
Shariq Ansari
4a57c4eb84
Merge pull request #1003 from shariquerik/default-lost-reason 2025-07-02 16:59:23 +05:30
Shariq Ansari
96cbdea820 fix: add default lost reason on install 2025-07-02 16:57:26 +05:30
Shariq Ansari
a3a54aef94
Merge pull request #984 from shariquerik/lost-reasons 2025-07-02 16:03:30 +05:30
Shariq Ansari
c96e5ff6c5 fix: update default probability from deal status 2025-07-02 15:58:12 +05:30
Shariq Ansari
144470877d fix: allow creating lost reason from lost reason modal field 2025-07-02 15:42:25 +05:30
Shariq Ansari
391844512a fix: intercept data tab's before save and side panel's before field change to show lost reason modal 2025-07-02 15:28:21 +05:30
Shariq Ansari
d89c304b13 fix: show lost reason modal if status changed to lost 2025-07-02 14:11:11 +05:30
Shariq Ansari
881126c7f1 refactor: statusOptions code 2025-07-02 14:10:14 +05:30
Shariq Ansari
5bbec00803 fix: renamed other_lost_reason to lost_notes 2025-07-02 13:59:34 +05:30
Shariq Ansari
7730e46cfc fix: removed unused triggerOnChange 2025-07-02 13:58:51 +05:30
Shariq Ansari
97b2253e9d fix: made lost notes as text and non mandatory if lost reason is not Other 2025-07-02 11:10:53 +05:30
Shariq Ansari
1afb2a783b
Merge branch 'develop' into lost-reasons 2025-07-01 19:34:35 +05:30
Shariq Ansari
0fdbfa3ad4
Merge pull request #998 from shariquerik/prettydate-fix 2025-07-01 19:23:24 +05:30
Shariq Ansari
a7dc5e05b3 fix: show absolute day count not in decimels 2025-07-01 19:20:04 +05:30
Shariq Ansari
92d7280728 chore: resolved conflict 2025-07-01 16:53:40 +05:30
Shariq Ansari
5d01b88a1e feat: created lost reason doctype 2025-07-01 16:51:01 +05:30
Shariq Ansari
2b47e3f4c9
Merge pull request #994 from shariquerik/forecasting-fix-1 2025-07-01 16:49:48 +05:30
Shariq Ansari
485360f291 fix: show forcasted sales section in sidepanel if forecasting is enabled 2025-07-01 16:37:04 +05:30
Shariq Ansari
17fdbb05ce fix: add mandatory fields in convert to deal modal if not added 2025-07-01 16:05:08 +05:30
Shariq Ansari
adc22efcb1 fix: show error message on convert to deal modal 2025-07-01 16:04:40 +05:30
Shariq Ansari
4c70b1a06b fix: mandatory error 2025-07-01 15:06:02 +05:30
Shariq Ansari
4f58aa110a fix: made deal value mandatory if forecasting is enabled 2025-07-01 15:05:37 +05:30
Shariq Ansari
4d3fe722e8 fix: added default probability to Lost status 2025-07-01 13:16:40 +05:30
Shariq Ansari
6320e580ae refactor: moved convert to deal modal into separate component 2025-07-01 13:07:36 +05:30
Shariq Ansari
611f4cde70 fix: prettyDate is not accurate 2025-07-01 12:58:57 +05:30
Shariq Ansari
6d3268a61e fix: add default probabilities in deal status 2025-07-01 12:07:44 +05:30
Shariq Ansari
bf0a1ecebd
Merge pull request #991 from shariquerik/edit-call-log 2025-07-01 11:52:18 +05:30
Shariq Ansari
693c086930 fix: show edit call log button in call log details modal 2025-07-01 11:49:42 +05:30
Shariq Ansari
7c307a9134
Merge pull request #988 from shariquerik/call-log-on-before-create 2025-06-30 20:06:01 +05:30
Shariq Ansari
aae7e0e36c fix: pass reference doc to call log modal to get reference doc in on before create 2025-06-30 20:00:05 +05:30
Shariq Ansari
2014a3d6de
Merge pull request #985 from shariquerik/on-before-create 2025-06-30 19:41:35 +05:30
Shariq Ansari
2e5c1bc3b5 fix: added on before create hook in all modals 2025-06-30 19:16:24 +05:30
Shariq Ansari
ac13b7a3bd fix: added on before create hook in call log modal 2025-06-30 18:43:19 +05:30
Shariq Ansari
6b7bdf5afb feat: added on before create hook in document.js 2025-06-30 18:42:20 +05:30
Shariq Ansari
3eba628a8b
Merge branch 'develop' into dashboard 2025-06-30 12:57:13 +05:30
Shariq Ansari
9949478b36 fix: added breadcrumb and made header sticky 2025-06-30 12:56:47 +05:30
Shariq Ansari
ff657ec34c
Merge pull request #980 from frappe/pot_develop_2025-06-29 2025-06-30 12:42:55 +05:30
Shariq Ansari
da4698d431
Merge branch 'develop' into pot_develop_2025-06-29 2025-06-30 12:42:12 +05:30
Shariq Ansari
20d47ae323
Merge pull request #978 from shariquerik/dynamic-app-alias 2025-06-30 11:59:29 +05:30
Shariq Ansari
f4f799f636 feat: create dynamic alias to use components from frontend vue apps 2025-06-30 11:49:31 +05:30
frappe-pr-bot
cc411f036d chore: update POT file 2025-06-29 09:36:46 +00:00
Saqib Ansari
62d5c2a91f feat: initialize dashboard boilerplate 2025-06-28 10:57:58 +05:30
Shariq Ansari
8350c5ee36
Merge pull request #971 from shariquerik/email-template-settings 2025-06-26 17:54:04 +05:30
Shariq Ansari
65435cf2b5 fix: delete icon issue & more cleanup 2025-06-26 17:49:10 +05:30
Shariq Ansari
af4c64e633 build(deps): bump frappeui to 0.1.162 2025-06-26 17:11:37 +05:30
Shariq Ansari
41b913debe fix: cannot change role of user with Admin access 2025-06-26 17:07:26 +05:30
Shariq Ansari
a3b9368953 fix: give Sales Manager & Sales User role if System Manager access is given 2025-06-26 16:54:33 +05:30
Shariq Ansari
28ece820ed style: better spacing 2025-06-26 16:46:23 +05:30
Shariq Ansari
cca420b1a0 style: minor changes 2025-06-25 21:19:49 +05:30
Shariq Ansari
05803c79b4 fix: make email template row clickable 2025-06-25 17:02:41 +05:30
Shariq Ansari
5932ccafec fix: add new email template from email selector modal 2025-06-25 15:23:30 +05:30
Shariq Ansari
7cee017e20 fix: removed email template page and related components 2025-06-25 15:15:34 +05:30
Shariq Ansari
b15a8d9c8a fix: added email template icon 2025-06-25 15:03:32 +05:30
Shariq Ansari
7e6d5c3e54 fix: Duplicate email template 2025-06-24 19:46:27 +05:30
Shariq Ansari
dd3d297dab fix: Edit email template 2025-06-24 19:37:13 +05:30
Shariq Ansari
e4f728d809 fix: Create email template 2025-06-24 18:52:36 +05:30
Shariq Ansari
cd7bab9184 feat: Create/Edit & List page for email template & implemented delete from list 2025-06-24 18:52:00 +05:30
Shariq Ansari
ec6b1558b1 fix: only show search if users are more than 10 2025-06-24 15:36:54 +05:30
Shariq Ansari
1c3ee8b557 refactor: added email templates in settings modal 2025-06-24 15:35:48 +05:30
Shariq Ansari
1db7f69f89
Merge pull request #960 from shariquerik/users-fix-1 2025-06-24 12:12:20 +05:30
Shariq Ansari
3c1ce1fe27 fix: make header sticky 2025-06-24 12:11:39 +05:30
Shariq Ansari
2d05b6a282
Merge pull request #957 from shariquerik/users-fix 2025-06-24 11:45:46 +05:30
Shariq Ansari
b5ed9692df fix: user with System Manager role is admin 2025-06-24 11:44:13 +05:30
Shariq Ansari
9a326d791b
Merge pull request #953 from shariquerik/users 2025-06-23 21:00:32 +05:30
Shariq Ansari
7fbd240d97 fix: added search in users page 2025-06-23 20:55:35 +05:30
Shariq Ansari
58d4691354
Merge pull request #846 from pratikb64/delete-from-record-view 2025-06-23 13:50:19 +05:30
Pratik
594295b7c8 style: switch button position 2025-06-23 08:13:06 +00:00
Shariq Ansari
2c45673f54
Merge pull request #845 from shariquerik/agents 2025-06-23 13:22:56 +05:30
Shariq Ansari
7827afe606
Merge pull request #946 from kalungia/dev 2025-06-23 13:21:59 +05:30
Shariq Ansari
bc7498e02b
Merge branch 'develop' into dev 2025-06-23 13:20:01 +05:30
Shariq Ansari
e5dd85aefb
Merge pull request #948 from frappe/pot_develop_2025-06-22 2025-06-23 13:19:09 +05:30
Shariq Ansari
cf1fce3dc0 fix: renaming fix and removed CRM User code 2025-06-23 13:18:16 +05:30
Pratik
480cc07cd9 refactor: remove unnecessary functions & components 2025-06-23 07:35:15 +00:00
Shariq Ansari
84d4327e80 fix: use change password modal in place 2025-06-23 13:04:12 +05:30
Pratik
34102ef6ef refactor: change labels & function names 2025-06-23 05:15:40 +00:00
Pratik
ca985a0b76 Merge branch 'develop' of https://github.com/pratikb64/crm into delete-from-record-view 2025-06-23 04:26:50 +00:00
frappe-pr-bot
4b4a154261 chore: update POT file 2025-06-22 09:36:52 +00:00
Shariq Ansari
e957327877 fix: use crmUsers in all link field 2025-06-20 18:57:09 +05:30
Shariq Ansari
2fdea90ad4 fix: loading state in Users page 2025-06-20 18:55:42 +05:30
Shariq Ansari
ad1aee9c9e fix: add user is actually add role 2025-06-20 18:55:14 +05:30
Shariq Ansari
bd7451e86f fix: if role is set to sales user then remove modules and set FCRM 2025-06-20 17:56:14 +05:30
Shariq Ansari
0230360145 fix: use text-ink-gray-8 instead of 9 2025-06-20 17:47:07 +05:30
Shariq Ansari
eee1190f10 fix: dark mode fixes for email account setting 2025-06-20 17:42:10 +05:30
Shariq Ansari
96c8aae01e chore: fixed warning 2025-06-20 17:25:14 +05:30
Shariq Ansari
0ad65be961 fix: layout change 2025-06-20 17:20:12 +05:30
Shariq Ansari
0f8d484e28 fix: existingEmail is a list 2025-06-20 17:18:36 +05:30
Shariq Ansari
364c369199 fix: updated users page to update user directly and removed unnecessary code 2025-06-20 16:46:41 +05:30
Shariq Ansari
901bcb8460 fix: removed CRM User doctype and moved api's to user.py 2025-06-20 16:45:48 +05:30
Shariq Ansari
d06ac91052 fix: use multi select user input and show already exist error if user with email exist or invited 2025-06-20 16:43:48 +05:30
Shariq Ansari
f818a4c1d6 fix: created multi select user input 2025-06-20 16:42:45 +05:30
Shariq Ansari
85191e10c8 fix: use crmUsers in comment box 2025-06-20 16:41:08 +05:30
Shariq Ansari
001a3231e1 fix: get users and crm users 2025-06-20 15:50:47 +05:30
Shariq Ansari
d951dff5a9 fix: added tooltip with shortcut 2025-06-19 15:08:53 +05:30
Shariq Ansari
dc82f837aa fix: moved change password modal in global modals 2025-06-19 15:07:57 +05:30
Shariq Ansari
7f1db0b444 fix: change password validation messsage 2025-06-19 12:56:50 +05:30
Abraham Kalungi
a317950567 fix: prevent TypeError when concatenating first and last name in WhatsApp messages
The last name on CRM Leads can be empty. In cases where it is, an error occurs: can only concatenate str (not "NoneType") to str. This prevents retrieving messages until a last name is added.
2025-06-18 15:31:00 +02:00
Shariq Ansari
4c7269e357 fix: updated components.d.ts 2025-06-17 23:46:53 +05:30
Shariq Ansari
15fd763de8 fix: use validateIsImageFile from utils 2025-06-17 23:46:28 +05:30
Shariq Ansari
0c314674fc
Merge branch 'develop' into agents 2025-06-17 23:42:42 +05:30
Shariq Ansari
efd03141f0
chore: resolved conflict 2025-06-17 23:42:20 +05:30
Shariq Ansari
675bcb549d
Discard changes to frontend/src/components/Settings/ProfileImageEditor.vue 2025-06-17 23:40:58 +05:30
Shariq Ansari
56425254a9 fix: updated components.d.ts 2025-06-17 23:35:51 +05:30
Shariq Ansari
22856351fd fix: only show users to manager 2025-06-17 23:35:51 +05:30
Shariq Ansari
dd1229309f fix: updated components.d.ts 2025-06-17 23:35:51 +05:30
Shariq Ansari
fad7c5985c refactor: profile page 2025-06-17 23:34:45 +05:30
Shariq Ansari
3234102e55 fix: capture onboarding step event of setting up password 2025-06-17 23:34:45 +05:30
Shariq Ansari
fb2f105520 feat: update password modal 2025-06-17 23:34:45 +05:30
Shariq Ansari
03abe0b5cd fix: create crm user on accepting invite 2025-06-17 23:34:44 +05:30
Shariq Ansari
6873c6db4e feat: add existing users 2025-06-17 23:34:44 +05:30
Shariq Ansari
08bab927a2 fix: filter out existing emails 2025-06-17 23:34:44 +05:30
Shariq Ansari
d244567b30 fix: open invite user page from users add new agent dropdown option 2025-06-17 23:34:44 +05:30
Shariq Ansari
2b1b21d2e2 fix: show role options based on logged in user's role 2025-06-17 23:34:44 +05:30
Shariq Ansari
12213de478 fix: show role options based on logged in user's role 2025-06-17 23:34:44 +05:30
Shariq Ansari
2a2c832e0b fix: updated roles in Invite user page 2025-06-17 23:34:44 +05:30
Shariq Ansari
b534aae70b fix: renamed component names from Agent to User 2025-06-17 23:34:44 +05:30
Shariq Ansari
6d3e4406ae fix: renamed & added role with filter 2025-06-17 23:34:44 +05:30
Shariq Ansari
463d60b650 fix: renamed Agent to User in Settings 2025-06-17 23:34:44 +05:30
Shariq Ansari
e9812495e9 fix: update agent fields based on user 2025-06-17 23:34:44 +05:30
Shariq Ansari
0a836c78bb fix: activate/deactivate agent 2025-06-17 23:34:44 +05:30
Shariq Ansari
5c7f835e4c fix: renamed invite members to invite agent 2025-06-17 23:34:44 +05:30
Shariq Ansari
346849631e fix: show and allow changing role from agents settings page 2025-06-17 23:34:44 +05:30
Shariq Ansari
bf166bdaad fix: added get user role in users store 2025-06-17 23:34:44 +05:30
Shariq Ansari
123f183f68 fix: removed x button from settings modal 2025-06-17 23:34:44 +05:30
Shariq Ansari
bea1505c63 fix: added Agents page in settings 2025-06-17 23:34:44 +05:30
Shariq Ansari
fac5ed5579 feat: added crm agent doctype 2025-06-17 23:34:44 +05:30
Shariq Ansari
96fefbd8a3
Merge pull request #937 from shariquerik/forecasting-fix 2025-06-16 17:48:08 +05:30
Shariq Ansari
548018997e build(deps): bump frappeui to 0.1.156 2025-06-16 17:42:28 +05:30
Shariq Ansari
9f3477e1cd fix: updated button with icon 2025-06-16 17:42:01 +05:30
Shariq Ansari
baa03246e6 fix: fixed breaking button with icon and open email box 2025-06-16 17:06:06 +05:30
Shariq Ansari
a17b1cd0e2 fix: added mandatory field error toast 2025-06-16 16:32:15 +05:30
Shariq Ansari
49d82870c4 fix: hide calendar icon in side panel date fields 2025-06-16 13:41:11 +05:30
Shariq Ansari
6a72a4467a build(deps): bump frappeui to 0.1.154 2025-06-16 13:40:53 +05:30
Shariq Ansari
efbed6e0b6 fix: renamed Expected Closure Date to Close Date 2025-06-16 11:44:08 +05:30
Shariq Ansari
5270670b65
Merge pull request #933 from frappe/pot_develop_2025-06-15 2025-06-16 11:39:47 +05:30
frappe-pr-bot
b82f4ca02b chore: update POT file 2025-06-15 09:36:57 +00:00
Pratik Badhe
0f451c7e3a
Merge pull request #930 from pratikb64/git-error 2025-06-13 18:26:31 +05:30
Pratik
824dc8dcdd fix: git command error 2025-06-13 12:51:04 +00:00
Shariq Ansari
20405be86c
Merge pull request #920 from shariquerik/forecasting 2025-06-13 15:04:23 +05:30
Shariq Ansari
4edfa951dc fix: asterisk is not visible if label is big enough 2025-06-13 15:02:50 +05:30
Shariq Ansari
029c16d1d0 fix: circular import 2025-06-13 14:46:44 +05:30
Shariq Ansari
b3acff8cba fix: create standard forecasting script on install and added in patch 2025-06-13 14:42:09 +05:30
Shariq Ansari
a98b0e3a00 fix: set close date to now if status is Won 2025-06-13 14:20:50 +05:30
Shariq Ansari
b1cbcbd98d
Merge pull request #923 from shariquerik/lead-org-avatar-fix 2025-06-12 18:09:41 +05:30
Shariq Ansari
e079980598 fix: removed leads organization logo 2025-06-12 18:07:07 +05:30
Shariq Ansari
2e27c0459c fix: set close date reqd as 1 or 0 based on enabled_forecasting 2025-06-11 19:30:08 +05:30
Shariq Ansari
d87a237789 feat: added enable forecasting settings 2025-06-11 19:03:22 +05:30
Shariq Ansari
e9e0aa357b fix: trigger on change on status change 2025-06-11 14:20:11 +05:30
Shariq Ansari
9af300bba8 fix: added throwError global method 2025-06-11 14:19:16 +05:30
Shariq Ansari
7d79cbf5bd fix: update and reset value in triggerOnChange method 2025-06-11 14:18:25 +05:30
Shariq Ansari
fdca27bb81 fix: added probability field in deal status 2025-06-11 13:01:22 +05:30
Shariq Ansari
01f0213693 fix: added deal value field 2025-06-11 13:00:02 +05:30
Shariq Ansari
5d29a49120
Merge pull request #916 from mahsem/develop 2025-06-11 11:13:25 +05:30
mahsem
33e6b80d5a
fix: add context for Integrations 2025-06-09 22:11:22 +02:00
Shariq Ansari
100d931535
Merge pull request #913 from shariquerik/future-date-time-ago 2025-06-09 16:51:02 +05:30
Shariq Ansari
dba6dd1983 fix: future date is not captured in pretty date 2025-06-09 16:49:09 +05:30
Shariq Ansari
dc8898e1da
Merge pull request #907 from frappe/pot_develop_2025-06-08 2025-06-09 14:09:56 +05:30
frappe-pr-bot
ed79bf55eb chore: update POT file 2025-06-08 09:36:10 +00:00
Shariq Ansari
fb644f5fbe
Merge pull request #905 from NagariaHussain/fix/image-upload
refactor: DRY up validate image file
2025-06-08 12:49:03 +05:30
Hussain Nagaria
ab409dfd2c fix: yet another unused import due to merge conflict 2025-06-08 12:37:15 +05:30
Hussain Nagaria
42285dd911 fix: unused import due to merge conflict 2025-06-08 12:36:39 +05:30
Md Hussain Nagaria
db2a6c65b7
Merge branch 'develop' into fix/image-upload 2025-06-08 12:34:30 +05:30
Hussain Nagaria
c6ad10857a refactor: DRY up validate image file
* Also, allows more types of image files
2025-06-08 12:30:51 +05:30
Shariq Ansari
f128a55f97
Merge pull request #902 from shariquerik/onload-onsave 2025-06-06 21:15:42 +05:30
Shariq Ansari
2a817e5861 fix: only load assignee if docname is passed 2025-06-06 21:14:20 +05:30
Shariq Ansari
5e616f1a50 refactor: statusOptions code 2025-06-06 21:09:27 +05:30
Shariq Ansari
c6e9d71e1f fix: allow snake & camel case for on load, on save, convert to deal, on create lead 2025-06-06 21:01:20 +05:30
Shariq Ansari
f58d44bf9c fix: use document.doc in status dropdown 2025-06-06 20:49:58 +05:30
Shariq Ansari
f72ab39c93 fix: onLoad & onSave 2025-06-06 20:35:25 +05:30
Shariq Ansari
6c706e6162
Merge pull request #899 from shariquerik/minor-fix 2025-06-06 17:51:43 +05:30
Shariq Ansari
8f81d207b8 fix: activity is not loading 2025-06-06 17:50:48 +05:30
Shariq Ansari
b74c5f384d
Merge pull request #896 from shariquerik/custom-actions 2025-06-06 17:24:13 +05:30
Shariq Ansari
df412d51fe fix: add custom actions using class based script in mobile view 2025-06-06 17:19:27 +05:30
Shariq Ansari
8942bb7e48 feat: add custom statuses using class based script 2025-06-06 17:17:11 +05:30
Shariq Ansari
ca60679126 feat: add custom actions using class based script 2025-06-06 16:38:39 +05:30
Shariq Ansari
8db846ad5d fix: trigger onload method if controller is loaded 2025-06-06 16:37:55 +05:30
Shariq Ansari
bb6a90058b
Merge pull request #894 from shariquerik/refactor-assignees 2025-06-06 14:58:47 +05:30
Shariq Ansari
44df09fac2 fix: removed setuAssignees code 2025-06-06 14:06:02 +05:30
Shariq Ansari
e214ce8bfb refactor: render assignees from document.js
reload assignees if lead_owner/deal_owner is changed
2025-06-05 18:55:28 +05:30
Shariq Ansari
6d281922e4 fix: load assignees in document.js 2025-06-05 18:53:57 +05:30
Shariq Ansari
58f09331b0 fix: remove multiple assignees not working 2025-06-05 18:52:39 +05:30
Shariq Ansari
9780a6b63e
Merge pull request #891 from shariquerik/fixes-2 2025-06-05 16:14:38 +05:30
Shariq Ansari
71f764c224 refactor: set default values for new lead, deal and contact 2025-06-05 16:08:51 +05:30
Shariq Ansari
9362997246 refactor: organization modal code refactor 2025-06-05 16:08:13 +05:30
Shariq Ansari
28ea88f61e refactor: call log modal code refactor 2025-06-05 16:07:40 +05:30
Shariq Ansari
a25ff14dd4 fix: activity is not loading 2025-06-05 15:31:36 +05:30
Shariq Ansari
d86caee7af
Merge pull request #887 from shariquerik/new-doc-issue 2025-06-05 13:56:57 +05:30
Shariq Ansari
c4caabe722 fix: moved address modal to global modals and control it using modals.js 2025-06-04 19:15:12 +05:30
Shariq Ansari
8dcb77634b fix: moved quick entry modal related logic to modals.js & GlobalModals for all pages 2025-06-04 19:14:15 +05:30
Shariq Ansari
c4feed116d fix: handle new document for lead/deal/contact/organization 2025-06-04 19:00:57 +05:30
Shariq Ansari
e220767179 fix: global modals not working in mobile view 2025-06-04 18:44:51 +05:30
Shariq Ansari
571126c36d fix: moved modal related code to modal.js 2025-06-04 18:34:19 +05:30
Shariq Ansari
832323f25e fix: handle new document for call log 2025-06-04 12:50:19 +05:30
Shariq Ansari
3b73432d8c fix: handle controllers for new document 2025-06-04 12:49:14 +05:30
Shariq Ansari
3aa341370b fix: await scripts.list.promise 2025-06-04 12:48:20 +05:30
Ankush Menat
895da1a812
fix: remove invasive settings (#884) 2025-06-02 19:03:54 +05:30
Shariq Ansari
d34ee6fe48
Merge pull request #875 from Ocheretovich/patch-2 2025-06-02 12:37:56 +05:30
Shariq Ansari
7298fe378c
Merge pull request #878 from frappe/pot_develop_2025-06-01 2025-06-02 12:37:01 +05:30
Shariq Ansari
2da0b48c29
Merge pull request #874 from Ocheretovich/patch-1 2025-06-02 12:36:01 +05:30
frappe-pr-bot
165509f5a0 chore: update POT file 2025-06-01 09:36:30 +00:00
Ocheretovich
c9b9dbb092
Update README.md 2025-05-29 13:06:52 +03:00
Ocheretovich
0cc1d5da8f
Update README.md 2025-05-29 13:03:21 +03:00
Pratik
c70dced268 refactor: internationalization & code clean up 2025-05-29 06:02:35 +00:00
Pratik
df698387dc Merge remote-tracking branch 'origin/develop' into delete-from-record-view 2025-05-29 05:54:17 +00:00
Pratik
716dc056d6 refactor: move delete button 2025-05-29 05:52:36 +00:00
Pratik Badhe
cf91f3f72a
Merge pull request #872 from pratikb64/export-filter-fix 2025-05-28 17:18:19 +05:30
Pratik
51b87d0ac6 fix: export with filter 2025-05-28 11:09:22 +00:00
Shariq Ansari
c83d7adddd
Merge pull request #868 from shariquerik/prettydate 2025-05-28 13:58:41 +05:30
Shariq Ansari
549665bc61 fix: use prettydate method instead of useTimeAgo 2025-05-28 13:50:01 +05:30
Pratik
7f5f43f0c2 style: fix dark mode styles 2025-05-27 05:22:30 +00:00
Pratik
af41469d58 feat: add list view & handle bulk delete, unlink 2025-05-26 15:24:24 +00:00
Shariq Ansari
43e1309bd8
Merge pull request #865 from shariquerik/form-script-fix 2025-05-26 17:56:12 +05:30
Shariq Ansari
91f7cf05fc fix: handle script load while setting up script 2025-05-26 17:50:24 +05:30
Shariq Ansari
875431a620 fix: moved setupHelperMethods from setupFormController to evaluateFormClass 2025-05-26 16:57:02 +05:30
Shariq Ansari
db0c0d98bc fix: pass getDoc function instead of document.doc to keep the reactivity 2025-05-26 16:46:24 +05:30
Shariq Ansari
5406f4a11b
Merge pull request #863 from shariquerik/convert-to-deal-script 2025-05-26 15:40:01 +05:30
Shariq Ansari
bfdd3273fe feat: intercept convert to deal via form script 2025-05-26 14:30:15 +05:30
Shariq Ansari
8798103e7e
Merge pull request #859 from frappe/pot_develop_2025-05-25 2025-05-26 12:08:46 +05:30
Shariq Ansari
203b5ab1ac
Merge branch 'develop' into pot_develop_2025-05-25 2025-05-26 12:04:31 +05:30
Shariq Ansari
ed1b26207b
Merge pull request #858 from shariquerik/create-call-log-script 2025-05-26 11:58:49 +05:30
frappe-pr-bot
e0166a08e2 chore: update POT file 2025-05-25 09:35:42 +00:00
Shariq Ansari
8af4e9b5e8 feat: intercept create lead from call log via form script 2025-05-23 21:49:12 +05:30
Shariq Ansari
900c1d3570
Merge pull request #856 from shariquerik/table-multiselect-fix 2025-05-23 20:39:42 +05:30
Shariq Ansari
b95a17a4e0 fix: set default value as empty array 2025-05-23 20:26:43 +05:30
Shariq Ansari
0f0b012a44
Merge pull request #849 from shariquerik/communication-date 2025-05-22 18:53:20 +05:30
Shariq Ansari
b291f82e4d fix: show communication date instead of creation 2025-05-22 18:13:07 +05:30
Pratik Badhe
86b7222916
Merge pull request #847 from pratikb64/filter-selected-filters 2025-05-22 16:41:57 +05:30
Pratik
7a12b80dd2 fix: hide selected filters from filter list 2025-05-22 10:50:39 +00:00
Pratik
4a836a58ee feat: handle bulk delete 2025-05-22 07:15:22 +00:00
Pratik
b47fc5b93b feat: handle linked docs while deleting 2025-05-21 14:20:48 +00:00
Shariq Ansari
f3b9103a51
Merge pull request #843 from shariquerik/about 2025-05-21 18:00:12 +05:30
Shariq Ansari
dc3ccdddd4 fix: added about link in standard_dropdown_items in hook.py 2025-05-21 17:56:54 +05:30
Shariq Ansari
807eb4a7d9 fix: removed doc & telegram link from user dropdown 2025-05-21 17:51:26 +05:30
Shariq Ansari
a24283eb5e feat: added action to open about modal in user dropdown 2025-05-21 17:50:53 +05:30
Shariq Ansari
fd7116b2e1 feat: show about details in about modal 2025-05-21 17:49:09 +05:30
Shariq Ansari
2e1289df28
Merge pull request #841 from shariquerik/update-toast 2025-05-20 14:37:38 +05:30
Shariq Ansari
6064ca5a4f fix: use toast.create api instead of createToast 2025-05-20 14:35:02 +05:30
Shariq Ansari
3db1b3c0f3 chore: update frappe-ui 2025-05-20 14:21:47 +05:30
Shariq Ansari
06ffa203ef
Merge pull request #838 from shariquerik/invite-member-fix-5 2025-05-20 14:09:38 +05:30
Shariq Ansari
dd1db8f782 fix: added update your password step in onboarding 2025-05-20 14:07:26 +05:30
Shariq Ansari
fe8e309399 feat: added password control 2025-05-20 14:07:15 +05:30
Shariq Ansari
e7a20374c7 fix: set default value as 0 in int field 2025-05-20 14:05:58 +05:30
Shariq Ansari
4cfa0f512b fix: do not show contacts in dropdown in invite member page 2025-05-20 14:05:47 +05:30
Shariq Ansari
64b4f6b759 fix: only set FCRM module if user is Sales User 2025-05-20 14:05:37 +05:30
Shariq Ansari
2d421e6052 fix: allow read permission for form script 2025-05-20 14:05:14 +05:30
Shariq Ansari
cd8dd683fa
Merge pull request #837 from frappe/revert-836-invite-member-fix-3 2025-05-20 13:54:44 +05:30
Shariq Ansari
a2bdc7ab93
Revert "fix: Invite Member Page" 2025-05-20 13:53:35 +05:30
Shariq Ansari
d4132c2411
Merge pull request #836 from shariquerik/invite-member-fix-3 2025-05-20 13:47:44 +05:30
Shariq Ansari
4c6e273268 fix: added update your password step in onboarding 2025-05-20 13:26:02 +05:30
Shariq Ansari
043f174e05 fix: updated components.d.ts 2025-05-20 13:24:42 +05:30
Shariq Ansari
26e9fac1ed feat: added password control 2025-05-20 13:23:26 +05:30
Shariq Ansari
88f33db249 fix: set default value as 0 in int field 2025-05-20 13:17:52 +05:30
Shariq Ansari
55a67bbc0c fix: do not show contacts in dropdown in invite member page 2025-05-20 13:17:20 +05:30
Shariq Ansari
08f042589d fix: only set FCRM module if user is Sales User 2025-05-20 13:16:58 +05:30
Shariq Ansari
52f540a014 fix: allow read permission for form script 2025-05-20 13:15:15 +05:30
Shariq Ansari
e85ef93480
Merge pull request #835 from frappe/revert-833-invite-member-fix-2 2025-05-20 13:09:32 +05:30
Shariq Ansari
a757f80263
Revert "fix: Invite Member Page" 2025-05-20 13:04:02 +05:30
Shariq Ansari
b9b8ff0e10
Merge pull request #833 from shariquerik/invite-member-fix-2 2025-05-20 12:47:27 +05:30
Shariq Ansari
e0aad074ec fix: added update your password step in onboarding 2025-05-19 21:58:03 +05:30
Shariq Ansari
ad88b4e046 feat: added password control 2025-05-19 21:02:10 +05:30
Shariq Ansari
5156814e7a fix: set default value as 0 in int field 2025-05-19 20:41:06 +05:30
Shariq Ansari
f988d16215 fix: use toast.create api instead of createToast 2025-05-19 20:40:11 +05:30
Shariq Ansari
f5a3fccad3 fix: do not show contacts in dropdown in invite member page 2025-05-19 19:05:37 +05:30
Shariq Ansari
e3f0079578 fix: only set FCRM module if user is Sales User 2025-05-19 18:02:30 +05:30
Shariq Ansari
b831ea3c47 fix: allow read permission for form script 2025-05-19 17:58:17 +05:30
Shariq Ansari
a88545b8b9
Merge pull request #831 from shariquerik/onboarding-fixes 2025-05-19 16:51:44 +05:30
Shariq Ansari
44523a0392 fix: store firstLead & firstDeal per user 2025-05-19 16:44:42 +05:30
Shariq Ansari
dbc207a9a6
Merge branch 'develop' into onboarding-fixes 2025-05-19 16:23:35 +05:30
Shariq Ansari
e68d861ee5
Merge pull request #828 from shariquerik/esm-toast 2025-05-19 16:21:16 +05:30
Shariq Ansari
7851bbadfa
Merge branch 'develop' into esm-toast 2025-05-19 16:13:55 +05:30
Shariq Ansari
9223d00af3
Merge pull request #826 from frappe/pot_develop_2025-05-18 2025-05-19 16:12:59 +05:30
Shariq Ansari
740c21532a fix: update Vue compiler options for custom lucide elements 2025-05-19 16:11:19 +05:30
Shariq Ansari
9fdd8bbc17 fix: add @tiptap/extension-paragraph dependency version 2.12.0 2025-05-19 15:56:43 +05:30
Shariq Ansari
0978fa58a2 fix: wrap layout and dialogs in FrappeUIProvider 2025-05-19 15:55:54 +05:30
Shariq Ansari
1395a12d32 build(deps): bump frappeui to 0.1.145 2025-05-19 15:55:37 +05:30
Shariq Ansari
9aab0e7417 fix: update package.json and config files to use ES module syntax 2025-05-19 15:55:07 +05:30
Shariq Ansari
ddc5810c71 fix: change heading to paragraph in invitation email template 2025-05-19 13:40:26 +05:30
Shariq Ansari
21c349e1d7 fix: added dependsOn value on dependent step to gray out 2025-05-19 13:39:06 +05:30
Shariq Ansari
a7784c2985 fix: get filtered steps based on condition 2025-05-19 13:06:38 +05:30
frappe-pr-bot
0cc69d90f0 chore: update POT file 2025-05-18 09:35:38 +00:00
Shariq Ansari
f125737d30
Merge pull request #821 from shariquerik/call-issue 2025-05-15 11:25:13 +05:30
Shariq Ansari
18aef2376a fix: cannot make call 2025-05-15 11:24:27 +05:30
Shariq Ansari
c8287ff107
Merge pull request #818 from shariquerik/contact-not-loading-1 2025-05-15 01:18:00 +05:30
Shariq Ansari
baf344a697 fix: remove updateField event from various components 2025-05-15 01:15:25 +05:30
Shariq Ansari
8c94049e3c fix: contact/organization page not loading 2025-05-15 01:01:48 +05:30
Shariq Ansari
646c76c3cb
Merge pull request #814 from shariquerik/product-details 2025-05-14 23:42:46 +05:30
Shariq Ansari
adbb9f5765 fix: pass doctype argument to get_product_details_script in create_product_details_script 2025-05-14 20:13:34 +05:30
Shariq Ansari
d3a6cc968f fix: add patch to create default scripts 2025-05-14 20:00:48 +05:30
Shariq Ansari
d6ff40cc6a chore: formatting fix 2025-05-14 19:58:39 +05:30
Shariq Ansari
fdd6c46b5f fix: create product detail script on install 2025-05-14 19:57:51 +05:30
Shariq Ansari
26c892c2a0 fix: added products table in crm lead 2025-05-14 19:57:09 +05:30
Shariq Ansari
3516e1ff44 fix: update field visibility logic and disable inputs based on read-only status 2025-05-14 19:08:29 +05:30
Shariq Ansari
0047077074 feat: enhance FormattedInput component with description slot and useAttrs for better attribute handling 2025-05-14 19:01:43 +05:30
Shariq Ansari
8459fac184 fix: set discount amount and net amount fields to read-only 2025-05-14 17:16:32 +05:30
Shariq Ansari
afe828f012 fix: update mandatory field indicator color and replace FormControl with FormattedInput for various field types 2025-05-14 16:55:19 +05:30
Shariq Ansari
60ed0a2043 fix: cache controller on document level not on doctype level 2025-05-14 15:21:47 +05:30
Shariq Ansari
2c9bc07dec fix: added default percent & int to 0 2025-05-14 15:21:07 +05:30
Shariq Ansari
91ba11b565 feat: added callback to update link field value after creating new 2025-05-14 14:04:25 +05:30
Shariq Ansari
8f79427720 fix: select text on focus 2025-05-14 13:34:21 +05:30
Shariq Ansari
32f3aaf38f fix: show formatted percent, currency & float only when not focused 2025-05-14 13:19:54 +05:30
Shariq Ansari
76aaf7f37d feat: added global create document modal for link field 2025-05-12 19:27:41 +05:30
Shariq Ansari
7d37c606cc fix: added columns for product code field 2025-05-12 17:51:36 +05:30
Shariq Ansari
6bce89f277 fix: right aligned number fields 2025-05-12 17:47:49 +05:30
Shariq Ansari
5420fcfe29 fix: render correct currency format 2025-05-12 17:45:05 +05:30
Shariq Ansari
8507c20481 fix: do not show qty and other fields 2025-05-12 17:20:28 +05:30
Shariq Ansari
914dd8bf93 fix: handle this.doc.getRow effectively 2025-05-12 16:37:33 +05:30
Shariq Ansari
960ebdc727 fix: handle field change for float, percent & currency 2025-05-12 16:34:48 +05:30
Shariq Ansari
74ef956638 fix: removed total quantity field 2025-05-12 16:32:09 +05:30
Shariq Ansari
a6323f42af fix: added logic to update amount, net amount, total and net total 2025-05-12 11:58:07 +05:30
Shariq Ansari
bc1c20c91f fix: added crm products table in crm deal and total field 2025-05-12 11:58:07 +05:30
Shariq Ansari
43297373ed fix: added crm product doctype 2025-05-12 11:58:07 +05:30
Shariq Ansari
5228755f7f fix: show formatted percent, currency & float in grid 2025-05-12 11:58:07 +05:30
Shariq Ansari
7ded0a0742 fix: show formatted percent, currency if read only 2025-05-12 11:53:03 +05:30
Shariq Ansari
d74ff9ab62
Merge pull request #811 from shariquerik/required-field-modal-fix 2025-05-12 11:30:32 +05:30
Shariq Ansari
6ef27106df
Merge branch 'develop' into required-field-modal-fix 2025-05-12 11:19:37 +05:30
Shariq Ansari
35a27101c1 fix: error if section is removed and saved 2025-05-12 11:18:47 +05:30
Shariq Ansari
6fbe75c8ad
Merge pull request #803 from frappe/pot_develop_2025-05-04 2025-05-09 20:30:58 +05:30
Shariq Ansari
89fd754efc
Merge pull request #806 from shariquerik/form-script-refactor 2025-05-09 20:24:49 +05:30
Shariq Ansari
576763fe5b fix: enhance error and warning messages with localization support 2025-05-09 18:00:46 +05:30
Shariq Ansari
c67ec08e1a fix: update toast messages for document update success and error handling 2025-05-09 17:53:28 +05:30
Shariq Ansari
6f49573f2f fix: add loading state check to prevent rendering issues in SidePanelLayout 2025-05-09 17:50:43 +05:30
Shariq Ansari
12c3290f19 fix: streamline trigger functions to use a unified handler for controller actions 2025-05-09 17:38:10 +05:30
Shariq Ansari
53c0706a3a feat: implement runSequentially utility for sequential function execution 2025-05-09 17:06:41 +05:30
Shariq Ansari
556386e446 fix: cache controllers and use Promise.all for concurrent execution 2025-05-09 15:22:40 +05:30
Shariq Ansari
07b2d9f792 fix: loop through controllers with multiple instances of multiple scripts and run trigger methods 2025-05-08 18:32:56 +05:30
Shariq Ansari
a2081da296 fix: provide array of instances in controllers if multiple script exist 2025-05-08 18:32:13 +05:30
Shariq Ansari
dde7db9489 fix: remove deprecated setupForm warning and error handling 2025-05-07 19:07:54 +05:30
Shariq Ansari
f947f55fc6 fix: do not show non value fields in dropdown 2025-05-07 19:05:10 +05:30
Shariq Ansari
7bbac6c703 fix: use dayjs for date field default value 2025-05-07 18:26:23 +05:30
Shariq Ansari
420ecb6147 fix: update all fields default value 2025-05-07 18:18:14 +05:30
Shariq Ansari
dcb2787498 feat: handle default value in grid 2025-05-07 18:12:22 +05:30
Shariq Ansari
336083a00f feat: added trigger function on row add & remove 2025-05-07 18:06:38 +05:30
Shariq Ansari
727d0a9acd fix: add doctype, idx, parent, parenttype & parentfield in new grid row 2025-05-07 16:59:22 +05:30
Shariq Ansari
29894ffcca fix: handle commented class declations 2025-05-07 16:38:01 +05:30
Shariq Ansari
e804fa39ba fix: exclude Float & Currency from read only formcontrol 2025-05-07 14:01:39 +05:30
Shariq Ansari
f866284240 fix: allow empty actions 2025-05-07 13:59:55 +05:30
Shariq Ansari
9e3124d29e fix: added triggerOnRefresh & getActions method 2025-05-07 12:15:49 +05:30
Shariq Ansari
d7e0eb09b3 fix: getRow should be available in parent & child instances 2025-05-07 12:14:47 +05:30
Shariq Ansari
5fcd447bc8 fix: added this.meta 2025-05-07 12:13:56 +05:30
Shariq Ansari
6f04b85663 fix: added this.doc.trigger & this.doc.getRow with row.trigger 2025-05-06 13:03:56 +05:30
Shariq Ansari
47262761fe fix: handle section.contacts also 2025-05-06 12:59:31 +05:30
frappe-pr-bot
b46e7a2185 chore: update POT file 2025-05-04 09:35:32 +00:00
Shariq Ansari
2d484c1ad2 fix: handle onchange of grid row field in modal 2025-05-03 15:35:10 +05:30
Shariq Ansari
275fa90a4d fix: added trigger method to call methods from same or different class instance 2025-05-02 18:25:51 +05:30
Shariq Ansari
f8956c70bf fix: handle onchange of grid row field 2025-05-02 16:56:57 +05:30
Shariq Ansari
39fa9c78f8 fix: parse multiple class in form script 2025-05-02 15:56:47 +05:30
Shariq Ansari
d96a29543e fix: added deprecation warning if using old formScript syntax 2025-05-02 08:03:42 +05:30
Shariq Ansari
d2d4abe91f fix: avoid none values 2025-05-02 07:28:40 +05:30
Shariq Ansari
5f567cf138 fix: added change emit in Table bulti select 2025-05-02 06:51:52 +05:30
Shariq Ansari
7bf7d94127 fix: added fieldChange method in almost all fieldtypes 2025-05-01 18:25:25 +05:30
Shariq Ansari
5b8d0d2aeb fix: check if script exist 2025-05-01 18:07:40 +05:30
Shariq Ansari
d37e585205 fix: trigger on change in Field & SidePanelLayout for Select field 2025-05-01 18:03:04 +05:30
Shariq Ansari
a30503ca5f fix: use document to load doc data in sidepanel layout 2025-05-01 18:01:53 +05:30
Shariq Ansari
e65899e384 fix: use document to load doc data in DataFields 2025-05-01 17:57:17 +05:30
Shariq Ansari
16a3f3d66c fix: created triggerOnChange method 2025-05-01 17:56:18 +05:30
Shariq Ansari
1e2f325c55 fix: setup form script in document.js 2025-05-01 17:55:54 +05:30
Shariq Ansari
ccd240f4e8 fix: created document composable to get any doctype record 2025-05-01 17:54:13 +05:30
Shariq Ansari
7b34c5eb66 fix: load script and setup class instances 2025-05-01 17:52:11 +05:30
Shariq Ansari
6da3761e76 fix: check if setupForm exist 2025-05-01 17:27:00 +05:30
Shariq Ansari
b03abdd2eb fix: get scripts api 2025-05-01 17:22:26 +05:30
Shariq Ansari
6ea4e985ef
Merge pull request #787 from frappe/pot_develop_2025-04-27 2025-04-28 12:28:29 +05:30
frappe-pr-bot
699d6cb08c chore: update POT file 2025-04-27 09:35:22 +00:00
Pratik Badhe
ac70deaf19
Merge pull request #781 from pratikb64/call-log-fix
fix: international call log issue
2025-04-23 16:12:59 +05:30
Pratik
4907db44eb fix: international call log issue 2025-04-23 15:54:54 +05:30
Pratik Badhe
81154d1f50
Merge pull request #776 from pratikb64/email-acc-localization
chore: add localization support for email account settings
2025-04-22 15:39:14 +05:30
Pratik
5eb46f6b6c chore: add localization support for email account settings 2025-04-22 15:33:28 +05:30
Shariq Ansari
001a6617f5
Merge pull request #771 from shariquerik/contact-not-loading 2025-04-22 13:11:42 +05:30
Shariq Ansari
c009373a43 fix: do not show error page while loading 2025-04-22 12:59:24 +05:30
Shariq Ansari
cef20e37c2 fix: contact page not loading 2025-04-22 12:57:20 +05:30
Shariq Ansari
20d16c6a32
Merge pull request #759 from frappe/pot_develop_2025-04-20 2025-04-21 14:36:29 +05:30
Shariq Ansari
2fc3daee70
Merge branch 'develop' into pot_develop_2025-04-20 2025-04-21 14:30:57 +05:30
Shariq Ansari
a7955ba9c5
Merge pull request #761 from shariquerik/data-tab-dirty-fix 2025-04-21 11:53:36 +05:30
Shariq Ansari
84e773eab9 fix: do not show error page while loading 2025-04-21 11:46:42 +05:30
Shariq Ansari
da4d3032be fix: mark data tab form dirty by watching field updates 2025-04-21 11:46:19 +05:30
frappe-pr-bot
d89e71ac2f chore: update POT file 2025-04-20 09:35:21 +00:00
Pratik Badhe
de806ee6d9
Merge pull request #753 from pratikb64/email-account-dark-mode
fix: dark mode email account css
2025-04-16 18:10:27 +05:30
Pratik
9c45877999 fix: dark mode email account css 2025-04-16 18:00:28 +05:30
Shariq Ansari
2059ecdb40
Merge pull request #726 from pratikb64/fix-export-logic 2025-04-14 11:19:59 +05:30
Shariq Ansari
52d66b5de4
Merge branch 'develop' into fix-export-logic 2025-04-14 11:15:25 +05:30
Shariq Ansari
fb9b026ad6 fix: restrict app in apps page if no access to FCRM module 2025-04-14 11:05:43 +05:30
Shariq Ansari
8f1b6f6b67
Merge pull request #742 from shariquerik/restrict-app-if-no-module-access-2 2025-04-14 10:36:12 +05:30
Shariq Ansari
0bd448a399 revert: restrict app in apps page if no access to FCRM module 2025-04-14 10:35:28 +05:30
Shariq Ansari
2b395a05ea
Merge pull request #734 from frappe/pot_develop_2025-04-13 2025-04-13 20:14:27 +05:30
Shariq Ansari
dce17de000
Merge pull request #735 from shariquerik/restrict-app-if-no-module-access-1 2025-04-13 20:07:47 +05:30
Shariq Ansari
3881179f72 fix: restrict app in apps page if no access to FCRM module 2025-04-13 19:59:23 +05:30
frappe-pr-bot
da0a502756 chore: update POT file 2025-04-13 09:36:51 +00:00
Pratik
cbf00e29ac refactor: make function names clearer 2025-04-11 18:09:15 +05:30
Pratik
a466766c5c refactor: remove unnecessary watchers 2025-04-08 18:22:44 +05:30
Shariq Ansari
a4781509c4
Merge branch 'develop' into fix-export-logic 2025-04-08 16:37:26 +05:30
Shariq Ansari
8a9361d822 revert: module validation 2025-04-08 16:01:23 +05:30
Shariq Ansari
e2522a492a
Merge pull request #728 from shariquerik/restrict-doc-access
fix: added ErrorPage if user does not have access to doc
2025-04-08 15:41:10 +05:30
Shariq Ansari
bab551c511
Merge branch 'develop' into restrict-doc-access 2025-04-08 15:39:37 +05:30
Shariq Ansari
c63bb16704 ci: added backport to main-hotfix ci 2025-04-08 15:36:32 +05:30
Shariq Ansari
fa56dc4791 fix: show error page if there is no access 2025-04-08 15:28:54 +05:30
Shariq Ansari
e92ee3b730 fix: check read access before loading data 2025-04-08 15:28:19 +05:30
Shariq Ansari
bb794f4887 fix: added ErrorPage component 2025-04-08 15:27:50 +05:30
Pratik
a227389e3e fix: export logic 2025-04-08 15:07:27 +05:30
Shariq Ansari
d9f0b067ca
Merge pull request #722 from shariquerik/added-mergify
ci: added mergify.yml for backport
2025-04-07 21:17:59 +05:30
Shariq Ansari
c0b708462a ci: added mergify.yml for backport 2025-04-07 18:00:59 +05:30
Shariq Ansari
adb0dfff47
Merge pull request #721 from shariquerik/restrict-app-if-no-module-access
fix: restrict app in apps page if no access to FCRM module
2025-04-07 17:37:02 +05:30
Shariq Ansari
6139cb5cb9 fix: restrict app in apps page if no access to FCRM module 2025-04-07 17:31:17 +05:30
Shariq Ansari
61d7924c54
Merge pull request #701 from frappe/pot_develop_2025-03-30
chore: update POT file
2025-04-07 16:51:16 +05:30
Shariq Ansari
899b09ac40
Merge branch 'develop' into pot_develop_2025-03-30 2025-04-07 16:51:07 +05:30
Shariq Ansari
debc9fc1cb
Merge pull request #716 from shariquerik/make-create-call
fix: Create & Make call
2025-04-07 16:49:38 +05:30
Shariq Ansari
5c76adedf3
Merge pull request #712 from shariquerik/dynamic-link
feat: Dynamic Link field support
2025-04-07 16:49:30 +05:30
Shariq Ansari
1ebb26e4c2
Merge pull request #708 from frappe/pot_develop_2025-04-06
chore: update POT file
2025-04-07 16:44:59 +05:30
Shariq Ansari
67378c1f52
Merge pull request #719 from pratikb64/default-assigned-to
fix: default "assigned to" in deals and leads list view
2025-04-07 16:44:32 +05:30
Pratik
469a22ef5f fix: default "assigned to" in deals and leads list view 2025-04-07 16:37:19 +05:30
Shariq Ansari
fdceb51fdc fix: added multi action button to make and create call 2025-04-07 15:34:46 +05:30
Shariq Ansari
97a132e05f fix: show call tab always 2025-04-07 15:32:34 +05:30
Shariq Ansari
26fabddcbe fix: handle feather icon in multi action button 2025-04-07 15:32:09 +05:30
Shariq Ansari
40370067b2 fix: dynamic variant 2025-04-07 14:13:55 +05:30
Shariq Ansari
f0bf6962e7 fix: do not show dropdown if only one option 2025-04-07 14:07:41 +05:30
Shariq Ansari
3b432a0209 fix: added multi action button 2025-04-07 13:58:58 +05:30
Shariq Ansari
c7a03922a0 feat: Dynamic Link field support 2025-04-07 13:16:52 +05:30
frappe-pr-bot
e70b4c091e chore: update POT file 2025-04-06 09:35:28 +00:00
Pratik Badhe
7e38d5e405
Merge pull request #707 from pratikb64/kanban-filter-fix
fix: kanban filter
2025-04-04 17:14:46 +05:30
Pratik
f810e82b45 fix: kanban filter 2025-04-04 17:07:54 +05:30
Pratik Badhe
dff9f93a6b
Merge pull request #704 from pratikb64/make-fields-mandatory
fix: add mandatory fields
2025-04-04 10:26:29 +05:30
Shariq Ansari
c4109ad6ac build(deps): bump frappeui to 0.1.123 2025-04-04 10:09:18 +05:30
Pratik
7a6efb900e fix: add mandatory fields 2025-04-01 17:26:46 +05:30
frappe-pr-bot
e080e47a35 chore: update POT file 2025-03-30 09:35:00 +00:00
Pratik Badhe
82599f91d8
Merge pull request #698 from pratikb64/email-settings-fix
fix: ui alignment
2025-03-28 15:34:36 +05:30
Pratik
8fa156f625 fix: ui alignment 2025-03-28 15:33:40 +05:30
Pratik Badhe
55112cefa9
Merge pull request #697 from pratikb64/email-setting-fix
fix: broken images
2025-03-27 17:38:28 +05:30
Pratik
152c7c8a91 fix: broken images 2025-03-27 17:37:39 +05:30
Pratik Badhe
aa1c0da80e
Merge pull request #696 from pratikb64/add-email-setting
feat: add email account
2025-03-27 15:33:20 +05:30
Pratik
87174f207d feat: add email account 2025-03-27 15:32:37 +05:30
Shariq Ansari
400f879d29 fix: only allow invite by email for Sales Manager & Sales User role 2025-03-26 14:44:40 +05:30
319 changed files with 155024 additions and 25094 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

45
.mergify.yml Normal file
View File

@ -0,0 +1,45 @@
pull_request_rules:
- name: Auto-close PRs on stable branch
conditions:
- and:
- and:
- author!=shariquerik
- author!=frappe-pr-bot
- author!=mergify[bot]
- or:
- base=main
actions:
close:
comment:
message: |
@{{author}}, thanks for the contribution, but we do not accept pull requests on a stable branch. Please raise PR on develop branch.
- name: backport to develop
conditions:
- label="backport develop"
actions:
backport:
branches:
- develop
assignees:
- "{{ author }}"
- name: backport to main-hotfix
conditions:
- label="backport main-hotfix"
actions:
backport:
branches:
- main-hotfix
assignees:
- "{{ author }}"
- name: backport to main
conditions:
- label="backport main"
actions:
backport:
branches:
- main
assignees:
- "{{ author }}"

View File

@ -8,7 +8,7 @@
**Simplify Sales, Amplify Relationships**
![GitHub release (latest by date)](https://img.shields.io/github/v/release/frappe/crm)
[![GitHub release (latest by date)](https://img.shields.io/github/v/release/frappe/crm)](https://github.com/frappe/crm/releases)
<div>
<picture>
@ -84,6 +84,14 @@ The motivation behind building Frappe CRM stems from the need for a simple, cust
- [Frappe Framework](https://github.com/frappe/frappe): A full-stack web application framework.
- [Frappe UI](https://github.com/frappe/frappe-ui): A Vue-based UI library, to provide a modern user interface.
### Compatibility
This app is compatible with the following versions of Frappe and ERPNext:
| CRM branch | Stability | Frappe branch | ERPNext branch |
| :-------------------- | :-------- | :------------------- | :------------------- |
| main - v1.x | stable | v15.x | v15.x |
| develop - future/v2.x | unstable | develop - future/v16 | develop - future/v16 |
## Getting Started (Production)
### Managed Hosting
@ -181,6 +189,7 @@ You need Docker, docker-compose and git setup on your machine. Refer [Docker doc
- [Discuss Forum](https://discuss.frappe.io/c/frappe-crm)
- [Documentation](https://docs.frappe.io/crm)
- [YouTube](https://www.youtube.com/channel/UCn3bV5kx77HsVwtnlCeEi_A)
- [X/Twitter](https://x.com/frappetech)
<br>
<br>

View File

@ -1,9 +1,10 @@
from bs4 import BeautifulSoup
import frappe
from frappe.translate import get_all_translations
from frappe.utils import validate_email_address, split_emails, cstr
from frappe.utils.telemetry import POSTHOG_HOST_FIELD, POSTHOG_PROJECT_FIELD
from bs4 import BeautifulSoup
from frappe.core.api.file import get_max_file_size
from frappe.translate import get_all_translations
from frappe.utils import cstr, split_emails, validate_email_address
from frappe.utils.modules import get_modules_from_all_apps_for_user
from frappe.utils.telemetry import POSTHOG_HOST_FIELD, POSTHOG_PROJECT_FIELD
@frappe.whitelist(allow_guest=True)
@ -63,9 +64,14 @@ def check_app_permission():
if frappe.session.user == "Administrator":
return True
allowed_modules = get_modules_from_all_apps_for_user()
allowed_modules = [x["module_name"] for x in allowed_modules]
if "FCRM" not in allowed_modules:
return False
roles = frappe.get_roles()
if any(
role in ["System Manager", "Sales User", "Sales Manager", "Sales Master Manager"] for role in roles
role in ["System Manager", "Sales User", "Sales Manager"] for role in roles
):
return True
@ -93,9 +99,14 @@ def accept_invitation(key: str | None = None):
@frappe.whitelist()
def invite_by_email(emails: str, role: str):
frappe.only_for("Sales Manager")
frappe.only_for(["Sales Manager", "System Manager"])
if role not in ["System Manager", "Sales Manager", "Sales User"]:
frappe.throw("Cannot invite for this role")
if not emails:
return
email_string = validate_email_address(emails, throw=False)
email_list = split_emails(email_string)
if not email_list:
@ -103,7 +114,10 @@ def invite_by_email(emails: str, role: str):
existing_members = frappe.db.get_all("User", filters={"email": ["in", email_list]}, pluck="email")
existing_invites = frappe.db.get_all(
"CRM Invitation",
filters={"email": ["in", email_list], "role": ["in", ["Sales Manager", "Sales User"]]},
filters={
"email": ["in", email_list],
"role": ["in", ["System Manager", "Sales Manager", "Sales User"]],
},
pluck="email",
)
@ -112,6 +126,12 @@ def invite_by_email(emails: str, role: str):
for email in to_invite:
frappe.get_doc(doctype="CRM Invitation", email=email, role=role).insert(ignore_permissions=True)
return {
"existing_members": existing_members,
"existing_invites": existing_invites,
"to_invite": to_invite,
}
@frappe.whitelist()
def get_file_uploader_defaults(doctype: str):

View File

@ -124,6 +124,7 @@ def get_deal_activities(name):
activity = {
"activity_type": "communication",
"communication_type": communication.communication_type,
"communication_date": communication.communication_date or communication.creation,
"creation": communication.creation,
"data": {
"subject": communication.subject,
@ -255,6 +256,7 @@ def get_lead_activities(name):
activity = {
"activity_type": "communication",
"communication_type": communication.communication_type,
"communication_date": communication.communication_date or communication.creation,
"creation": communication.creation,
"data": {
"subject": communication.subject,

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

@ -14,32 +14,16 @@ def update_deals_email_mobile_no(doc):
)
for linked_deal in linked_deals:
deal = frappe.get_cached_doc("CRM Deal", linked_deal.parent)
deal = frappe.db.get_values("CRM Deal", linked_deal.parent, ["email", "mobile_no"], as_dict=True)[0]
if deal.email != doc.email_id or deal.mobile_no != doc.mobile_no:
deal.email = doc.email_id
deal.mobile_no = doc.mobile_no
deal.save(ignore_permissions=True)
@frappe.whitelist()
def get_contact(name):
Contact = frappe.qb.DocType("Contact")
query = frappe.qb.from_(Contact).select("*").where(Contact.name == name).limit(1)
contact = query.run(as_dict=True)
if not len(contact):
frappe.throw(_("Contact not found"), frappe.DoesNotExistError)
contact = contact.pop()
contact["doctype"] = "Contact"
contact["email_ids"] = frappe.get_all(
"Contact Email", filters={"parent": name}, fields=["name", "email_id", "is_primary"]
frappe.db.set_value(
"CRM Deal",
linked_deal.parent,
{
"email": doc.email_id,
"mobile_no": doc.mobile_no,
},
)
contact["phone_nos"] = frappe.get_all(
"Contact Phone", filters={"parent": name}, fields=["name", "phone", "is_primary_mobile_no"]
)
return contact
@frappe.whitelist()

1142
crm/api/dashboard.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -3,6 +3,7 @@ import json
import frappe
from frappe import _
from frappe.custom.doctype.property_setter.property_setter import make_property_setter
from frappe.desk.form.assign_to import set_status
from frappe.model import no_value_fields
from frappe.model.document import get_controller
from frappe.utils import make_filter_tuple
@ -10,6 +11,7 @@ from pypika import Criterion
from crm.api.views import get_views
from crm.fcrm.doctype.crm_form_script.crm_form_script import get_form_script
from crm.utils import get_dynamic_linked_docs, get_linked_docs
@frappe.whitelist()
@ -418,16 +420,23 @@ def get_data(
rows.append(field)
for kc in kanban_columns:
column_filters = {column_field: kc.get("name")}
# Start with base filters
column_filters = []
# Convert and add the main filters first
if filters:
base_filters = convert_filter_to_tuple(doctype, filters)
column_filters.extend(base_filters)
# Add the column-specific filter
if column_field and kc.get("name"):
column_filters.append([doctype, column_field, "=", kc.get("name")])
order = kc.get("order")
if (column_field in filters and filters.get(column_field) != kc.get("name")) or kc.get("delete"):
if kc.get("delete"):
column_data = []
else:
column_filters.update(filters.copy())
page_length = 20
if kc.get("page_length"):
page_length = kc.get("page_length")
page_length = kc.get("page_length", 20)
if order:
column_data = get_records_based_on_order(
@ -437,26 +446,20 @@ def get_data(
column_data = frappe.get_list(
doctype,
fields=rows,
filters=convert_filter_to_tuple(doctype, column_filters),
filters=column_filters,
order_by=order_by,
page_length=page_length,
)
new_filters = filters.copy()
new_filters.update({column_field: kc.get("name")})
all_count = frappe.get_list(
doctype,
filters=convert_filter_to_tuple(doctype, new_filters),
filters=column_filters,
fields="count(*) as total_count",
)[0].total_count
kc["all_count"] = all_count
kc["count"] = len(column_data)
for d in column_data:
getCounts(d, doctype)
if order:
column_data = sorted(
column_data,
@ -658,6 +661,25 @@ def get_fields_meta(doctype, restricted_fieldtypes=None, as_array=False, only_re
return fields_meta
@frappe.whitelist()
def remove_assignments(doctype, name, assignees, ignore_permissions=False):
assignees = frappe.parse_json(assignees)
if not assignees:
return
for assign_to in assignees:
set_status(
doctype,
name,
todo=None,
assign_to=assign_to,
status="Cancelled",
ignore_permissions=ignore_permissions,
)
@frappe.whitelist()
def get_assigned_users(doctype, name, default_assigned_to=None):
assigned_users = frappe.get_all(
"ToDo",
@ -725,3 +747,167 @@ def getCounts(d, doctype):
"FCRM Note", filters={"reference_doctype": doctype, "reference_docname": d.get("name")}
)
return d
@frappe.whitelist()
def get_linked_docs_of_document(doctype, docname):
try:
doc = frappe.get_doc(doctype, docname)
except frappe.DoesNotExistError:
return []
linked_docs = get_linked_docs(doc)
dynamic_linked_docs = get_dynamic_linked_docs(doc)
linked_docs.extend(dynamic_linked_docs)
linked_docs = list({doc["reference_docname"]: doc for doc in linked_docs}.values())
docs_data = []
for doc in linked_docs:
if not doc.get("reference_doctype") or not doc.get("reference_docname"):
continue
try:
data = frappe.get_doc(doc["reference_doctype"], doc["reference_docname"])
except (frappe.DoesNotExistError, frappe.ValidationError):
continue
title = data.get("title")
if data.doctype == "CRM Call Log":
title = f"Call from {data.get('from')} to {data.get('to')}"
if data.doctype == "CRM Deal":
title = data.get("organization")
if data.doctype == "CRM Notification":
title = data.get("message")
docs_data.append(
{
"doc": data.doctype,
"title": title or data.get("name"),
"reference_docname": doc["reference_docname"],
"reference_doctype": doc["reference_doctype"],
}
)
return docs_data
def remove_doc_link(doctype, docname):
if not doctype or not docname:
return
try:
linked_doc_data = frappe.get_doc(doctype, docname)
if doctype == "CRM Notification":
delete_notification_type = {
"notification_type_doctype": "",
"notification_type_doc": "",
}
delete_references = {
"reference_doctype": "",
"reference_name": "",
}
if linked_doc_data.get("notification_type_doctype") == linked_doc_data.get("reference_doctype"):
delete_references.update(delete_notification_type)
linked_doc_data.update(delete_references)
else:
linked_doc_data.update(
{
"reference_doctype": "",
"reference_docname": "",
}
)
linked_doc_data.save(ignore_permissions=True)
except (frappe.DoesNotExistError, frappe.ValidationError):
pass
def remove_contact_link(doctype, docname):
if not doctype or not docname:
return
try:
linked_doc_data = frappe.get_doc(doctype, docname)
linked_doc_data.update(
{
"contact": None,
"contacts": [],
}
)
linked_doc_data.save(ignore_permissions=True)
except (frappe.DoesNotExistError, frappe.ValidationError):
pass
@frappe.whitelist()
def remove_linked_doc_reference(items, remove_contact=None, delete=False):
if isinstance(items, str):
items = frappe.parse_json(items)
for item in items:
if not item.get("doctype") or not item.get("docname"):
continue
try:
if remove_contact:
remove_contact_link(item["doctype"], item["docname"])
else:
remove_doc_link(item["doctype"], item["docname"])
if delete:
frappe.delete_doc(item["doctype"], item["docname"])
except (frappe.DoesNotExistError, frappe.ValidationError):
# Skip if document doesn't exist or has validation errors
continue
return "success"
@frappe.whitelist()
def delete_bulk_docs(doctype, items, delete_linked=False):
from frappe.desk.reportview import delete_bulk
if not doctype:
frappe.throw("Doctype is required")
if not items:
frappe.throw("Items are required")
items = frappe.parse_json(items)
if not isinstance(items, list):
frappe.throw("Items must be a list")
for doc in items:
try:
if not frappe.db.exists(doctype, doc):
frappe.log_error(f"Document {doctype} {doc} does not exist", "Bulk Delete Error")
continue
linked_docs = get_linked_docs_of_document(doctype, doc)
for linked_doc in linked_docs:
if not linked_doc.get("reference_doctype") or not linked_doc.get("reference_docname"):
continue
remove_linked_doc_reference(
[
{
"doctype": linked_doc["reference_doctype"],
"docname": linked_doc["reference_docname"],
}
],
remove_contact=doctype == "Contact",
delete=delete_linked,
)
except Exception as e:
frappe.log_error(
f"Error processing linked docs for {doctype} {doc}: {str(e)}", "Bulk Delete Error"
)
if len(items) > 10:
frappe.enqueue("frappe.desk.reportview.delete_bulk", doctype=doctype, items=items)
else:
delete_bulk(doctype, items)
return "success"

View File

@ -23,11 +23,32 @@ def get_users():
if frappe.session.user == user.name:
user.session_user = True
user.is_manager = "Sales Manager" in frappe.get_roles(user.name) or user.name == "Administrator"
user.roles = frappe.get_roles(user.name)
user.is_agent = frappe.db.exists("CRM Telephony Agent", {"user": user.name})
user.role = ""
return users
if "System Manager" in user.roles:
user.role = "System Manager"
elif "Sales Manager" in user.roles:
user.role = "Sales Manager"
elif "Sales User" in user.roles:
user.role = "Sales User"
elif "Guest" in user.roles:
user.role = "Guest"
if frappe.session.user == user.name:
user.session_user = True
user.is_telephony_agent = frappe.db.exists("CRM Telephony Agent", {"user": user.name})
crm_users = []
# crm users are users with role Sales User or Sales Manager
for user in users:
if "Sales User" in user.roles or "Sales Manager" in user.roles:
crm_users.append(user)
return users, crm_users
@frappe.whitelist()

99
crm/api/settings.py Normal file
View File

@ -0,0 +1,99 @@
import frappe
@frappe.whitelist()
def create_email_account(data):
service = data.get("service")
service_config = email_service_config.get(service)
if not service_config:
return "Service not supported"
try:
email_doc = frappe.get_doc(
{
"doctype": "Email Account",
"email_id": data.get("email_id"),
"email_account_name": data.get("email_account_name"),
"service": service,
"enable_incoming": data.get("enable_incoming"),
"enable_outgoing": data.get("enable_outgoing"),
"default_incoming": data.get("default_incoming"),
"default_outgoing": data.get("default_outgoing"),
"email_sync_option": "ALL",
"initial_sync_count": 100,
"create_contact": 1,
"track_email_status": 1,
"use_tls": 1,
"use_imap": 1,
"smtp_port": 587,
**service_config,
}
)
if service == "Frappe Mail":
email_doc.api_key = data.get("api_key")
email_doc.api_secret = data.get("api_secret")
email_doc.frappe_mail_site = data.get("frappe_mail_site")
email_doc.append_to = "CRM Lead"
else:
email_doc.append("imap_folder", {"append_to": "CRM Lead", "folder_name": "INBOX"})
email_doc.password = data.get("password")
# validate whether the credentials are correct
email_doc.get_incoming_server()
# if correct credentials, save the email account
email_doc.save()
except Exception as e:
frappe.throw(str(e))
email_service_config = {
"Frappe Mail": {
"domain": None,
"password": None,
"awaiting_password": 0,
"ascii_encode_password": 0,
"login_id_is_different": 0,
"login_id": None,
"use_imap": 0,
"use_ssl": 0,
"validate_ssl_certificate": 0,
"use_starttls": 0,
"email_server": None,
"incoming_port": 0,
"always_use_account_email_id_as_sender": 1,
"use_tls": 0,
"use_ssl_for_outgoing": 0,
"smtp_server": None,
"smtp_port": None,
"no_smtp_authentication": 0,
},
"GMail": {
"email_server": "imap.gmail.com",
"use_ssl": 1,
"smtp_server": "smtp.gmail.com",
},
"Outlook": {
"email_server": "imap-mail.outlook.com",
"use_ssl": 1,
"smtp_server": "smtp-mail.outlook.com",
},
"Sendgrid": {
"smtp_server": "smtp.sendgrid.net",
"smtp_port": 587,
},
"SparkPost": {
"smtp_server": "smtp.sparkpostmail.com",
},
"Yahoo": {
"email_server": "imap.mail.yahoo.com",
"use_ssl": 1,
"smtp_server": "smtp.mail.yahoo.com",
"smtp_port": 587,
},
"Yandex": {
"email_server": "imap.yandex.com",
"use_ssl": 1,
"smtp_server": "smtp.yandex.com",
"smtp_port": 587,
},
}

View File

@ -1,28 +1,19 @@
import frappe
from frappe import _
from crm.fcrm.doctype.crm_notification.crm_notification import notify_user
def after_insert(doc, method):
if (
doc.reference_type in ["CRM Lead", "CRM Deal"]
and doc.reference_name
and doc.allocated_to
):
if doc.reference_type in ["CRM Lead", "CRM Deal"] and doc.reference_name and doc.allocated_to:
fieldname = "lead_owner" if doc.reference_type == "CRM Lead" else "deal_owner"
lead_owner = frappe.db.get_value(
doc.reference_type, doc.reference_name, fieldname
)
if not lead_owner:
owner = frappe.db.get_value(doc.reference_type, doc.reference_name, fieldname)
if not owner:
frappe.db.set_value(
doc.reference_type, doc.reference_name, fieldname, doc.allocated_to
doc.reference_type, doc.reference_name, fieldname, doc.allocated_to, update_modified=False
)
if (
doc.reference_type in ["CRM Lead", "CRM Deal", "CRM Task"]
and doc.reference_name
and doc.allocated_to
):
if doc.reference_type in ["CRM Lead", "CRM Deal", "CRM Task"] and doc.reference_name and doc.allocated_to:
notify_assigned_user(doc)
@ -47,9 +38,7 @@ def notify_assigned_user(doc, is_cancelled=False):
doc.reference_type, doc.reference_name, owner
)
if is_cancelled
else _("{0} assigned a {1} {2} to you").format(
owner, doc.reference_type, doc.reference_name
)
else _("{0} assigned a {1} {2} to you").format(owner, doc.reference_type, doc.reference_name)
)
redirect_to_doctype, redirect_to_name = get_redirect_to_doc(doc)

84
crm/api/user.py Normal file
View File

@ -0,0 +1,84 @@
import frappe
@frappe.whitelist()
def add_existing_users(users, role="Sales User"):
"""
Add existing users to the CRM by assigning them a role (Sales User or Sales Manager).
:param users: List of user names to be added
"""
frappe.only_for(["System Manager", "Sales Manager"])
users = frappe.parse_json(users)
for user in users:
add_user(user, role)
@frappe.whitelist()
def update_user_role(user, new_role):
"""
Update the role of the user to Sales Manager, Sales User, or System Manager.
:param user: The name of the user
:param new_role: The new role to assign (Sales Manager or Sales User)
"""
frappe.only_for(["System Manager", "Sales Manager"])
if new_role not in ["System Manager", "Sales Manager", "Sales User"]:
frappe.throw("Cannot assign this role")
user_doc = frappe.get_doc("User", user)
if new_role == "System Manager":
user_doc.append_roles("System Manager", "Sales Manager", "Sales User")
user_doc.set("block_modules", [])
if new_role == "Sales Manager":
user_doc.append_roles("Sales Manager", "Sales User")
user_doc.remove_roles("System Manager")
if new_role == "Sales User":
user_doc.append_roles("Sales User")
user_doc.remove_roles("Sales Manager", "System Manager")
update_module_in_user(user_doc, "FCRM")
user_doc.save(ignore_permissions=True)
@frappe.whitelist()
def add_user(user, role):
"""
Add a user means adding role (Sales User or/and Sales Manager) to the user.
:param user: The name of the user to be added
:param role: The role to be assigned (Sales User or Sales Manager)
"""
update_user_role(user, role)
@frappe.whitelist()
def remove_user(user):
"""
Remove a user means removing Sales User & Sales Manager roles from the user.
:param user: The name of the user to be removed
"""
frappe.only_for(["System Manager", "Sales Manager"])
user_doc = frappe.get_doc("User", user)
roles = [d.role for d in user_doc.roles]
if "Sales User" in roles:
user_doc.remove_roles("Sales User")
if "Sales Manager" in roles:
user_doc.remove_roles("Sales Manager")
user_doc.save(ignore_permissions=True)
frappe.msgprint(f"User {user} has been removed from CRM roles.")
def update_module_in_user(user, module):
block_modules = frappe.get_all(
"Module Def",
fields=["name as module"],
filters={"name": ["!=", module]},
)
if block_modules:
user.set("block_modules", block_modules)

View File

@ -10,6 +10,13 @@ from crm.fcrm.doctype.crm_notification.crm_notification import notify_user
def validate(doc, method):
if doc.type == "Incoming" and doc.get("from"):
name, doctype = get_lead_or_deal_from_number(doc.get("from"))
if name != None:
doc.reference_doctype = doctype
doc.reference_name = name
if doc.type == "Outgoing" and doc.get("to"):
name, doctype = get_lead_or_deal_from_number(doc.get("to"))
if name != None:
doc.reference_doctype = doctype
doc.reference_name = name
@ -29,7 +36,7 @@ def on_update(doc, method):
def notify_agent(doc):
if doc.type == "Incoming":
doctype = doc.reference_doctype
if doctype.startswith("CRM "):
if doctype and doctype.startswith("CRM "):
doctype = doctype[4:].lower()
notification_text = f"""
<div class="mb-2 leading-5 text-ink-gray-5">
@ -335,5 +342,5 @@ def get_from_name(message):
else:
from_name = doc.get("lead_name")
else:
from_name = doc.get("first_name") + " " + doc.get("last_name")
from_name = " ".join(filter(None, [doc.get("first_name"), doc.get("last_name")]))
return from_name

View File

@ -41,13 +41,15 @@
"fieldname": "from",
"fieldtype": "Data",
"in_list_view": 1,
"label": "From"
"label": "From",
"reqd": 1
},
{
"fieldname": "status",
"fieldtype": "Select",
"label": "Status",
"options": "Initiated\nRinging\nIn Progress\nCompleted\nFailed\nBusy\nNo Answer\nQueued\nCanceled"
"options": "Initiated\nRinging\nIn Progress\nCompleted\nFailed\nBusy\nNo Answer\nQueued\nCanceled",
"reqd": 1
},
{
"fieldname": "start_time",
@ -69,13 +71,15 @@
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Type",
"options": "Incoming\nOutgoing"
"options": "Incoming\nOutgoing",
"reqd": 1
},
{
"fieldname": "to",
"fieldtype": "Data",
"in_list_view": 1,
"label": "To"
"label": "To",
"reqd": 1
},
{
"description": "Call duration in seconds",
@ -153,7 +157,7 @@
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2025-01-22 17:57:59.289548",
"modified": "2025-04-01 16:01:54.479309",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Call Log",

View File

@ -190,11 +190,20 @@ def get_call_log(name):
@frappe.whitelist()
def create_lead_from_call_log(call_log):
def create_lead_from_call_log(call_log, lead_details=None):
lead = frappe.new_doc("CRM Lead")
lead.first_name = "Lead from call " + call_log.get("from")
lead.mobile_no = call_log.get("from")
lead.lead_owner = frappe.session.user
lead_details = frappe.parse_json(lead_details or "{}")
if not lead_details.get("lead_owner"):
lead_details["lead_owner"] = frappe.session.user
if not lead_details.get("mobile_no"):
lead_details["mobile_no"] = call_log.get("from") or ""
if not lead_details.get("first_name"):
lead_details["first_name"] = "Lead from call " + (
lead_details.get("mobile_no") or call_log.get("name")
)
lead.update(lead_details)
lead.save(ignore_permissions=True)
# link call log with lead

View File

@ -0,0 +1,8 @@
// Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
// frappe.ui.form.on("CRM Dashboard", {
// refresh(frm) {
// },
// });

View File

@ -0,0 +1,105 @@
{
"actions": [],
"allow_rename": 1,
"autoname": "field:title",
"creation": "2025-07-14 12:19:49.725022",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"title",
"private",
"column_break_exbw",
"user",
"section_break_hfza",
"layout"
],
"fields": [
{
"fieldname": "column_break_exbw",
"fieldtype": "Column Break"
},
{
"fieldname": "section_break_hfza",
"fieldtype": "Section Break"
},
{
"default": "[]",
"fieldname": "layout",
"fieldtype": "Code",
"label": "Layout",
"options": "JSON"
},
{
"fieldname": "title",
"fieldtype": "Data",
"label": "Name",
"unique": 1
},
{
"depends_on": "private",
"fieldname": "user",
"fieldtype": "Link",
"label": "User",
"mandatory_depends_on": "private",
"options": "User"
},
{
"default": "0",
"fieldname": "private",
"fieldtype": "Check",
"label": "Private"
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2025-07-14 12:36:10.831351",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Dashboard",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales User",
"share": 1,
"write": 1
}
],
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": [],
"title_field": "title"
}

View File

@ -0,0 +1,34 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import frappe
from frappe import _
from frappe.model.document import Document
class CRMDashboard(Document):
pass
def default_manager_dashboard_layout():
"""
Returns the default layout for the CRM Manager Dashboard.
"""
return '[{"name":"total_leads","type":"number_chart","tooltip":"Total number of leads","layout":{"x":0,"y":0,"w":4,"h":3,"i":"total_leads"}},{"name":"ongoing_deals","type":"number_chart","tooltip":"Total number of ongoing deals","layout":{"x":8,"y":0,"w":4,"h":3,"i":"ongoing_deals"}},{"name":"won_deals","type":"number_chart","tooltip":"Total number of won deals","layout":{"x":12,"y":0,"w":4,"h":3,"i":"won_deals"}},{"name":"average_won_deal_value","type":"number_chart","tooltip":"Average value of won deals","layout":{"x":16,"y":0,"w":4,"h":3,"i":"average_won_deal_value"}},{"name":"average_deal_value","type":"number_chart","tooltip":"Average deal value of ongoing and won deals","layout":{"x":0,"y":2,"w":4,"h":3,"i":"average_deal_value"}},{"name":"average_time_to_close_a_lead","type":"number_chart","tooltip":"Average time taken to close a lead","layout":{"x":4,"y":0,"w":4,"h":3,"i":"average_time_to_close_a_lead"}},{"name":"average_time_to_close_a_deal","type":"number_chart","layout":{"x":4,"y":2,"w":4,"h":3,"i":"average_time_to_close_a_deal"}},{"name":"spacer","type":"spacer","layout":{"x":8,"y":2,"w":12,"h":3,"i":"spacer"}},{"name":"sales_trend","type":"axis_chart","layout":{"x":0,"y":4,"w":10,"h":9,"i":"sales_trend"}},{"name":"forecasted_revenue","type":"axis_chart","layout":{"x":10,"y":4,"w":10,"h":9,"i":"forecasted_revenue"}},{"name":"funnel_conversion","type":"axis_chart","layout":{"x":0,"y":11,"w":10,"h":9,"i":"funnel_conversion"}},{"name":"deals_by_stage_donut","type":"donut_chart","layout":{"x":10,"y":11,"w":10,"h":9,"i":"deals_by_stage_donut"}},{"name":"lost_deal_reasons","type":"axis_chart","layout":{"x":0,"y":32,"w":20,"h":9,"i":"lost_deal_reasons"}},{"name":"leads_by_source","type":"donut_chart","layout":{"x":0,"y":18,"w":10,"h":9,"i":"leads_by_source"}},{"name":"deals_by_source","type":"donut_chart","layout":{"x":10,"y":18,"w":10,"h":9,"i":"deals_by_source"}},{"name":"deals_by_territory","type":"axis_chart","layout":{"x":0,"y":25,"w":10,"h":9,"i":"deals_by_territory"}},{"name":"deals_by_salesperson","type":"axis_chart","layout":{"x":10,"y":25,"w":10,"h":9,"i":"deals_by_salesperson"}}]'
def create_default_manager_dashboard(force=False):
"""
Creates the default CRM Manager Dashboard if it does not exist.
"""
if not frappe.db.exists("CRM Dashboard", "Manager Dashboard"):
doc = frappe.new_doc("CRM Dashboard")
doc.title = "Manager Dashboard"
doc.layout = default_manager_dashboard_layout()
doc.insert(ignore_permissions=True)
else:
doc = frappe.get_doc("CRM Dashboard", "Manager Dashboard")
if force:
doc.layout = default_manager_dashboard_layout()
doc.save(ignore_permissions=True)
return doc.layout

View File

@ -0,0 +1,30 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
# import frappe
from frappe.tests import IntegrationTestCase, UnitTestCase
# On IntegrationTestCase, the doctype test records and all
# link-field test record dependencies are recursively loaded
# Use these module variables to add/remove to/from that list
EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
class UnitTestCRMDashboard(UnitTestCase):
"""
Unit tests for CRMDashboard.
Use this class for testing individual functions and methods.
"""
pass
class IntegrationTestCRMDashboard(IntegrationTestCase):
"""
Integration tests for CRMDashboard.
Use this class for testing interactions between multiple components.
"""
pass

View File

@ -1,18 +1,5 @@
import frappe
from crm.api.doc import get_assigned_users, get_fields_meta
from crm.fcrm.doctype.crm_form_script.crm_form_script import get_form_script
@frappe.whitelist()
def get_deal(name):
deal = frappe.get_doc("CRM Deal", name).as_dict()
deal["fields_meta"] = get_fields_meta("CRM Deal")
deal["_form_script"] = get_form_script("CRM Deal")
deal["_assign"] = get_assigned_users("CRM Deal", deal.name)
return deal
@frappe.whitelist()
def get_deal_contacts(name):
@ -30,24 +17,12 @@ def get_deal_contacts(name):
is_primary = contact.is_primary
contact = frappe.get_doc("Contact", contact.contact).as_dict()
def get_primary_email(contact):
for email in contact.email_ids:
if email.is_primary:
return email.email_id
return contact.email_ids[0].email_id if contact.email_ids else ""
def get_primary_mobile_no(contact):
for phone in contact.phone_nos:
if phone.is_primary:
return phone.phone
return contact.phone_nos[0].phone if contact.phone_nos else ""
_contact = {
"name": contact.name,
"image": contact.image,
"full_name": contact.full_name,
"email": get_primary_email(contact),
"mobile_no": get_primary_mobile_no(contact),
"email": contact.email_id,
"mobile_no": contact.mobile_no,
"is_primary": is_primary,
}
deal_contacts.append(_contact)

View File

@ -5,4 +5,68 @@ frappe.ui.form.on("CRM Deal", {
refresh(frm) {
frm.add_web_link(`/crm/deals/${frm.doc.name}`, __("Open in Portal"));
},
update_total: function (frm) {
let total = 0;
let total_qty = 0;
let net_total = 0;
frm.doc.products.forEach((d) => {
total += d.amount;
total_qty += d.qty;
net_total += d.net_amount;
});
frappe.model.set_value(frm.doctype, frm.docname, "total", total);
frappe.model.set_value(
frm.doctype,
frm.docname,
"net_total",
net_total || total
);
}
});
frappe.ui.form.on("CRM Products", {
products_add: function (frm, cdt, cdn) {
frm.trigger("update_total");
},
products_remove: function (frm, cdt, cdn) {
frm.trigger("update_total");
},
product_code: function (frm, cdt, cdn) {
let d = frappe.get_doc(cdt, cdn);
frappe.model.set_value(cdt, cdn, "product_name", d.product_code);
},
rate: function (frm, cdt, cdn) {
let d = frappe.get_doc(cdt, cdn);
if (d.rate && d.qty) {
frappe.model.set_value(cdt, cdn, "amount", d.rate * d.qty);
}
frm.trigger("update_total");
},
qty: function (frm, cdt, cdn) {
let d = frappe.get_doc(cdt, cdn);
if (d.rate && d.qty) {
frappe.model.set_value(cdt, cdn, "amount", d.rate * d.qty);
}
frm.trigger("update_total");
},
discount_percentage: function (frm, cdt, cdn) {
let d = frappe.get_doc(cdt, cdn);
if (d.discount_percentage && d.amount) {
discount_amount = (d.discount_percentage / 100) * d.amount;
frappe.model.set_value(
cdt,
cdn,
"discount_amount",
discount_amount
);
frappe.model.set_value(
cdt,
cdn,
"net_amount",
d.amount - discount_amount
);
}
frm.trigger("update_total");
}
});

View File

@ -11,11 +11,18 @@
"naming_series",
"organization",
"next_step",
"probability",
"column_break_ijan",
"status",
"close_date",
"deal_owner",
"lost_reason",
"lost_notes",
"section_break_jgpm",
"probability",
"expected_deal_value",
"deal_value",
"column_break_kpxa",
"expected_closure_date",
"closed_date",
"contacts_tab",
"contacts",
"contact",
@ -32,6 +39,7 @@
"column_break_xbyf",
"territory",
"currency",
"exchange_rate",
"annual_revenue",
"industry",
"person_section",
@ -43,6 +51,12 @@
"mobile_no",
"phone",
"gender",
"products_tab",
"products",
"section_break_ccbj",
"total",
"column_break_udbq",
"net_total",
"sla_tab",
"sla",
"sla_creation",
@ -82,11 +96,6 @@
"fieldtype": "Data",
"label": "Website"
},
{
"fieldname": "close_date",
"fieldtype": "Date",
"label": "Close Date"
},
{
"fieldname": "next_step",
"fieldtype": "Data",
@ -119,13 +128,13 @@
{
"fieldname": "email",
"fieldtype": "Data",
"label": "Email",
"label": "Primary Email",
"options": "Email"
},
{
"fieldname": "mobile_no",
"fieldtype": "Data",
"label": "Mobile No",
"label": "Primary Mobile No",
"options": "Phone"
},
{
@ -239,7 +248,7 @@
{
"fieldname": "phone",
"fieldtype": "Data",
"label": "Phone",
"label": "Primary Phone",
"options": "Phone"
},
{
@ -334,11 +343,96 @@
"fieldtype": "Link",
"label": "Currency",
"options": "Currency"
},
{
"fieldname": "products_tab",
"fieldtype": "Tab Break",
"label": "Products"
},
{
"fieldname": "products",
"fieldtype": "Table",
"label": "Products",
"options": "CRM Products"
},
{
"fieldname": "section_break_ccbj",
"fieldtype": "Section Break"
},
{
"fieldname": "column_break_udbq",
"fieldtype": "Column Break"
},
{
"fieldname": "total",
"fieldtype": "Currency",
"label": "Total",
"options": "currency",
"read_only": 1
},
{
"description": "Total after discount",
"fieldname": "net_total",
"fieldtype": "Currency",
"label": "Net Total",
"options": "currency",
"read_only": 1
},
{
"fieldname": "section_break_jgpm",
"fieldtype": "Section Break"
},
{
"fieldname": "deal_value",
"fieldtype": "Currency",
"label": "Deal Value",
"options": "currency"
},
{
"fieldname": "column_break_kpxa",
"fieldtype": "Column Break"
},
{
"fieldname": "lost_reason",
"fieldtype": "Link",
"label": "Lost Reason",
"mandatory_depends_on": "eval: doc.status == \"Lost\"",
"options": "CRM Lost Reason"
},
{
"fieldname": "lost_notes",
"fieldtype": "Text",
"label": "Lost Notes",
"mandatory_depends_on": "eval: doc.lost_reason == \"Other\""
},
{
"default": "1",
"description": "The rate used to convert the deal\u2019s currency to your crm's base currency (set in CRM Settings). It is set once when the currency is first added and doesn't change automatically.",
"fieldname": "exchange_rate",
"fieldtype": "Float",
"label": "Exchange Rate"
},
{
"fieldname": "expected_deal_value",
"fieldtype": "Currency",
"label": "Expected Deal Value",
"options": "currency"
},
{
"fieldname": "expected_closure_date",
"fieldtype": "Date",
"label": "Expected Closure Date"
},
{
"fieldname": "closed_date",
"fieldtype": "Date",
"label": "Closed Date"
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2024-12-11 14:31:41.058895",
"modified": "2025-08-26 12:12:56.324245",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Deal",
@ -370,6 +464,7 @@
"write": 1
}
],
"row_format": "Dynamic",
"show_title_field_in_link": 1,
"sort_field": "modified",
"sort_order": "DESC",

View File

@ -7,9 +7,8 @@ from frappe.desk.form.assign_to import add as assign
from frappe.model.document import Document
from crm.fcrm.doctype.crm_service_level_agreement.utils import get_sla
from crm.fcrm.doctype.crm_status_change_log.crm_status_change_log import (
add_status_change_log,
)
from crm.fcrm.doctype.crm_status_change_log.crm_status_change_log import add_status_change_log
from crm.fcrm.doctype.fcrm_settings.fcrm_settings import get_exchange_rate
class CRMDeal(Document):
@ -24,6 +23,11 @@ class CRMDeal(Document):
self.assign_agent(self.deal_owner)
if self.has_value_changed("status"):
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_forecasting_fields()
self.validate_lost_reason()
self.update_exchange_rate()
def after_insert(self):
if self.deal_owner:
@ -133,6 +137,60 @@ class CRMDeal(Document):
if sla:
sla.apply(self)
def update_closed_date(self):
"""
Update the closed date based on the "Won" status.
"""
if self.status == "Won" and not self.closed_date:
self.closed_date = frappe.utils.nowdate()
def update_default_probability(self):
"""
Update the default probability based on the status.
"""
if not self.probability or self.probability == 0:
self.probability = frappe.db.get_value("CRM Deal Status", self.status, "probability") or 0
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)
if not self.expected_closure_date:
frappe.throw(_("Expected Closure Date is required."), frappe.MandatoryError)
def validate_lost_reason(self):
"""
Validate the lost reason if the status is set to "Lost".
"""
if self.status and frappe.get_cached_value("CRM Deal Status", self.status, "type") == "Lost":
if not self.lost_reason:
frappe.throw(_("Please specify a reason for losing the deal."), frappe.ValidationError)
elif self.lost_reason == "Other" and not self.lost_notes:
frappe.throw(_("Please specify the reason for losing the deal."), frappe.ValidationError)
def update_exchange_rate(self):
if self.has_value_changed("currency") or not self.exchange_rate:
system_currency = frappe.db.get_single_value("FCRM Settings", "currency") or "USD"
exchange_rate = 1
if self.currency and self.currency != system_currency:
exchange_rate = get_exchange_rate(self.currency, system_currency)
self.db_set("exchange_rate", exchange_rate)
@staticmethod
def default_list_data():
columns = [

View File

@ -7,8 +7,11 @@
"engine": "InnoDB",
"field_order": [
"deal_status",
"color",
"position"
"type",
"position",
"column_break_ojiu",
"probability",
"color"
],
"fields": [
{
@ -32,11 +35,30 @@
"fieldtype": "Int",
"in_list_view": 1,
"label": "Position"
},
{
"fieldname": "probability",
"fieldtype": "Percent",
"in_list_view": 1,
"label": "Probability"
},
{
"default": "Open",
"fieldname": "type",
"fieldtype": "Select",
"in_list_view": 1,
"label": "Type",
"options": "Open\nOngoing\nOn Hold\nWon\nLost"
},
{
"fieldname": "column_break_ojiu",
"fieldtype": "Column Break"
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2024-01-19 21:56:44.552134",
"modified": "2025-07-11 16:03:28.077955",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Deal Status",
@ -68,6 +90,7 @@
"write": 1
}
],
"row_format": "Dynamic",
"sort_field": "modified",
"sort_order": "DESC",
"states": []

View File

@ -27,7 +27,9 @@ def get_fields_layout(doctype: str, type: str, parent_doctype: str | None = None
if not tabs and type != "Required Fields":
tabs = get_default_layout(doctype)
has_tabs = tabs[0].get("sections") if tabs and tabs[0] else False
has_tabs = False
if isinstance(tabs, list) and len(tabs) > 0 and isinstance(tabs[0], dict):
has_tabs = any("sections" in tab for tab in tabs)
if not has_tabs:
tabs = [{"name": "first_tab", "sections": tabs}]
@ -45,9 +47,19 @@ def get_fields_layout(doctype: str, type: str, parent_doctype: str | None = None
fields = frappe.get_meta(doctype).fields
fields = [field for field in fields if field.fieldname in allowed_fields]
required_fields = []
if type == "Required Fields":
required_fields = [
field for field in frappe.get_meta(doctype, False).fields if field.reqd and not field.default
]
for tab in tabs:
for section in tab.get("sections"):
if section.get("columns"):
section["columns"] = [column for column in section.get("columns") if column]
for column in section.get("columns") if section.get("columns") else []:
column["fields"] = [field for field in column.get("fields") if field]
for field in column.get("fields") if column.get("fields") else []:
field = next((f for f in fields if f.fieldname == field), None)
if field:
@ -55,6 +67,32 @@ def get_fields_layout(doctype: str, type: str, parent_doctype: str | None = None
handle_perm_level_restrictions(field, doctype, parent_doctype)
column["fields"][column.get("fields").index(field["fieldname"])] = field
# remove field from required_fields if it is already present
if (
type == "Required Fields"
and field.reqd
and any(f.get("fieldname") == field.get("fieldname") for f in required_fields)
):
required_fields = [
f for f in required_fields if f.get("fieldname") != field.get("fieldname")
]
if type == "Required Fields" and required_fields and tabs:
tabs[-1].get("sections").append(
{
"label": "Required Fields",
"name": "required_fields_section_" + str(random_string(4)),
"opened": True,
"hideLabel": True,
"columns": [
{
"name": "required_fields_column_" + str(random_string(4)),
"fields": [field.as_dict() for field in required_fields],
}
],
}
)
return tabs or []
@ -78,6 +116,8 @@ def get_sidepanel_sections(doctype):
fields = frappe.get_meta(doctype).fields
fields = [field for field in fields if field.fieldtype not in not_allowed_fieldtypes]
add_forecasting_section(layout, doctype)
for section in layout:
section["name"] = section.get("name") or section.get("label")
for column in section.get("columns") if section.get("columns") else []:
@ -95,6 +135,38 @@ def get_sidepanel_sections(doctype):
return layout
def add_forecasting_section(layout, doctype):
if (
doctype == "CRM Deal"
and frappe.db.get_single_value("FCRM Settings", "enable_forecasting")
and not any(section.get("name") == "forecasted_sales_section" for section in layout)
):
contacts_section_index = next(
(
i
for i, section in enumerate(layout)
if section.get("name") == "contacts_section" or section.get("label") == "Contacts"
),
None,
)
if contacts_section_index is not None:
layout.insert(
contacts_section_index + 1,
{
"name": "forecasted_sales_section",
"label": "Forecasted Sales",
"opened": True,
"columns": [
{
"name": "column_" + str(random_string(4)),
"fields": ["expected_closure_date", "probability", "expected_deal_value"],
}
],
},
)
def handle_perm_level_restrictions(field, doctype, parent_doctype=None):
if field.permlevel == 0:
return

View File

@ -65,7 +65,7 @@
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2024-09-16 19:40:19.340948",
"modified": "2025-05-19 17:57:24.610295",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Form Script",
@ -83,8 +83,18 @@
"role": "Sales Manager",
"share": 1,
"write": 1
},
{
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "All",
"share": 1
}
],
"row_format": "Dynamic",
"sort_field": "modified",
"sort_order": "DESC",
"states": []

View File

@ -27,7 +27,7 @@
"fieldtype": "Select",
"in_list_view": 1,
"label": "Role",
"options": "\nSales User\nSales Manager",
"options": "\nSales User\nSales Manager\nSystem Manager",
"reqd": 1
},
{
@ -66,7 +66,7 @@
],
"index_web_pages_for_search": 1,
"links": [],
"modified": "2024-09-03 14:59:29.450018",
"modified": "2025-06-17 17:20:18.935395",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Invitation",
@ -106,6 +106,7 @@
"share": 1
}
],
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": []

View File

@ -21,7 +21,7 @@ class CRMInvitation(Document):
if frappe.local.dev_server:
print(f"Invite link for {self.email}: {invite_link}")
title = f"Frappe CRM"
title = "Frappe CRM"
template = "crm_invitation"
frappe.sendmail(
@ -35,7 +35,7 @@ class CRMInvitation(Document):
@frappe.whitelist()
def accept_invitation(self):
frappe.only_for("System Manager")
frappe.only_for(["System Manager", "Sales Manager"])
self.accept()
def accept(self):
@ -44,12 +44,28 @@ class CRMInvitation(Document):
user = self.create_user_if_not_exists()
user.append_roles(self.role)
if self.role == "System Manager":
user.append_roles("Sales Manager", "Sales User")
elif self.role == "Sales Manager":
user.append_roles("Sales User")
if self.role == "Sales User":
self.update_module_in_user(user, "FCRM")
user.save(ignore_permissions=True)
self.status = "Accepted"
self.accepted_at = frappe.utils.now()
self.save(ignore_permissions=True)
def update_module_in_user(self, user, module):
block_modules = frappe.get_all(
"Module Def",
fields=["name as module"],
filters={"name": ["!=", module]},
)
if block_modules:
user.set("block_modules", block_modules)
def create_user_if_not_exists(self):
if not frappe.db.exists("User", self.email):
first_name = self.email.split("@")[0].title()

View File

@ -1,14 +0,0 @@
import frappe
from crm.api.doc import get_assigned_users, get_fields_meta
from crm.fcrm.doctype.crm_form_script.crm_form_script import get_form_script
@frappe.whitelist()
def get_lead(name):
lead = frappe.get_doc("CRM Lead", name).as_dict()
lead["fields_meta"] = get_fields_meta("CRM Lead")
lead["_form_script"] = get_form_script("CRM Lead")
lead["_assign"] = get_assigned_users("CRM Lead", lead.name)
return lead

View File

@ -5,4 +5,68 @@ frappe.ui.form.on("CRM Lead", {
refresh(frm) {
frm.add_web_link(`/crm/leads/${frm.doc.name}`, __("Open in Portal"));
},
update_total: function (frm) {
let total = 0;
let total_qty = 0;
let net_total = 0;
frm.doc.products.forEach((d) => {
total += d.amount;
total_qty += d.qty;
net_total += d.net_amount;
});
frappe.model.set_value(frm.doctype, frm.docname, "total", total);
frappe.model.set_value(
frm.doctype,
frm.docname,
"net_total",
net_total || total
);
}
});
frappe.ui.form.on("CRM Products", {
products_add: function (frm, cdt, cdn) {
frm.trigger("update_total");
},
products_remove: function (frm, cdt, cdn) {
frm.trigger("update_total");
},
product_code: function (frm, cdt, cdn) {
let d = frappe.get_doc(cdt, cdn);
frappe.model.set_value(cdt, cdn, "product_name", d.product_code);
},
rate: function (frm, cdt, cdn) {
let d = frappe.get_doc(cdt, cdn);
if (d.rate && d.qty) {
frappe.model.set_value(cdt, cdn, "amount", d.rate * d.qty);
}
frm.trigger("update_total");
},
qty: function (frm, cdt, cdn) {
let d = frappe.get_doc(cdt, cdn);
if (d.rate && d.qty) {
frappe.model.set_value(cdt, cdn, "amount", d.rate * d.qty);
}
frm.trigger("update_total");
},
discount_percentage: function (frm, cdt, cdn) {
let d = frappe.get_doc(cdt, cdn);
if (d.discount_percentage && d.amount) {
discount_amount = (d.discount_percentage / 100) * d.amount;
frappe.model.set_value(
cdt,
cdn,
"discount_amount",
discount_amount
);
frappe.model.set_value(
cdt,
cdn,
"net_amount",
d.amount - discount_amount
);
}
frm.trigger("update_total");
}
});

View File

@ -37,6 +37,12 @@
"annual_revenue",
"image",
"converted",
"products_tab",
"products",
"section_break_ggwh",
"total",
"column_break_uisv",
"net_total",
"sla_tab",
"sla",
"sla_creation",
@ -285,12 +291,47 @@
"fieldtype": "Table",
"label": "Status Change Log",
"options": "CRM Status Change Log"
},
{
"fieldname": "products_tab",
"fieldtype": "Tab Break",
"label": "Products"
},
{
"fieldname": "products",
"fieldtype": "Table",
"label": "Products",
"options": "CRM Products"
},
{
"fieldname": "section_break_ggwh",
"fieldtype": "Section Break"
},
{
"fieldname": "total",
"fieldtype": "Currency",
"label": "Total",
"options": "currency",
"read_only": 1
},
{
"fieldname": "column_break_uisv",
"fieldtype": "Column Break"
},
{
"description": "Total after discount",
"fieldname": "net_total",
"fieldtype": "Currency",
"label": "Net Total",
"options": "currency",
"read_only": 1
}
],
"grid_page_length": 50,
"image_field": "image",
"index_web_pages_for_search": 1,
"links": [],
"modified": "2025-01-02 22:14:01.991054",
"modified": "2025-05-14 19:51:06.184569",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Lead",
@ -331,6 +372,7 @@
"share": 1
}
],
"row_format": "Dynamic",
"sender_field": "email",
"sender_name_field": "first_name",
"show_title_field_in_link": 1,

View File

@ -27,9 +27,10 @@
"label": "Details"
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2025-01-02 22:13:30.498404",
"modified": "2025-06-30 16:53:51.721752",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Lead Source",
@ -44,7 +45,7 @@
"print": 1,
"read": 1,
"report": 1,
"role": "Sales User",
"role": "System Manager",
"share": 1,
"write": 1
},
@ -60,6 +61,15 @@
"share": 1,
"write": 1
},
{
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales User",
"share": 1
},
{
"email": 1,
"export": 1,
@ -71,6 +81,7 @@
}
],
"quick_entry": 1,
"row_format": "Dynamic",
"sort_field": "modified",
"sort_order": "DESC",
"states": []

View File

@ -0,0 +1,8 @@
// Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
// frappe.ui.form.on("CRM Lost Reason", {
// refresh(frm) {
// },
// });

View File

@ -0,0 +1,79 @@
{
"actions": [],
"allow_rename": 1,
"autoname": "field:lost_reason",
"creation": "2025-06-30 16:51:31.082360",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"lost_reason",
"description"
],
"fields": [
{
"fieldname": "lost_reason",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Lost Reason",
"reqd": 1,
"unique": 1
},
{
"fieldname": "description",
"fieldtype": "Text Editor",
"label": "Description"
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"links": [],
"modified": "2025-06-30 16:59:15.094049",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Lost Reason",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "Sales User",
"share": 1,
"write": 1
}
],
"quick_entry": 1,
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}

View File

@ -0,0 +1,9 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
# import frappe
from frappe.model.document import Document
class CRMLostReason(Document):
pass

View File

@ -0,0 +1,30 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
# import frappe
from frappe.tests import IntegrationTestCase, UnitTestCase
# On IntegrationTestCase, the doctype test records and all
# link-field test record dependencies are recursively loaded
# Use these module variables to add/remove to/from that list
EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
class UnitTestCRMLostReason(UnitTestCase):
"""
Unit tests for CRMLostReason.
Use this class for testing individual functions and methods.
"""
pass
class IntegrationTestCRMLostReason(IntegrationTestCase):
"""
Integration tests for CRMLostReason.
Use this class for testing interactions between multiple components.
"""
pass

View File

@ -10,6 +10,7 @@
"organization_name",
"no_of_employees",
"currency",
"exchange_rate",
"annual_revenue",
"organization_logo",
"column_break_pnpp",
@ -74,12 +75,18 @@
"fieldtype": "Link",
"label": "Address",
"options": "Address"
},
{
"description": "The rate used to convert the organization\u2019s currency to your crm's base currency (set in CRM Settings). It is set once when the currency is first added and doesn't change automatically.",
"fieldname": "exchange_rate",
"fieldtype": "Float",
"label": "Exchange Rate"
}
],
"image_field": "organization_logo",
"index_web_pages_for_search": 1,
"links": [],
"modified": "2024-09-17 18:37:10.341062",
"modified": "2025-07-15 11:40:12.175598",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Organization",
@ -111,6 +118,7 @@
"write": 1
}
],
"row_format": "Dynamic",
"sort_field": "modified",
"sort_order": "DESC",
"states": []

View File

@ -4,41 +4,55 @@
import frappe
from frappe.model.document import Document
from crm.fcrm.doctype.fcrm_settings.fcrm_settings import get_exchange_rate
class CRMOrganization(Document):
def validate(self):
self.update_exchange_rate()
def update_exchange_rate(self):
if self.has_value_changed("currency") or not self.exchange_rate:
system_currency = frappe.db.get_single_value("FCRM Settings", "currency") or "USD"
exchange_rate = 1
if self.currency and self.currency != system_currency:
exchange_rate = get_exchange_rate(self.currency, system_currency)
self.db_set("exchange_rate", exchange_rate)
@staticmethod
def default_list_data():
columns = [
{
'label': 'Organization',
'type': 'Data',
'key': 'organization_name',
'width': '16rem',
"label": "Organization",
"type": "Data",
"key": "organization_name",
"width": "16rem",
},
{
'label': 'Website',
'type': 'Data',
'key': 'website',
'width': '14rem',
"label": "Website",
"type": "Data",
"key": "website",
"width": "14rem",
},
{
'label': 'Industry',
'type': 'Link',
'key': 'industry',
'options': 'CRM Industry',
'width': '14rem',
"label": "Industry",
"type": "Link",
"key": "industry",
"options": "CRM Industry",
"width": "14rem",
},
{
'label': 'Annual Revenue',
'type': 'Currency',
'key': 'annual_revenue',
'width': '14rem',
"label": "Annual Revenue",
"type": "Currency",
"key": "annual_revenue",
"width": "14rem",
},
{
'label': 'Last Modified',
'type': 'Datetime',
'key': 'modified',
'width': '8rem',
"label": "Last Modified",
"type": "Datetime",
"key": "modified",
"width": "8rem",
},
]
rows = [
@ -51,4 +65,4 @@ class CRMOrganization(Document):
"annual_revenue",
"modified",
]
return {'columns': columns, 'rows': rows}
return {"columns": columns, "rows": rows}

View File

View File

@ -0,0 +1,9 @@
// Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
frappe.ui.form.on("CRM Product", {
product_code: function (frm) {
if (!frm.doc.product_name)
frm.set_value("product_name", frm.doc.product_code);
}
});

View File

@ -0,0 +1,105 @@
{
"actions": [],
"allow_import": 1,
"allow_rename": 1,
"autoname": "field:product_code",
"creation": "2025-04-28 11:45:09.309636",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"naming_series",
"product_code",
"product_name",
"column_break_bpdj",
"disabled",
"standard_rate",
"image",
"section_break_rtwm",
"description"
],
"fields": [
{
"fieldname": "naming_series",
"fieldtype": "Select",
"label": "Naming Series",
"options": "CRM-PROD-.YYYY.-"
},
{
"fieldname": "product_code",
"fieldtype": "Data",
"in_list_view": 1,
"label": "Product Code",
"reqd": 1,
"unique": 1
},
{
"fieldname": "product_name",
"fieldtype": "Data",
"label": "Product Name"
},
{
"fieldname": "column_break_bpdj",
"fieldtype": "Column Break"
},
{
"default": "0",
"fieldname": "disabled",
"fieldtype": "Check",
"label": "Disabled"
},
{
"fieldname": "image",
"fieldtype": "Attach Image",
"label": "Image"
},
{
"fieldname": "section_break_rtwm",
"fieldtype": "Section Break"
},
{
"fieldname": "description",
"fieldtype": "Text Editor",
"label": "Description"
},
{
"fieldname": "standard_rate",
"fieldtype": "Currency",
"label": "Standard Selling Rate"
}
],
"grid_page_length": 50,
"image_field": "image",
"index_web_pages_for_search": 1,
"links": [],
"make_attachments_public": 1,
"modified": "2025-04-28 12:47:25.087957",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Product",
"naming_rule": "By fieldname",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
"read": 1,
"report": 1,
"role": "System Manager",
"share": 1,
"write": 1
}
],
"quick_entry": 1,
"row_format": "Dynamic",
"search_fields": "product_name,description",
"show_name_in_global_search": 1,
"show_preview_popup": 1,
"sort_field": "creation",
"sort_order": "DESC",
"states": [],
"title_field": "product_name",
"track_changes": 1
}

View File

@ -0,0 +1,16 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import frappe
from frappe.model.document import Document
class CRMProduct(Document):
def validate(self):
self.set_product_name()
def set_product_name(self):
if not self.product_name:
self.product_name = self.product_code
else:
self.product_name = self.product_name.strip()

View File

@ -0,0 +1,29 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
# import frappe
from frappe.tests import IntegrationTestCase, UnitTestCase
# On IntegrationTestCase, the doctype test records and all
# link-field test record dependencies are recursively loaded
# Use these module variables to add/remove to/from that list
EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
class UnitTestCRMProduct(UnitTestCase):
"""
Unit tests for CRMProduct.
Use this class for testing individual functions and methods.
"""
pass
class IntegrationTestCRMProduct(IntegrationTestCase):
"""
Integration tests for CRMProduct.
Use this class for testing interactions between multiple components.
"""
pass

View File

@ -0,0 +1,136 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2025-04-28 12:50:49.812915",
"doctype": "DocType",
"editable_grid": 1,
"engine": "InnoDB",
"field_order": [
"product_code",
"column_break_gvbc",
"product_name",
"section_break_fnvf",
"qty",
"column_break_ajac",
"rate",
"section_break_olqb",
"discount_percentage",
"column_break_uvra",
"discount_amount",
"section_break_cnpb",
"column_break_pozr",
"amount",
"column_break_ejqw",
"net_amount"
],
"fields": [
{
"fieldname": "column_break_gvbc",
"fieldtype": "Column Break"
},
{
"fieldname": "product_name",
"fieldtype": "Data",
"label": "Product Name",
"reqd": 1
},
{
"fieldname": "section_break_fnvf",
"fieldtype": "Section Break"
},
{
"fieldname": "section_break_olqb",
"fieldtype": "Section Break"
},
{
"bold": 1,
"fieldname": "discount_percentage",
"fieldtype": "Percent",
"label": "Discount %"
},
{
"fieldname": "discount_amount",
"fieldtype": "Currency",
"label": "Discount Amount",
"options": "currency",
"read_only": 1
},
{
"fieldname": "section_break_cnpb",
"fieldtype": "Section Break"
},
{
"fieldname": "column_break_pozr",
"fieldtype": "Column Break"
},
{
"bold": 1,
"fieldname": "rate",
"fieldtype": "Currency",
"in_list_view": 1,
"label": "Rate",
"options": "currency",
"reqd": 1
},
{
"bold": 1,
"fieldname": "amount",
"fieldtype": "Currency",
"label": "Amount",
"options": "currency",
"read_only": 1
},
{
"bold": 1,
"depends_on": "discount_percentage",
"description": "Amount after discount",
"fieldname": "net_amount",
"fieldtype": "Currency",
"label": "Net Amount",
"options": "currency",
"read_only": 1
},
{
"bold": 1,
"columns": 5,
"fieldname": "product_code",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Product",
"options": "CRM Product"
},
{
"bold": 1,
"default": "1",
"fieldname": "qty",
"fieldtype": "Float",
"label": "Quantity"
},
{
"fieldname": "column_break_ajac",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_uvra",
"fieldtype": "Column Break"
},
{
"fieldname": "column_break_ejqw",
"fieldtype": "Column Break"
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2025-05-14 18:52:26.183306",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Products",
"owner": "Administrator",
"permissions": [],
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}

View File

@ -0,0 +1,110 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import frappe
from frappe.model.document import Document
class CRMProducts(Document):
pass
def create_product_details_script(doctype):
if not frappe.db.exists("CRM Form Script", "Product Details Script for " + doctype):
script = get_product_details_script(doctype)
frappe.get_doc(
{
"doctype": "CRM Form Script",
"name": "Product Details Script for " + doctype,
"dt": doctype,
"view": "Form",
"script": script,
"enabled": 1,
"is_standard": 1,
}
).insert()
def get_product_details_script(doctype):
doctype_class = "class " + doctype.replace(" ", "")
return (
doctype_class
+ " {"
+ """
update_total() {
let total = 0
let total_qty = 0
let net_total = 0
let discount_applied = false
this.doc.products.forEach((d) => {
total += d.amount
net_total += d.net_amount
if (d.discount_percentage > 0) {
discount_applied = true
}
})
this.doc.total = total
this.doc.net_total = net_total || total
if (!net_total && discount_applied) {
this.doc.net_total = net_total
}
}
}
class CRMProducts {
products_add() {
let row = this.doc.getRow('products')
row.trigger('qty')
this.doc.trigger('update_total')
}
products_remove() {
this.doc.trigger('update_total')
}
async product_code(idx) {
let row = this.doc.getRow('products', idx)
let a = await call("frappe.client.get_value", {
doctype: "CRM Product",
filters: { name: row.product_code },
fieldname: ["product_name", "standard_rate"],
})
row.product_name = a.product_name
if (a.standard_rate && !row.rate) {
row.rate = a.standard_rate
row.trigger("rate")
}
}
qty(idx) {
let row = this.doc.getRow('products', idx)
row.amount = row.qty * row.rate
row.trigger('discount_percentage', idx)
}
rate() {
let row = this.doc.getRow('products')
row.amount = row.qty * row.rate
row.trigger('discount_percentage')
}
discount_percentage(idx) {
let row = this.doc.getRow('products', idx)
if (!row.discount_percentage) {
row.net_amount = row.amount
row.discount_amount = 0
}
if (row.discount_percentage && row.amount) {
row.discount_amount = (row.discount_percentage / 100) * row.amount
row.net_amount = row.amount - row.discount_amount
}
this.doc.trigger('update_total')
}
}"""
)

View File

@ -13,6 +13,8 @@
"column_break_mwmz",
"duration",
"last_status_change_log",
"from_type",
"to_type",
"log_owner"
],
"fields": [
@ -61,17 +63,30 @@
"fieldtype": "Link",
"label": "Owner",
"options": "User"
},
{
"fieldname": "from_type",
"fieldtype": "Data",
"in_list_view": 1,
"label": "From Type"
},
{
"fieldname": "to_type",
"fieldtype": "Data",
"in_list_view": 1,
"label": "To Type"
}
],
"index_web_pages_for_search": 1,
"istable": 1,
"links": [],
"modified": "2024-01-06 13:26:40.597277",
"modified": "2025-07-13 12:37:41.278584",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Status Change Log",
"owner": "Administrator",
"permissions": [],
"row_format": "Dynamic",
"sort_field": "modified",
"sort_order": "DESC",
"states": []

View File

@ -1,15 +1,17 @@
# Copyright (c) 2024, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import frappe
from datetime import datetime
from frappe.utils import add_to_date, get_datetime
import frappe
from frappe.model.document import Document
from frappe.utils import add_to_date, get_datetime
class CRMStatusChangeLog(Document):
pass
def get_duration(from_date, to_date):
if not isinstance(from_date, datetime):
from_date = get_datetime(from_date)
@ -18,28 +20,45 @@ def get_duration(from_date, to_date):
duration = to_date - from_date
return duration.total_seconds()
def add_status_change_log(doc):
to_status_type = frappe.db.get_value("CRM Deal Status", doc.status, "type") if doc.status else None
if not doc.is_new():
previous_status = doc.get_doc_before_save().status if doc.get_doc_before_save() else None
previous_status_type = (
frappe.db.get_value("CRM Deal Status", previous_status, "type") if previous_status else None
)
if not doc.status_change_log and previous_status:
now_minus_one_minute = add_to_date(datetime.now(), minutes=-1)
doc.append("status_change_log", {
doc.append(
"status_change_log",
{
"from": previous_status,
"from_type": previous_status_type or "",
"to": "",
"to_type": "",
"from_date": now_minus_one_minute,
"to_date": "",
"log_owner": frappe.session.user,
})
},
)
last_status_change = doc.status_change_log[-1]
last_status_change.to = doc.status
last_status_change.to_type = to_status_type or ""
last_status_change.to_date = datetime.now()
last_status_change.log_owner = frappe.session.user
last_status_change.duration = get_duration(last_status_change.from_date, last_status_change.to_date)
doc.append("status_change_log", {
doc.append(
"status_change_log",
{
"from": doc.status,
"from_type": to_status_type or "",
"to": "",
"to_type": "",
"from_date": datetime.now(),
"to_date": "",
"log_owner": frappe.session.user,
})
},
)

View File

@ -63,8 +63,7 @@
"fieldname": "twiml_sid",
"fieldtype": "Data",
"label": "TwiML SID",
"permlevel": 1,
"read_only": 1
"permlevel": 1
},
{
"fieldname": "section_break_ssqj",
@ -105,7 +104,7 @@
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2025-01-15 19:35:13.406254",
"modified": "2025-08-19 13:36:19.823197",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Twilio Settings",
@ -152,6 +151,7 @@
"write": 1
}
],
"row_format": "Dynamic",
"sort_field": "modified",
"sort_order": "DESC",
"states": [],

View File

@ -128,14 +128,32 @@ def get_quotation_url(crm_deal, organization):
address = address.get("name") if address else None
if not erpnext_crm_settings.is_erpnext_in_different_site:
quotation_url = get_url_to_list("Quotation")
return f"{quotation_url}/new?quotation_to=CRM Deal&crm_deal={crm_deal}&party_name={crm_deal}&company={erpnext_crm_settings.erpnext_company}&contact_person={contact}&customer_address={address}"
base_url = f"{get_url_to_list('Quotation')}/new"
params = {
"quotation_to": "CRM Deal",
"crm_deal": crm_deal,
"party_name": crm_deal,
"company": erpnext_crm_settings.erpnext_company,
"contact_person": contact,
"customer_address": address,
}
else:
site_url = erpnext_crm_settings.get("erpnext_site_url")
quotation_url = f"{site_url}/app/quotation"
base_url = f"{site_url}/app/quotation/new"
prospect = create_prospect_in_remote_site(crm_deal, erpnext_crm_settings)
return f"{quotation_url}/new?quotation_to=Prospect&crm_deal={crm_deal}&party_name={prospect}&company={erpnext_crm_settings.erpnext_company}&contact_person={contact}&customer_address={address}"
params = {
"quotation_to": "Prospect",
"crm_deal": crm_deal,
"party_name": prospect,
"company": erpnext_crm_settings.erpnext_company,
"contact_person": contact,
"customer_address": address,
}
# Filter out None values and build query string
query_string = "&".join(f"{key}={value}" for key, value in params.items() if value is not None)
return f"{base_url}?{query_string}"
def create_prospect_in_remote_site(crm_deal, erpnext_crm_settings):
@ -264,7 +282,7 @@ def create_customer_in_remote_site(customer, erpnext_crm_settings):
@frappe.whitelist()
def get_crm_form_script():
return """
async function setupForm({ doc, call, $dialog, updateField, createToast }) {
async function setupForm({ doc, call, $dialog, updateField, toast }) {
let actions = [];
let is_erpnext_integration_enabled = await call("frappe.client.get_single_value", {doctype: "ERPNext CRM Settings", field: "enabled"});
if (!["Lost", "Won"].includes(doc?.status) && is_erpnext_integration_enabled) {

View File

@ -19,7 +19,8 @@
"fieldtype": "Data",
"in_list_view": 1,
"in_standard_filter": 1,
"label": "Title"
"label": "Title",
"reqd": 1
},
{
"fieldname": "content",
@ -49,7 +50,7 @@
"link_fieldname": "note"
}
],
"modified": "2024-01-19 21:56:30.123334",
"modified": "2025-04-01 15:30:14.742001",
"modified_by": "Administrator",
"module": "FCRM",
"name": "FCRM Note",

View File

@ -7,6 +7,14 @@
"field_order": [
"defaults_tab",
"restore_defaults",
"enable_forecasting",
"auto_update_expected_deal_value",
"currency_tab",
"currency",
"exchange_rate_provider_section",
"service_provider",
"column_break_vqck",
"access_key",
"branding_tab",
"brand_name",
"brand_logo",
@ -28,7 +36,7 @@
{
"fieldname": "defaults_tab",
"fieldtype": "Tab Break",
"label": "Defaults"
"label": "Settings"
},
{
"fieldname": "branding_tab",
@ -56,12 +64,61 @@
"fieldname": "favicon",
"fieldtype": "Attach",
"label": "Favicon"
},
{
"default": "0",
"description": "It will make deal's \"Expected Closure Date\" & \"Expected Deal Value\" mandatory to get accurate forecasting insights",
"fieldname": "enable_forecasting",
"fieldtype": "Check",
"label": "Enable Forecasting"
},
{
"fieldname": "currency",
"fieldtype": "Link",
"in_list_view": 1,
"label": "Currency",
"options": "Currency"
},
{
"fieldname": "currency_tab",
"fieldtype": "Tab Break",
"label": "Currency"
},
{
"fieldname": "exchange_rate_provider_section",
"fieldtype": "Section Break",
"label": "Exchange Rate Provider"
},
{
"default": "frankfurter.app",
"fieldname": "service_provider",
"fieldtype": "Select",
"label": "Service Provider",
"options": "frankfurter.app\nexchangerate.host"
},
{
"depends_on": "eval:doc.service_provider == 'exchangerate.host';",
"fieldname": "access_key",
"fieldtype": "Data",
"label": "Access Key",
"mandatory_depends_on": "eval:doc.service_provider == 'exchangerate.host';"
},
{
"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-02-20 12:38:38.088477",
"modified": "2025-09-16 17:33:26.406549",
"modified_by": "Administrator",
"module": "FCRM",
"name": "FCRM Settings",
@ -95,6 +152,7 @@
"share": 1
}
],
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": []

View File

@ -2,7 +2,9 @@
# For license information, please see license.txt
import frappe
import requests
from frappe import _
from frappe.custom.doctype.property_setter.property_setter import delete_property_setter, make_property_setter
from frappe.model.document import Document
from crm.install import after_install
@ -15,6 +17,8 @@ class FCRMSettings(Document):
def validate(self):
self.do_not_allow_to_delete_if_standard()
self.setup_forecasting()
self.make_currency_read_only()
def do_not_allow_to_delete_if_standard(self):
if not self.has_value_changed("dropdown_items"):
@ -24,8 +28,53 @@ class FCRMSettings(Document):
standard_old_items = [d.name1 for d in old_items if d.is_standard]
deleted_standard_items = set(standard_old_items) - set(standard_new_items)
if deleted_standard_items:
standard_dropdown_items = get_standard_dropdown_items()
if not deleted_standard_items.intersection(standard_dropdown_items):
return
frappe.throw(_("Cannot delete standard items {0}").format(", ".join(deleted_standard_items)))
def setup_forecasting(self):
if self.has_value_changed("enable_forecasting"):
if not self.enable_forecasting:
delete_property_setter(
"CRM Deal",
"reqd",
"expected_closure_date",
)
delete_property_setter(
"CRM Deal",
"reqd",
"expected_deal_value",
)
else:
make_property_setter(
"CRM Deal",
"expected_closure_date",
"reqd",
1 if self.enable_forecasting else 0,
"Check",
)
make_property_setter(
"CRM Deal",
"expected_deal_value",
"reqd",
1 if self.enable_forecasting else 0,
"Check",
)
def make_currency_read_only(self):
if self.currency and self.has_value_changed("currency"):
make_property_setter(
"FCRM Settings",
"currency",
"read_only",
1,
"Check",
)
def get_standard_dropdown_items():
return [item.get("name1") for item in frappe.get_hooks("standard_dropdown_items")]
def after_migrate():
@ -51,3 +100,109 @@ def sync_table(key, hook):
crm_settings.set(key, items)
crm_settings.save()
def create_forecasting_script():
if not frappe.db.exists("CRM Form Script", "Forecasting Script"):
script = get_forecasting_script()
frappe.get_doc(
{
"doctype": "CRM Form Script",
"name": "Forecasting Script",
"dt": "CRM Deal",
"view": "Form",
"script": script,
"enabled": 1,
"is_standard": 1,
}
).insert()
def get_forecasting_script():
return """class CRMDeal {
async status() {
await this.doc.trigger('updateProbability')
}
async updateProbability() {
let status = await call("frappe.client.get_value", {
doctype: "CRM Deal Status",
fieldname: "probability",
filters: { name: this.doc.status },
})
this.doc.probability = status.probability
}
}"""
def get_exchange_rate(from_currency, to_currency, date=None):
if not date:
date = "latest"
api_used = "frankfurter"
api_endpoint = f"https://api.frankfurter.app/{date}?from={from_currency}&to={to_currency}"
res = requests.get(api_endpoint, timeout=5)
if res.ok:
data = res.json()
return data["rates"][to_currency]
# Fallback to exchangerate.host if Frankfurter API fails
settings = FCRMSettings("FCRM Settings")
if settings and settings.service_provider == "exchangerate.host":
api_used = "exchangerate.host"
if not settings.access_key:
frappe.throw(
_("Access Key is required for Service Provider: {0}").format(
frappe.bold(settings.service_provider)
)
)
params = {
"access_key": settings.access_key,
"from": from_currency,
"to": to_currency,
"amount": 1,
}
if date != "latest":
params["date"] = date
api_endpoint = "https://api.exchangerate.host/convert"
res = requests.get(api_endpoint, params=params, timeout=5)
if res.ok:
data = res.json()
return data["result"]
frappe.log_error(
title="Exchange Rate Fetch Error",
message=f"Failed to fetch exchange rate from {from_currency} to {to_currency} using {api_used} API.",
)
if api_used == "frankfurter":
user = frappe.session.user
is_manager = (
"System Manager" in frappe.get_roles(user)
or "Sales Manager" in frappe.get_roles(user)
or user == "Administrator"
)
if not is_manager:
frappe.throw(
_(
"Ask your manager to set up the Exchange Rate Provider, as default provider does not support currency conversion for {0} to {1}."
).format(from_currency, to_currency)
)
else:
frappe.throw(
_(
"Setup the Exchange Rate Provider as 'Exchangerate Host' in settings, as default provider does not support currency conversion for {0} to {1}."
).format(from_currency, to_currency)
)
frappe.throw(
_(
"Failed to fetch exchange rate from {0} to {1} on {2}. Please check your internet connection or try again later."
).format(from_currency, to_currency, date)
)

View File

@ -0,0 +1,8 @@
// Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
// For license information, please see license.txt
// frappe.ui.form.on("Helpdesk CRM Settings", {
// refresh(frm) {
// },
// });

View File

@ -0,0 +1,102 @@
{
"actions": [],
"allow_rename": 1,
"creation": "2025-08-18 17:25:49.638398",
"doctype": "DocType",
"engine": "InnoDB",
"field_order": [
"enabled",
"column_break_idaw",
"is_helpdesk_in_different_site",
"helpdesk_site_url",
"helpdesk_site_apis_section",
"api_key",
"column_break_tqsm",
"api_secret"
],
"fields": [
{
"default": "0",
"fieldname": "enabled",
"fieldtype": "Check",
"label": "Enabled"
},
{
"fieldname": "column_break_idaw",
"fieldtype": "Column Break"
},
{
"default": "0",
"depends_on": "enabled",
"fieldname": "is_helpdesk_in_different_site",
"fieldtype": "Check",
"label": "Is Helpdesk installed on a different site?"
},
{
"depends_on": "eval:doc.enabled && doc.is_helpdesk_in_different_site",
"fieldname": "helpdesk_site_url",
"fieldtype": "Data",
"label": "Helpdesk Site URL",
"mandatory_depends_on": "is_helpdesk_in_different_site"
},
{
"depends_on": "enabled",
"fieldname": "helpdesk_site_apis_section",
"fieldtype": "Section Break",
"label": "Helpdesk Site API's"
},
{
"depends_on": "eval:doc.enabled && doc.is_helpdesk_in_different_site",
"fieldname": "api_key",
"fieldtype": "Data",
"label": "API Key",
"mandatory_depends_on": "is_helpdesk_in_different_site"
},
{
"fieldname": "column_break_tqsm",
"fieldtype": "Column Break"
},
{
"depends_on": "eval:doc.enabled && doc.is_helpdesk_in_different_site",
"fieldname": "api_secret",
"fieldtype": "Password",
"label": "API Secret",
"mandatory_depends_on": "is_helpdesk_in_different_site"
}
],
"grid_page_length": 50,
"index_web_pages_for_search": 1,
"issingle": 1,
"links": [],
"modified": "2025-08-18 17:33:38.616328",
"modified_by": "Administrator",
"module": "FCRM",
"name": "Helpdesk CRM Settings",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"role": "System Manager",
"share": 1,
"write": 1
},
{
"create": 1,
"delete": 1,
"email": 1,
"print": 1,
"read": 1,
"role": "Sales Manager",
"share": 1,
"write": 1
}
],
"row_format": "Dynamic",
"sort_field": "creation",
"sort_order": "DESC",
"states": []
}

View File

@ -0,0 +1,178 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
# For license information, please see license.txt
import frappe
from frappe import _
from frappe.model.document import Document
class HelpdeskCRMSettings(Document):
def validate(self):
if self.enabled:
self.validate_if_helpdesk_installed()
self.create_helpdesk_script()
def validate_if_helpdesk_installed(self):
if not self.is_helpdesk_in_different_site:
if "helpdesk" not in frappe.get_installed_apps():
frappe.throw(_("Helpdesk is not installed in the current site"))
def create_helpdesk_script(self):
if not frappe.db.exists("CRM Form Script", "Helpdesk Integration Script"):
script = get_helpdesk_script()
frappe.get_doc(
{
"doctype": "CRM Form Script",
"name": "Helpdesk Integration Script",
"dt": "CRM Deal",
"view": "Form",
"script": script,
"enabled": 1,
"is_standard": 1,
}
).insert()
@frappe.whitelist()
def create_customer_in_helpdesk(name, email):
helpdesk_crm_settings = frappe.get_single("Helpdesk CRM Settings")
if not helpdesk_crm_settings.enabled:
frappe.throw(_("Helpdesk is not integrated with the CRM"))
if not helpdesk_crm_settings.is_helpdesk_in_different_site:
# from helpdesk.integrations.crm.api import create_customer
return create_customer(name, email)
def get_helpdesk_script():
return """class CRMDeal {
onLoad() {
this.actions.push(
{
group: "Helpdesk",
hideLabel: true,
items: [
{
label: "Create customer in Helpdesk",
onClick: () => {
call('crm.fcrm.doctype.helpdesk_crm_settings.helpdesk_crm_settings.create_customer_in_helpdesk', {
name: this.doc.organization,
email: this.doc.email
}).then((a) => {
toast.success("Customer created successfully, " + a.customer)
})
}
}
]
}
)
}
}"""
# Helpdesk methods TODO: move to helpdesk.integrations.crm.api
def create_customer(name, email):
customer = frappe.db.exists("HD Customer", name)
if not customer:
customer = frappe.get_doc(
{
"doctype": "HD Customer",
"customer_name": name,
}
)
customer.insert(ignore_permissions=True, ignore_if_duplicate=True)
else:
customer = frappe.get_doc("HD Customer", customer)
contact = frappe.db.exists("Contact", {"email_id": email})
if contact:
contact = frappe.get_doc("Contact", contact)
contact.append(
"links", {"link_doctype": "HD Customer", "link_name": customer.name}
)
contact.save(ignore_permissions=True)
else:
contact = frappe.get_doc(
{
"doctype": "Contact",
"first_name": email.split("@")[0],
"email_ids": [{"email_id": email, "is_primary": 1}],
"links": [{"link_doctype": "HD Customer", "link_name": customer.name}],
}
)
contact.insert(ignore_permissions=True)
if not frappe.db.exists("User", contact.email_id):
invite_user(contact.name)
else:
base_url = frappe.utils.get_url() + "/helpdesk"
frappe.sendmail(
recipients=[contact.email_id],
subject="Welcome existing user to Helpdesk",
message=f"""
<h1>Hello,</h1>
<button>{base_url}</button>
""",
now=True,
)
return {"customer": customer.name, "contact": contact.name}
def invite_user(contact: str):
contact = frappe.get_doc("Contact", contact)
contact.check_permission()
if not contact.email_id:
frappe.throw(_("Please set Email Address"))
user = frappe.get_doc(
{
"doctype": "User",
"first_name": contact.first_name,
"last_name": contact.last_name,
"email": contact.email_id,
"user_type": "Website User",
"send_welcome_email": 0
}
).insert()
contact.user = user.name
contact.save(ignore_permissions=True)
send_welcome_mail_to_user(user)
return user.name
def send_welcome_mail_to_user(user):
from frappe.utils import get_url
from frappe.utils.user import get_user_fullname
link = user.reset_password()
frappe.cache.hset("redirect_after_login", user.name, "/helpdesk")
site_url = get_url()
subject = _("Welcome to Helpdesk")
created_by = get_user_fullname(frappe.session["user"])
if created_by == "Guest":
created_by = "Administrator"
args = {
"first_name": user.first_name or user.last_name or "user",
"last_name": user.last_name,
"user": user.name,
"title": subject,
"login_url": get_url(),
"created_by": created_by,
"site_url": site_url,
"link": link
}
frappe.sendmail(
recipients=[user.email],
subject=subject,
template="helpdesk_invitation",
args=args,
now=True,
)

View File

@ -0,0 +1,21 @@
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
# import frappe
from frappe.tests import IntegrationTestCase
# On IntegrationTestCase, the doctype test records and all
# link-field test record dependencies are recursively loaded
# Use these module variables to add/remove to/from that list
EXTRA_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
IGNORE_TEST_RECORD_DEPENDENCIES = [] # eg. ["User"]
class IntegrationTestHelpdeskCRMSettings(IntegrationTestCase):
"""
Integration tests for HelpdeskCRMSettings.
Use this class for testing interactions between multiple components.
"""
pass

View File

@ -264,22 +264,6 @@ standard_dropdown_items = [
"route": "#",
"is_standard": 1,
},
{
"name1": "support_link",
"label": "Support",
"type": "Route",
"icon": "life-buoy",
"route": "https://t.me/frappecrm",
"is_standard": 1,
},
{
"name1": "docs_link",
"label": "Docs",
"type": "Route",
"icon": "book-open",
"route": "https://docs.frappe.io/crm",
"is_standard": 1,
},
{
"name1": "toggle_theme",
"label": "Toggle theme",
@ -303,6 +287,14 @@ standard_dropdown_items = [
"route": "#",
"is_standard": 1,
},
{
"name1": "about",
"label": "About",
"type": "Route",
"icon": "info",
"route": "#",
"is_standard": 1,
},
{
"name1": "separator",
"label": "",

View File

@ -4,6 +4,9 @@ import click
import frappe
from frappe.custom.doctype.custom_field.custom_field import create_custom_fields
from crm.fcrm.doctype.crm_dashboard.crm_dashboard import create_default_manager_dashboard
from crm.fcrm.doctype.crm_products.crm_products import create_product_details_script
def before_install():
pass
@ -18,7 +21,12 @@ def after_install(force=False):
add_email_template_custom_fields()
add_default_industries()
add_default_lead_sources()
add_default_lost_reasons()
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()
@ -65,30 +73,44 @@ def add_default_deal_statuses():
statuses = {
"Qualification": {
"color": "gray",
"type": "Open",
"probability": 10,
"position": 1,
},
"Demo/Making": {
"color": "orange",
"type": "Ongoing",
"probability": 25,
"position": 2,
},
"Proposal/Quotation": {
"color": "blue",
"type": "Ongoing",
"probability": 50,
"position": 3,
},
"Negotiation": {
"color": "yellow",
"type": "Ongoing",
"probability": 70,
"position": 4,
},
"Ready to Close": {
"color": "purple",
"type": "Ongoing",
"probability": 90,
"position": 5,
},
"Won": {
"color": "green",
"type": "Won",
"probability": 100,
"position": 6,
},
"Lost": {
"color": "red",
"type": "Lost",
"probability": 0,
"position": 7,
},
}
@ -100,6 +122,8 @@ def add_default_deal_statuses():
doc = frappe.new_doc("CRM Deal Status")
doc.deal_status = status
doc.color = statuses[status]["color"]
doc.type = statuses[status]["type"]
doc.probability = statuses[status]["probability"]
doc.position = statuses[status]["position"]
doc.insert()
@ -170,7 +194,7 @@ def add_default_fields_layout(force=False):
},
"CRM Deal-Data Fields": {
"doctype": "CRM Deal",
"layout": '[{"label": "Details", "name": "details_section", "opened": true, "columns": [{"name": "column_z9XL", "fields": ["organization", "annual_revenue", "next_step"]}, {"name": "column_gM4w", "fields": ["website", "close_date", "deal_owner"]}, {"name": "column_gWmE", "fields": ["territory", "probability"]}]}]',
"layout": '[{"name":"first_tab","sections":[{"label":"Details","name":"details_section","opened":true,"columns":[{"name":"column_z9XL","fields":["organization","annual_revenue","next_step"]},{"name":"column_gM4w","fields":["website","closed_date","deal_owner"]},{"name":"column_gWmE","fields":["territory","probability"]}]},{"label":"Products","name":"section_jHhQ","opened":true,"columns":[{"name":"column_xiNF","fields":["products"]}],"editingLabel":false,"hideLabel":true},{"label":"New Section","name":"section_WNOQ","opened":true,"columns":[{"name":"column_ziBW","fields":["total"]},{"label":"","name":"column_wuwA","fields":["net_total"]}],"hideBorder":true,"hideLabel":true}]}]',
},
}
@ -340,6 +364,44 @@ def add_default_lead_sources():
doc.insert()
def add_default_lost_reasons():
lost_reasons = [
{
"reason": "Pricing",
"description": "The prospect found the pricing to be too high or not competitive.",
},
{"reason": "Competition", "description": "The prospect chose a competitor's product or service."},
{
"reason": "Budget Constraints",
"description": "The prospect did not have the budget to proceed with the purchase.",
},
{
"reason": "Missing Features",
"description": "The prospect felt that the product or service was missing key features they needed.",
},
{
"reason": "Long Sales Cycle",
"description": "The sales process took too long, leading to loss of interest.",
},
{
"reason": "No Decision-Maker",
"description": "The prospect was not the decision-maker and could not proceed.",
},
{"reason": "Unresponsive Prospect", "description": "The prospect did not respond to follow-ups."},
{"reason": "Poor Fit", "description": "The prospect was not a good fit for the product or service."},
{"reason": "Other", "description": ""},
]
for reason in lost_reasons:
if frappe.db.exists("CRM Lost Reason", reason["reason"]):
continue
doc = frappe.new_doc("CRM Lost Reason")
doc.lost_reason = reason["reason"]
doc.description = reason["description"]
doc.insert()
def add_standard_dropdown_items():
crm_settings = frappe.get_single("FCRM Settings")
@ -353,3 +415,88 @@ def add_standard_dropdown_items():
crm_settings.append("dropdown_items", item)
crm_settings.save()
def add_default_scripts():
from crm.fcrm.doctype.fcrm_settings.fcrm_settings import create_forecasting_script
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

@ -35,7 +35,7 @@ def set_default_calling_medium(medium):
frappe.get_doc(
{
"doctype": "CRM Telephony Agent",
"agent": frappe.session.user,
"user": frappe.session.user,
"default_medium": medium,
}
).insert(ignore_permissions=True)
@ -110,12 +110,12 @@ def get_contact_by_phone_number(phone_number):
number = parse_phone_number(phone_number)
if number.get("is_valid"):
return get_contact(number.get("national_number"))
return get_contact(number.get("national_number"), number.get("country"))
else:
return get_contact(phone_number, exact_match=True)
return get_contact(phone_number, number.get("country"), exact_match=True)
def get_contact(phone_number, exact_match=False):
def get_contact(phone_number, country="IN", exact_match=False):
if not phone_number:
return {"mobile_no": phone_number}
@ -149,11 +149,11 @@ def get_contact(phone_number, exact_match=False):
deal = frappe.db.get_value(
"CRM Contacts", {"contact": contact.name, "is_primary": 1}, "parent"
)
if are_same_phone_number(contact.mobile_no, phone_number, validate=not exact_match):
if are_same_phone_number(contact.mobile_no, phone_number, country, validate=not exact_match):
contact["deal"] = deal
return contact
# Else, return the first contact
if are_same_phone_number(contacts[0].mobile_no, phone_number, validate=not exact_match):
if are_same_phone_number(contacts[0].mobile_no, phone_number, country, validate=not exact_match):
return contacts[0]
# Else, Check if the number is associated with a lead
@ -173,7 +173,7 @@ def get_contact(phone_number, exact_match=False):
if len(leads):
for lead in leads:
if are_same_phone_number(lead.mobile_no, phone_number, validate=not exact_match):
if are_same_phone_number(lead.mobile_no, phone_number, country, validate=not exact_match):
lead["lead"] = lead.name
lead["full_name"] = lead.lead_name
return lead

View File

@ -242,19 +242,18 @@ def get_call_log_status(call_payload, direction="inbound"):
elif status == "failed":
return "Failed"
status = call_payload.get("DialCallStatus")
call_type = call_payload.get("CallType")
dial_call_status = call_payload.get("DialCallStatus")
status = call_payload.get("DialCallStatus") or call_payload.get("Status")
if call_type == "incomplete" and dial_call_status == "no-answer":
if call_type == "incomplete" and status == "no-answer":
status = "No Answer"
elif call_type == "client-hangup" and dial_call_status == "canceled":
elif call_type == "client-hangup" and status == "canceled":
status = "Canceled"
elif call_type == "incomplete" and dial_call_status == "failed":
elif call_type == "incomplete" and status == "failed":
status = "Failed"
elif call_type == "completed":
status = "Completed"
elif dial_call_status == "busy":
elif status == "busy":
status = "Ringing"
return status

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

6396
crm/locale/cs.po Normal file

File diff suppressed because it is too large Load Diff

6396
crm/locale/da.po Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

6396
crm/locale/id.po Normal file

File diff suppressed because it is too large Load Diff

6396
crm/locale/it.po Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

6396
crm/locale/my.po Normal file

File diff suppressed because it is too large Load Diff

6396
crm/locale/nb.po Normal file

File diff suppressed because it is too large Load Diff

6396
crm/locale/nl.po Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

6396
crm/locale/pt_BR.po Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

6396
crm/locale/sr.po Normal file

File diff suppressed because it is too large Load Diff

6396
crm/locale/sr_CS.po Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

6396
crm/locale/ta.po Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

6396
crm/locale/vi.po Normal file

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -12,3 +12,8 @@ crm.patches.v1_0.create_default_sidebar_fields_layout
crm.patches.v1_0.update_deal_quick_entry_layout
crm.patches.v1_0.update_layouts_to_new_format
crm.patches.v1_0.move_twilio_agent_to_telephony_agent
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()

View File

@ -0,0 +1,5 @@
from crm.install import add_default_lost_reasons
def execute():
add_default_lost_reasons()

View File

@ -0,0 +1,5 @@
from crm.install import add_default_scripts
def execute():
add_default_scripts()

View File

@ -0,0 +1,24 @@
import frappe
def execute():
deal_statuses = frappe.get_all("CRM Deal Status", fields=["name", "probability", "deal_status"])
for status in deal_statuses:
if status.probability is None or status.probability == 0:
if status.deal_status == "Qualification":
probability = 10
elif status.deal_status == "Demo/Making":
probability = 25
elif status.deal_status == "Proposal/Quotation":
probability = 50
elif status.deal_status == "Negotiation":
probability = 70
elif status.deal_status == "Ready to Close":
probability = 90
elif status.deal_status == "Won":
probability = 100
else:
probability = 0
frappe.db.set_value("CRM Deal Status", status.name, "probability", probability)

View File

@ -0,0 +1,44 @@
import frappe
def execute():
deal_statuses = frappe.get_all("CRM Deal Status", fields=["name", "type", "deal_status"])
openStatuses = ["New", "Open", "Unassigned", "Qualification"]
ongoingStatuses = [
"Demo/Making",
"Proposal/Quotation",
"Negotiation",
"Ready to Close",
"Demo Scheduled",
"Follow Up",
]
onHoldStatuses = ["On Hold", "Paused", "Stalled", "Awaiting Reply"]
wonStatuses = ["Won", "Closed Won", "Successful", "Completed"]
lostStatuses = [
"Lost",
"Closed",
"Closed Lost",
"Junk",
"Unqualified",
"Disqualified",
"Cancelled",
"No Response",
]
for status in deal_statuses:
if not status.type or status.type is None or status.type == "Open":
if status.deal_status in openStatuses:
type = "Open"
elif status.deal_status in ongoingStatuses:
type = "Ongoing"
elif status.deal_status in onHoldStatuses:
type = "On Hold"
elif status.deal_status in wonStatuses:
type = "Won"
elif status.deal_status in lostStatuses:
type = "Lost"
else:
type = "Ongoing"
frappe.db.set_value("CRM Deal Status", status.name, "type", type)

Some files were not shown because too many files have changed in this diff Show More