Compare commits

..

746 Commits

Author SHA1 Message Date
Frappe PR Bot
cf849f7dff chore(release): Bumped to Version 1.53.1 2025-09-25 16:33:11 +00:00
Shariq Ansari
3e9fdb8d20
Merge pull request #1287 from frappe/main-hotfix 2025-09-25 22:02:44 +05:30
Shariq Ansari
260755fd2e
Merge pull request #1286 from frappe/mergify/bp/main-hotfix/pr-1279 2025-09-25 21:57:28 +05:30
Shariq Ansari
85df56b464
Merge pull request #1285 from frappe/mergify/bp/main-hotfix/pr-1284 2025-09-25 21:53:53 +05:30
Shariq Ansari
a9e956b5fc chore: Norwegian Bokmal translations
(cherry picked from commit 9e92282e25cd1d3e5c33b87b02ad6dfdc09158cc)
2025-09-25 16:23:42 +00:00
Shariq Ansari
905eb63c5f chore: Serbian (Latin) translations
(cherry picked from commit 0138716e070b8098fd37c3ee67496c7a0d1ff473)
2025-09-25 16:23:42 +00:00
Shariq Ansari
3eee437014 chore: Serbian (Cyrillic) translations
(cherry picked from commit 589c95e263bf70fda044ef841a623ccda510c744)
2025-09-25 16:23:42 +00:00
Shariq Ansari
4498de2041 chore: Norwegian Bokmal translations
(cherry picked from commit a4e2663b2418c935c8279fab97934dff0d2221b7)
2025-09-25 16:23:41 +00:00
Shariq Ansari
bfb0d25765 chore: Norwegian Bokmal translations
(cherry picked from commit f91ac266ca921427fa2d38af4e8d8f847d46e111)
2025-09-25 16:23:41 +00:00
Shariq Ansari
9dd6ffa1e1 chore: Danish translations
(cherry picked from commit 415d5410ba707a59a6cc6a7cf8d0bafc8a6a7e50)
2025-09-25 16:23:41 +00:00
Shariq Ansari
05322e805f chore: Esperanto translations
(cherry picked from commit 9fc20a3078922b45440551343f7fb032d17d814b)
2025-09-25 16:23:40 +00:00
Shariq Ansari
8dc6db3218 chore: Croatian translations
(cherry picked from commit 43dadfe746f3ade875bf5420edca1b3bc92cc372)
2025-09-25 16:23:40 +00:00
Shariq Ansari
1b63384eac chore: Thai translations
(cherry picked from commit 56071d5e0dd520d96b24ce92d9079823921402aa)
2025-09-25 16:23:40 +00:00
Shariq Ansari
37bbbb6b4b chore: Persian translations
(cherry picked from commit b0e79d0aef3a3fe637c6d0d2d734118b095a52a5)
2025-09-25 16:23:40 +00:00
Shariq Ansari
6f0244c2b6 chore: Vietnamese translations
(cherry picked from commit 5848649955c084076afda007e21df1b0940394f6)
2025-09-25 16:23:39 +00:00
Shariq Ansari
e08bc9cd20 chore: Chinese Simplified translations
(cherry picked from commit 3c5ee979f86d9a0cdbd6717c91253622e47e3f8d)
2025-09-25 16:23:39 +00:00
Shariq Ansari
2043157567 chore: Turkish translations
(cherry picked from commit 2acd7476c8e1f92f2747a84666badafe5b204910)
2025-09-25 16:23:39 +00:00
Shariq Ansari
8093a422cd chore: Russian translations
(cherry picked from commit 66c586582836bcbd3210a4cd2e254edf3fc9b9f5)
2025-09-25 16:23:38 +00:00
Shariq Ansari
4bef919d38 chore: Portuguese translations
(cherry picked from commit 103a137af12912bcf388b06a14c84abadbad8979)
2025-09-25 16:23:38 +00:00
Shariq Ansari
874947b8ae chore: Dutch translations
(cherry picked from commit 52cc70d704a284bd41696e67e2c1fb24142dc6ee)
2025-09-25 16:23:38 +00:00
Shariq Ansari
ca90c0406e chore: Hungarian translations
(cherry picked from commit d72dcee7b663d35c83a5658815a1cdd529b445c3)
2025-09-25 16:23:38 +00:00
Shariq Ansari
6bf27d852b chore: Czech translations
(cherry picked from commit b473b27f9ace8d76023b13ec1cf57e81cc487835)
2025-09-25 16:23:37 +00:00
Shariq Ansari
793cb76789 chore: Arabic translations
(cherry picked from commit 8805560144baa224c6f3ac5758e9d3d288e60f45)
2025-09-25 16:23:37 +00:00
Shariq Ansari
ff07054ca3 chore: Spanish translations
(cherry picked from commit 3f0c4e9614d8081344dd8ef213bed525c69a4b1a)
2025-09-25 16:23:37 +00:00
Shariq Ansari
2ee5269d3e chore: French translations
(cherry picked from commit 2b13c3f27704a8b50facb7636f4a82810e843bd6)
2025-09-25 16:23:36 +00:00
Shariq Ansari
e27954da52 chore: German translations
(cherry picked from commit b6fa3bf32b3c21e82917061da94f450e81f48323)
2025-09-25 16:23:36 +00:00
Shariq Ansari
2faa0d0f04 chore: Serbian (Latin) translations
(cherry picked from commit ae9e59aa0002112fa22192d15df43491b1145c8c)
2025-09-25 16:23:36 +00:00
Shariq Ansari
f1664eec2f chore: Bosnian translations
(cherry picked from commit 4533becc620ea06bc61043eb58e8350b90445950)
2025-09-25 16:23:36 +00:00
Shariq Ansari
7f2efea7cb chore: Indonesian translations
(cherry picked from commit 57bd9fe70a6f09d336b8b17dd1215481f2f5d03d)
2025-09-25 16:23:35 +00:00
Shariq Ansari
d2cc6b7c2e chore: Portuguese, Brazilian translations
(cherry picked from commit 013c21a5d1b564632b0383893d4b45512afa9e4c)
2025-09-25 16:23:35 +00:00
Shariq Ansari
1afb6d6827 chore: Swedish translations
(cherry picked from commit 9a780039e589e369f76f4fe9b4e0dff0902bd859)
2025-09-25 16:23:35 +00:00
Shariq Ansari
ccaf136830 chore: Serbian (Cyrillic) translations
(cherry picked from commit 1bd62289dc720edc9515a3677ac377732ae1dc60)
2025-09-25 16:23:34 +00:00
Shariq Ansari
58a41d1b11 chore: Polish translations
(cherry picked from commit f7382f40ac78be3804f34866162f30329f742d76)
2025-09-25 16:23:34 +00:00
Shariq Ansari
777f3ac06c chore: Italian translations
(cherry picked from commit 3c870ce042a7d165ad914f90cf84fd5473ad8243)
2025-09-25 16:23:34 +00:00
Shariq Ansari
105c78e264
Merge pull request #1283 from frappe/mergify/bp/main-hotfix/pr-1282
fix: add validation for mandatory fields in useDocument (backport #1282)
2025-09-25 21:53:09 +05:30
Shariq Ansari
46cc1d2924 build(deps): bump frappeui to 0.1.201
(cherry picked from commit 171060df8ade73f6b9ef4b51945c76604c759299)
2025-09-25 16:22:33 +00:00
Shariq Ansari
ff4ca9fe66 fix: add validation for mandatory fields in useDocument
(cherry picked from commit dbcda4c548270f4b030d819857b1f393fdaadecb)
2025-09-25 16:18:30 +00:00
Shariq Ansari
4989dc0921
Merge pull request #1277 from shariquerik/backport-1125
fix: Bulk Delete "Reference Doctype must be set first" Error (backport #1125)
2025-09-22 16:12:16 +05:30
Shariq Ansari
1e613ebcd1 fix: Bulk Delete 'Reference Doctype must be set first' Error backport (#1125) 2025-09-22 16:04:53 +05:30
Frappe PR Bot
4f8f195d77 chore(release): Bumped to Version 1.53.0 2025-09-22 09:55:37 +00:00
Shariq Ansari
af64b86a04
Merge pull request #1276 from frappe/main-hotfix 2025-09-22 15:25:13 +05:30
Shariq Ansari
7e9bc0524e
Merge pull request #1275 from frappe/mergify/bp/main-hotfix/pr-1266 2025-09-22 15:18:12 +05:30
Shariq Ansari
9d0a0d1d32
Merge pull request #1273 from frappe/mergify/bp/main-hotfix/pr-1272 2025-09-22 15:17:51 +05:30
Shariq Ansari
9c84a8be7f
Merge pull request #1274 from frappe/mergify/bp/main-hotfix/pr-1262 2025-09-22 15:17:42 +05:30
frappe-pr-bot
d24537489e chore: update POT file
(cherry picked from commit 625e472303a4d759024a744bd93bc8d721537a0a)
2025-09-22 09:41:24 +00:00
Shariq Ansari
bd89b3b356 chore: Norwegian Bokmal translations
(cherry picked from commit ce632c69c1e634dc0feed03eec3f4c76370e7dcf)
2025-09-22 09:41:23 +00:00
Shariq Ansari
988fb90ddb chore: Norwegian Bokmal translations
(cherry picked from commit 93ed6fcdddac8a903e470ee35d1cbcca7e9ba5cf)
2025-09-22 09:41:23 +00:00
Shariq Ansari
8018b1766c chore: Norwegian Bokmal translations
(cherry picked from commit e3eff7f78de04f49bb78a3e1401048a42d4bf2eb)
2025-09-22 09:41:23 +00:00
Shariq Ansari
9c4c2a0aca chore: Norwegian Bokmal translations
(cherry picked from commit 394da5e0024dfce029f90346ff695dc7f7a67e5f)
2025-09-22 09:41:23 +00:00
Shariq Ansari
803e639961 build(deps): bump frappeui to 0.1.200
(cherry picked from commit 96c0c99939b30880ddf27b91f3f6b18c95ef3409)
2025-09-22 09:40:21 +00:00
Shariq Ansari
fabd362b2a
Merge pull request #1260 from frappe/mergify/bp/main-hotfix/pr-1256 2025-09-18 15:44:32 +05:30
Shariq Ansari
7dd98733f1
chore: resolved conflict 2025-09-18 15:38:44 +05:30
Shariq Ansari
ee4b7721b0
chore: resolved conflict 2025-09-18 15:37:11 +05:30
Shariq Ansari
95bc551254
chore: resolved conflict 2025-09-18 15:35:03 +05:30
Shariq Ansari
2546bdabb1 refactor: adjust padding and improve layout for Settings component
(cherry picked from commit d687a2eb56142c49b2b776dec55ad533556421f6)
2025-09-18 09:59:25 +00:00
Shariq Ansari
af248964c6 refactor: adjust padding and improve layout for Currency and Forecasting settings components
(cherry picked from commit 1044adc494b0b5b7f347aaf0080914a28be56eb9)
2025-09-18 09:59:25 +00:00
Shariq Ansari
8749f7bfd0 refactor: update styling and improve layout for assignment rules components
(cherry picked from commit 9f95a3a2b2132357708db03b9b4922f356150ff4)
2025-09-18 09:59:25 +00:00
Shariq Ansari
d18618b856 refactor: replace EmailMultiSelect with FormControl for inviting users by email
(cherry picked from commit 69f80903118965f500199f1b3368deb195882699)

# Conflicts:
#	frontend/src/components/Settings/InviteUserPage.vue
2025-09-18 09:59:24 +00:00
Shariq Ansari
ce4af4907a refactor: remove TemplateOption component usage and simplify dropdown options in multiple components
(cherry picked from commit ac34ac9b87b9c671be75401a545e09e0e83ac378)

# Conflicts:
#	frontend/src/components/Settings/Users.vue
2025-09-18 09:59:24 +00:00
Shariq Ansari
84d24a384b refactor: update Vite configuration to support dynamic loading of frappe-ui in development mode
(cherry picked from commit 129f8a00b66d87529c21ef085e66dc7864a3776e)
2025-09-18 09:59:24 +00:00
Shariq Ansari
29d86859d4 revert: create dynamic alias to use components from frontend vue apps
(cherry picked from commit 6328b6941bb620e47cebe82519df3f1453f355ae)
2025-09-18 09:59:23 +00:00
Shariq Ansari
be452fee58 refactor: reduce gap in Brand logo and Favicon sections for improved layout
(cherry picked from commit fbc9e37036d5720948381ca891714d78af001433)
2025-09-18 09:59:23 +00:00
Shariq Ansari
100eec0677 refactor: remove icon-left from Update button in multiple settings components
(cherry picked from commit 149901f6054f000d503ef8940037c13bd2e344f3)
2025-09-18 09:59:23 +00:00
Shariq Ansari
a4d3852c0e feat: Auto update expected deal value based on products value
(cherry picked from commit 7e21a5fee206723cf714f7a8732bb8929aaa57df)
2025-09-18 09:59:23 +00:00
Shariq Ansari
0399fc32be refactor: add ForecastingSettings component and remove GeneralSettingsPage component
(cherry picked from commit f4ff6bbdf306a89b78aab82df972bf55e1e0d82d)
2025-09-18 09:59:22 +00:00
Shariq Ansari
a79192ef4d fix: add auto-update expected deal value checkbox in FCRM settings
(cherry picked from commit 915023317310178d67306bb6d8b48e224e5644ae)
2025-09-18 09:59:22 +00:00
Shariq Ansari
e10ec543a7 refactor: CurrencySettings component
(cherry picked from commit 186584c1ac79170afa4ef8860bff9d3d3d91cadc)
2025-09-18 09:59:22 +00:00
Shariq Ansari
1962b9a103 refactor: update BrandSettings component to improve logo and favicon handling
(cherry picked from commit 3752c611576778f028ba78d6c1ae533a88c6040b)
2025-09-18 09:59:21 +00:00
Shariq Ansari
a3abaa57ec refactor: HomeActions component
(cherry picked from commit a6ecc5cfeda51781286d013cf3a738b8a3adfdc5)
2025-09-18 09:59:21 +00:00
Shariq Ansari
1bf3f7a38c refactor: BrandSettings component
(cherry picked from commit 84e0fe30a9667468ea9ddbb0bc768e3da62620d3)
2025-09-18 09:59:20 +00:00
Shariq Ansari
af81750388 refactor: enhance Settings component structure
(cherry picked from commit 03acea69b130cfdbdc00994c8d9930ad948cb64c)

# Conflicts:
#	frontend/src/components/Settings/Settings.vue
2025-09-18 09:59:20 +00:00
Shariq Ansari
7330a3c2a5 refactor: clean up ImageUploader component and improve label handling
(cherry picked from commit e19f75083147faaf988bcbef448e9d1ddbb9179a)
2025-09-18 09:59:19 +00:00
Shariq Ansari
9e8a4024a5
Merge pull request #1255 from frappe/mergify/bp/main-hotfix/pr-1252
fix: paddings and labels (backport #1252)
2025-09-18 15:27:27 +05:30
Shariq Ansari
7ef00965fa
Merge branch 'main-hotfix' into mergify/bp/main-hotfix/pr-1252 2025-09-18 15:21:52 +05:30
Shariq Ansari
97925aae15
Merge pull request #1259 from frappe/mergify/bp/main-hotfix/pr-1257 2025-09-18 15:17:19 +05:30
Shariq Ansari
0b75228722 chore: Portuguese translations
(cherry picked from commit fca831b92e633f7a7f6cdd09f66d83bac19e2590)
2025-09-18 09:42:12 +00:00
Shariq Ansari
a360fa774b
Merge pull request #1258 from frappe/mergify/bp/main-hotfix/pr-1206 2025-09-18 15:11:28 +05:30
Shariq Ansari
4601b56ee1
chore: resolved conflict 2025-09-18 15:05:35 +05:30
Pratik Badhe
d985a44291 feat: add assignment rule
(cherry picked from commit 0c5684905f44af211189bf674735b046858a5b86)

# Conflicts:
#	frontend/components.d.ts
#	yarn.lock
2025-09-18 09:19:54 +00:00
Pratik Badhe
ce66705e9c revert: yarn.lock file
(cherry picked from commit 41ef219d0abd0c0036d7697dc5a8b8ab78a81344)
2025-09-17 06:47:25 +00:00
Pratik Badhe
004923419c fix: paddings and labels
(cherry picked from commit db577afc568b56b49846773b16b638e0cf1444fa)

# Conflicts:
#	frontend/src/components/Settings/AssignmentRules/AssigneeRules.vue
#	frontend/src/components/Settings/AssignmentRules/AssignmentRuleView.vue
#	frontend/src/components/Settings/AssignmentRules/AssignmentRules.vue
2025-09-17 06:47:25 +00:00
Shariq Ansari
49ed1ac174
Merge pull request #1254 from frappe/mergify/bp/main-hotfix/pr-1253 2025-09-17 11:55:38 +05:30
Shariq Ansari
a7dd1e9bf6 chore: Norwegian Bokmal translations
(cherry picked from commit b6e3cdfc378c9ab6322e6148d28387e5d399310c)
2025-09-17 06:08:01 +00:00
Shariq Ansari
4cfd0022f4 chore: Danish translations
(cherry picked from commit c0171c0555fe7091102b12cd2ccd8ec714dbe34d)
2025-09-17 06:08:00 +00:00
Shariq Ansari
fc3d8cd94d chore: Esperanto translations
(cherry picked from commit 6f154e191a816c118ffc190a36277ea9235eedc3)
2025-09-17 06:08:00 +00:00
Shariq Ansari
5473a93b5e chore: Croatian translations
(cherry picked from commit 552e500a31bca989d7b4554cfc0aa0015635098c)
2025-09-17 06:08:00 +00:00
Shariq Ansari
57d306ea1f chore: Thai translations
(cherry picked from commit bf6940a6ff7cd972c384a050068aaa2835bc371a)
2025-09-17 06:07:59 +00:00
Shariq Ansari
7c324bd07f chore: Persian translations
(cherry picked from commit dc9b07b02a5ea4443967d3261781d2786e7ff810)
2025-09-17 06:07:59 +00:00
Shariq Ansari
09421217b4 chore: Vietnamese translations
(cherry picked from commit 0a45094c33db76bea8606c02b2b0985e6e35e34f)
2025-09-17 06:07:59 +00:00
Shariq Ansari
630dfcd0e7 chore: Chinese Simplified translations
(cherry picked from commit 247d8e043e548d30ffc4494544cdf7e95bec94e1)
2025-09-17 06:07:58 +00:00
Shariq Ansari
b999a375b3 chore: Turkish translations
(cherry picked from commit 73a1ecd418e0ca1ba40442aa0338b7f6853d0650)
2025-09-17 06:07:58 +00:00
Shariq Ansari
b5f5a3b5d5 chore: Russian translations
(cherry picked from commit 77e7bb011b5357465f6565eeddddd4ec160c1d3c)
2025-09-17 06:07:57 +00:00
Shariq Ansari
814d39572a chore: Portuguese translations
(cherry picked from commit 9233e77ab8376301a61c56d4ee072fb3c4caea4b)
2025-09-17 06:07:57 +00:00
Shariq Ansari
6fc4c0699a chore: Dutch translations
(cherry picked from commit 32e5d56ef19da5c0577334992a43d3c0db761700)
2025-09-17 06:07:57 +00:00
Shariq Ansari
50ea06a568 chore: Hungarian translations
(cherry picked from commit cea6b6c6b4bfe87e6c533aadba632f60081853bc)
2025-09-17 06:07:56 +00:00
Shariq Ansari
daf0ddaab4 chore: Czech translations
(cherry picked from commit 2d636d7ffb252e52352e0883747c6fb158d42774)
2025-09-17 06:07:56 +00:00
Shariq Ansari
70107a4836 chore: Arabic translations
(cherry picked from commit 9d9caf2856b5fd1c1f5bc88024292a2dea3dd1f3)
2025-09-17 06:07:56 +00:00
Shariq Ansari
f2e6380d3e chore: Spanish translations
(cherry picked from commit 4ff4f3c5b53fe6ea60623894770ecad3b2289441)
2025-09-17 06:07:56 +00:00
Shariq Ansari
eed1e23b5b chore: French translations
(cherry picked from commit 8167e1388da8693ab2d14dba876d7092a40d1875)
2025-09-17 06:07:55 +00:00
Shariq Ansari
1bb75dd911 chore: German translations
(cherry picked from commit 8e3cf3846aad4c72ff8d1b53a662d95565ce227a)
2025-09-17 06:07:55 +00:00
Shariq Ansari
1086ce406f chore: Serbian (Latin) translations
(cherry picked from commit 2d8ada04c869cc4f0652c3d2e2946820e1b89335)
2025-09-17 06:07:55 +00:00
Shariq Ansari
39c5497363 chore: Bosnian translations
(cherry picked from commit 4fba2353cffcab5e223318b74830390046ee1deb)
2025-09-17 06:07:54 +00:00
Shariq Ansari
4bc31431e7 chore: Indonesian translations
(cherry picked from commit f251d83e97cdca93447de491e228e0648f16c7f0)
2025-09-17 06:07:54 +00:00
Shariq Ansari
fe290877e4 chore: Portuguese, Brazilian translations
(cherry picked from commit 283b34662e6da88c68273cd64c708e63a7aabadb)
2025-09-17 06:07:54 +00:00
Shariq Ansari
e4bdc0586e chore: Swedish translations
(cherry picked from commit 9bcfcf4ac722caf126cf311079c3220590e8c91d)
2025-09-17 06:07:53 +00:00
Shariq Ansari
695f9e1303 chore: Serbian (Cyrillic) translations
(cherry picked from commit d80bbcd33d99872ffe28cc334c3c523ac775506e)
2025-09-17 06:07:53 +00:00
Shariq Ansari
98747bdc2a chore: Polish translations
(cherry picked from commit 42ee5ea64df69c172cd683aa9e1169969267158b)
2025-09-17 06:07:53 +00:00
Shariq Ansari
16ed1ad060 chore: Italian translations
(cherry picked from commit 1472a7f33d50686df2ff5c978682d3a693b5d674)
2025-09-17 06:07:52 +00:00
Shariq Ansari
ff312d964b
Merge pull request #1251 from frappe/main-hotfix 2025-09-16 15:23:38 +05:30
Shariq Ansari
49d7af5548 build(deps): bump frappeui to 0.1.197 2025-09-16 14:51:32 +05:30
Shariq Ansari
a30d21c346
Merge pull request #1250 from frappe/mergify/bp/main-hotfix/pr-1242 2025-09-16 14:25:58 +05:30
Shariq Ansari
f459bd57ba
Merge pull request #1249 from frappe/mergify/bp/main-hotfix/pr-1245 2025-09-16 14:25:50 +05:30
Shariq Ansari
b4d89e1a5a chore: Danish translations
(cherry picked from commit 2e5f4a9d22f615ff8f57afd4cccb763fb3b0d1da)
2025-09-16 08:50:23 +00:00
Shariq Ansari
25bc9d8acb chore: Persian translations
(cherry picked from commit 100d01334a4fa5d9b9c686b27a6c794fc1e8cd35)
2025-09-16 08:50:22 +00:00
Shariq Ansari
568477f9c7 chore: Portuguese translations
(cherry picked from commit 03ab96d94f49599ccc0a2ca4fe4045540d59403a)
2025-09-16 08:50:22 +00:00
Shariq Ansari
9c04ade20d chore: Norwegian Bokmal translations
(cherry picked from commit 6f640f5eee07558b133fe1acea6b26e9f23783c1)
2025-09-16 08:50:22 +00:00
Shariq Ansari
7940211fad chore: Norwegian Bokmal translations
(cherry picked from commit 376917bc75086608fcd774289d119c6a6adb2d32)
2025-09-16 08:50:21 +00:00
Shariq Ansari
df0968ed67 chore: Portuguese translations
(cherry picked from commit 54753d3274a5e75dd684efafca91517f04104620)
2025-09-16 08:50:21 +00:00
Shariq Ansari
89462e63cb chore: Turkish translations
(cherry picked from commit 3c3108a9c19bab39ca67bb7efbc8e299ccfcc5ea)
2025-09-16 08:50:21 +00:00
Shariq Ansari
23c53ffa9a chore: Norwegian Bokmal translations
(cherry picked from commit e0cfae1eb3fae321bf187c2e8bae9875e7409bb8)
2025-09-16 08:50:21 +00:00
Shariq Ansari
ae3df8d391 chore: Norwegian Bokmal translations
(cherry picked from commit fa03245effea3cabe2e536c99ec4ef65460d80c4)
2025-09-16 08:50:20 +00:00
Shariq Ansari
2d51933ceb chore: Serbian (Latin) translations
(cherry picked from commit f253392ba74c28f78357fe70d886db6eaf73128f)
2025-09-16 08:50:20 +00:00
Shariq Ansari
a7958dc2a2 chore: Serbian (Cyrillic) translations
(cherry picked from commit 6e608d845b99b959bf18232abf0235a87b2b274f)
2025-09-16 08:50:20 +00:00
frappe-pr-bot
1c4f78b01c chore: update POT file
(cherry picked from commit 1627cf1e5488f596e463b6253855cf8eff17064f)
2025-09-16 08:49:19 +00:00
Shariq Ansari
2722ef6cad
Merge pull request #1241 from frappe/mergify/bp/main-hotfix/pr-1240 2025-09-09 14:30:02 +05:30
Shariq Ansari
ac7d3907c2 chore: Norwegian Bokmal translations
(cherry picked from commit ffd2452675e3710e5e64535d6b29faff736c1607)
2025-09-09 08:57:46 +00:00
Frappe PR Bot
17b7c6ecef chore(release): Bumped to Version 1.52.11 2025-09-08 14:20:41 +00:00
Shariq Ansari
8d7a155d78
Merge pull request #1239 from frappe/main-hotfix 2025-09-08 19:49:39 +05:30
Shariq Ansari
6dc85ad1b2
Merge branch 'main' into main-hotfix 2025-09-08 19:42:43 +05:30
Shariq Ansari
ac98c1a090
Merge pull request #1238 from frappe/mergify/bp/main-hotfix/pr-1237 2025-09-08 14:53:07 +05:30
Shariq Ansari
90a6bde438 chore: Norwegian Bokmal translations
(cherry picked from commit 097c58b991eac4253b637f535d13132bf6d21dc5)
2025-09-08 05:50:47 +00:00
Shariq Ansari
5fea7bf0e2 chore: Danish translations
(cherry picked from commit 64bf702b62d55eed433106bfc6b00887a58c29cb)
2025-09-08 05:50:46 +00:00
Shariq Ansari
1031e9c4ec chore: Esperanto translations
(cherry picked from commit 7e27e9f45ef72862626dd756cbf3cf50730ddce2)
2025-09-08 05:50:46 +00:00
Shariq Ansari
c6e4b9b5d3 chore: Croatian translations
(cherry picked from commit ee19b344ec333b53e0a585d99465cf908d58318e)
2025-09-08 05:50:46 +00:00
Shariq Ansari
f2a4b9ec56 chore: Thai translations
(cherry picked from commit eb70553fea56eb054e28676287323367b1aea3e4)
2025-09-08 05:50:46 +00:00
Shariq Ansari
14a1af4455 chore: Persian translations
(cherry picked from commit 9e4d268b504220f3a98a1411b9d0c0961e01f9b5)
2025-09-08 05:50:45 +00:00
Shariq Ansari
e3ab227124 chore: Vietnamese translations
(cherry picked from commit d92c25ab4ea769593ed4252a4058a85713b7d7ba)
2025-09-08 05:50:45 +00:00
Shariq Ansari
5f6cc26126 chore: Chinese Simplified translations
(cherry picked from commit 9975be4ff7984ccd663edf2544374319ff15e965)
2025-09-08 05:50:45 +00:00
Shariq Ansari
8051fd1f99 chore: Turkish translations
(cherry picked from commit 2442f6f2adc51a5a00a96798a20d0d856d24d85e)
2025-09-08 05:50:44 +00:00
Shariq Ansari
1fc98f619c chore: Russian translations
(cherry picked from commit e39a20f652a5900598eed1cb70c049a13ac38bec)
2025-09-08 05:50:44 +00:00
Shariq Ansari
5921af8c0b chore: Portuguese translations
(cherry picked from commit dcca47f3cad050cd573f40b648fd70f0baf6a704)
2025-09-08 05:50:44 +00:00
Shariq Ansari
fe505d33d2 chore: Dutch translations
(cherry picked from commit df8aaea3745a6f83baca39860afaaac3b91045a0)
2025-09-08 05:50:44 +00:00
Shariq Ansari
300f0b24e2 chore: Hungarian translations
(cherry picked from commit c3ac80afa8c74217a100c7b5d0ee24e1b738f62d)
2025-09-08 05:50:43 +00:00
Shariq Ansari
b7c26e35e9 chore: Czech translations
(cherry picked from commit 8d59359ef5bf29a4b46163f1fa118aa13d6ddf2b)
2025-09-08 05:50:43 +00:00
Shariq Ansari
4c7c8b915a chore: Arabic translations
(cherry picked from commit 53202f4a5b07eba3afc408736abc077eb4461a44)
2025-09-08 05:50:43 +00:00
Shariq Ansari
d80feb1e77 chore: Spanish translations
(cherry picked from commit 792db2725229ab4372b0349995acea0ecc313ee9)
2025-09-08 05:50:43 +00:00
Shariq Ansari
2a8c7307f0 chore: French translations
(cherry picked from commit c9bcbcf1d0a4e15ca65a5f77ef046156531b9128)
2025-09-08 05:50:42 +00:00
Shariq Ansari
0683d93621 chore: German translations
(cherry picked from commit 79a0c02f03b092f4259f63ec92d7372ee1cdafb6)
2025-09-08 05:50:42 +00:00
Shariq Ansari
5ce2fcd368 chore: Serbian (Latin) translations
(cherry picked from commit 2a5dbfb75d382c73ad94725030ae509049abe3bc)
2025-09-08 05:50:42 +00:00
Shariq Ansari
5372fdcaf1 chore: Bosnian translations
(cherry picked from commit b7443ff1bb90770e15af51b42a37e0dc35fb2d8a)
2025-09-08 05:50:41 +00:00
Shariq Ansari
9f46bbd25d chore: Indonesian translations
(cherry picked from commit 5ee9d5787a542b27d2059f76edc19c4657c7886b)
2025-09-08 05:50:41 +00:00
Shariq Ansari
87e82ce39e chore: Portuguese, Brazilian translations
(cherry picked from commit 426dc836ca4eb324ee1929bec06c646ea04095ab)
2025-09-08 05:50:41 +00:00
Shariq Ansari
443aeddca0 chore: Swedish translations
(cherry picked from commit d5287103797eebe59f2f821eb5ad9dafbc8cdadc)
2025-09-08 05:50:41 +00:00
Shariq Ansari
dc7d5f57b8 chore: Serbian (Cyrillic) translations
(cherry picked from commit 0a4cfa6055da2820f5ca9a52f25979f0e3cfd829)
2025-09-08 05:50:40 +00:00
Shariq Ansari
1cbd633e5b chore: Polish translations
(cherry picked from commit 1ca85157abc1f4ea412f34163469d3451fbab998)
2025-09-08 05:50:40 +00:00
Shariq Ansari
cf58a634e9 chore: Italian translations
(cherry picked from commit d8162a1dc48705ab7d9b89f0f9dacf1422a80c02)
2025-09-08 05:50:40 +00:00
Frappe PR Bot
b118e75bec chore(release): Bumped to Version 1.52.10 2025-09-07 14:02:13 +00:00
Shariq Ansari
2b1048fd83
Merge pull request #1236 from frappe/mergify/bp/main/pr-1234
fix: Organization is not getting renamed (backport #1234)
2025-09-07 19:31:08 +05:30
Shariq Ansari
7468f19b48
Merge pull request #1235 from frappe/mergify/bp/main-hotfix/pr-1234
fix: Organization is not getting renamed (backport #1234)
2025-09-07 19:30:57 +05:30
Shariq Ansari
f994dd36a9 fix: remove unnecessary class from Button component in TaskModal and add click.stop to Notes dropdown
(cherry picked from commit 30d95a6582cf8d5ba8e06e6d94e78b54c82e57a3)
2025-09-07 13:55:59 +00:00
Shariq Ansari
dc98613296 fix: add 'interactjs' to optimizeDeps include list in vite.config.js
(cherry picked from commit 24b580150af1e51db30c3c9fac8138bc62dd8a05)
2025-09-07 13:55:58 +00:00
Shariq Ansari
f132a46206 fix: update organization logo handling and add beforeFieldChange functionality to rename organization
(cherry picked from commit 1b7af2096f6bfc18094ce727e3e43754c279e51b)
2025-09-07 13:55:58 +00:00
Shariq Ansari
cfeac13c9c fix: remove unnecessary class from Button component in TaskModal and add click.stop to Notes dropdown
(cherry picked from commit 30d95a6582cf8d5ba8e06e6d94e78b54c82e57a3)
2025-09-07 13:55:55 +00:00
Shariq Ansari
b82dc0473a fix: add 'interactjs' to optimizeDeps include list in vite.config.js
(cherry picked from commit 24b580150af1e51db30c3c9fac8138bc62dd8a05)
2025-09-07 13:55:55 +00:00
Shariq Ansari
8f0e8f3f52 fix: update organization logo handling and add beforeFieldChange functionality to rename organization
(cherry picked from commit 1b7af2096f6bfc18094ce727e3e43754c279e51b)
2025-09-07 13:55:54 +00:00
Shariq Ansari
7a9da275da
Merge pull request #1233 from frappe/mergify/bp/main-hotfix/pr-1230 2025-09-07 18:07:30 +05:30
Shariq Ansari
cc25feea09 chore: Norwegian Bokmal translations
(cherry picked from commit 891d78c3b655a473c7215002f1c0fb35f92de89f)
2025-09-07 12:30:47 +00:00
Shariq Ansari
b64058bd10 chore: Norwegian Bokmal translations
(cherry picked from commit 4baee8351b911d47fad88aaa528254766e424e19)
2025-09-07 12:30:47 +00:00
Shariq Ansari
b6af543243
Merge pull request #1232 from frappe/mergify/bp/main/pr-1231 2025-09-07 17:59:11 +05:30
Shariq Ansari
7bcee291c7
chore: resolved conflict 2025-09-07 17:58:17 +05:30
frappe-pr-bot
570a45eeaf chore: update POT file
(cherry picked from commit 591076bf2778d5f98e4023665fcd8b84e7747b2f)

# Conflicts:
#	crm/locale/main.pot
2025-09-07 12:20:39 +00:00
Shariq Ansari
dcadd3d0c1
Merge pull request #1228 from frappe/mergify/bp/main-hotfix/pr-1224 2025-09-05 16:18:50 +05:30
Shariq Ansari
8d4975554d chore: Portuguese translations
(cherry picked from commit 023d949577a74af8ebe0d61b95da73ad988a64e0)
2025-09-05 10:48:09 +00:00
Shariq Ansari
4bf8c8d0b8
Merge pull request #1227 from frappe/mergify/bp/main-hotfix/pr-1226
fix: if contact email is updated it is updating previously opened contact (backport #1226)
2025-09-05 16:15:01 +05:30
Shariq Ansari
0d9264e5e2
chore: resolved conflict 2025-09-05 15:53:57 +05:30
Shariq Ansari
068f303448
chore: resolved conflict 2025-09-05 15:51:48 +05:30
Shariq Ansari
e8e4367eb7
chore: resolved conflict 2025-09-05 15:50:09 +05:30
Shariq Ansari
afadf9f8f4 fix: if contact email is updated it is updating previously opened contact
(cherry picked from commit 50708ebe32df130a4c6c5f678b5b9d0e85ccfa66)

# Conflicts:
#	frontend/components.d.ts
#	frontend/src/components/SidePanelLayout.vue
#	frontend/src/pages/Contact.vue
2025-09-05 10:16:18 +00:00
Shariq Ansari
8ab6da55de
Merge pull request #1223 from frappe/mergify/bp/main-hotfix/pr-1220 2025-09-04 17:54:42 +05:30
Shariq Ansari
b066eb8c75
Merge pull request #1222 from frappe/mergify/bp/main-hotfix/pr-1221
fix: address creation not returning to organization modal (backport #1221)
2025-09-04 17:53:54 +05:30
Shariq Ansari
c33f2e936a chore: Norwegian Bokmal translations
(cherry picked from commit 0cd527f6ef9b5409d1fb3c0ba6874302a4268704)
2025-09-04 12:22:34 +00:00
Shariq Ansari
2f02b8ccfd chore: Danish translations
(cherry picked from commit fead8c38767d8ccd8a81a77f9d04036354a452b5)
2025-09-04 12:22:33 +00:00
Shariq Ansari
9e9b0f7266 chore: Esperanto translations
(cherry picked from commit 1e6270df44b9d9b478de7c7cd9e44c634d2bffd2)
2025-09-04 12:22:33 +00:00
Shariq Ansari
148e6ef8bb chore: Croatian translations
(cherry picked from commit 7c9e9b954da6539744e6886aa8beb00b94748a78)
2025-09-04 12:22:33 +00:00
Shariq Ansari
00398b188c chore: Thai translations
(cherry picked from commit 6b2a1e7ff1f36fdc9ea4365fb44ff9575c2a7fbf)
2025-09-04 12:22:32 +00:00
Shariq Ansari
80e43864b7 chore: Persian translations
(cherry picked from commit 4aa506985faf95608edc9cf35a523648bab98574)
2025-09-04 12:22:32 +00:00
Shariq Ansari
9a9b91b76d chore: Vietnamese translations
(cherry picked from commit 496659af0a5a825aed132a46cc93e1e9c2612d79)
2025-09-04 12:22:32 +00:00
Shariq Ansari
d555222ebb chore: Chinese Simplified translations
(cherry picked from commit 9669b6d54c8e25345acd30677f0fc975352d0983)
2025-09-04 12:22:32 +00:00
Shariq Ansari
222ba09c67 chore: Turkish translations
(cherry picked from commit d406f7345cb08dbd1fc525aff638170c66430ef0)
2025-09-04 12:22:31 +00:00
Shariq Ansari
0c8a3edf5e chore: Russian translations
(cherry picked from commit f838ef56a66a6cf62a283d83982c067cfedf1a60)
2025-09-04 12:22:31 +00:00
Shariq Ansari
c44f7d5834 chore: Portuguese translations
(cherry picked from commit 77c5cb40e9f5abb32e38d5004dcdf1cac291e30a)
2025-09-04 12:22:31 +00:00
Shariq Ansari
f072fc992c chore: Dutch translations
(cherry picked from commit 0e1a4f00061f52e6b3e86b8a636d98a0bfc9addc)
2025-09-04 12:22:30 +00:00
Shariq Ansari
092310846c chore: Hungarian translations
(cherry picked from commit c4b5c56fe4daadc619445c3e8a29080b6f46fae7)
2025-09-04 12:22:30 +00:00
Shariq Ansari
eb00a7c692 chore: Czech translations
(cherry picked from commit 9066ed068826937aee7128c90e1f539c7aefb49d)
2025-09-04 12:22:30 +00:00
Shariq Ansari
8a7ed1e8f1 chore: Arabic translations
(cherry picked from commit 9a189aa5860f5069f2c993763297aa4d7d7381e7)
2025-09-04 12:22:29 +00:00
Shariq Ansari
a852e33605 chore: Spanish translations
(cherry picked from commit aa28206f572b0a1303a638f4af9c4290c472e4ec)
2025-09-04 12:22:29 +00:00
Shariq Ansari
7f3732f0e0 chore: French translations
(cherry picked from commit 628be7cb7cea5e50954518229ede04b6ad58eb1d)
2025-09-04 12:22:29 +00:00
Shariq Ansari
75a9bd290c chore: German translations
(cherry picked from commit b74f92c86e8d26798d3ead8748cef245e643f26b)
2025-09-04 12:22:28 +00:00
Shariq Ansari
687c1d362c chore: Serbian (Latin) translations
(cherry picked from commit 9190974293d715158d1ea6186b3588e7b74d7287)
2025-09-04 12:22:28 +00:00
Shariq Ansari
e771a63640 chore: Bosnian translations
(cherry picked from commit ffae4b10b9284f68ecbd478712148443fd3bbdc6)
2025-09-04 12:22:28 +00:00
Shariq Ansari
e87785fac5 chore: Indonesian translations
(cherry picked from commit b64baa239095fb34691f6713cf9ad8aede2e7f57)
2025-09-04 12:22:27 +00:00
Shariq Ansari
c84da0c7b4 chore: Portuguese, Brazilian translations
(cherry picked from commit 87c4d38c7787e7a227ac47490792ccdddeddc796)
2025-09-04 12:22:27 +00:00
Shariq Ansari
aeb4590a6f chore: Swedish translations
(cherry picked from commit bf32cbd3e8dacc2209aa59ba7d53dc90a0a02330)
2025-09-04 12:22:27 +00:00
Shariq Ansari
d6567c7f01 chore: Serbian (Cyrillic) translations
(cherry picked from commit 6d929d0e7e5dc2c6039383e554bbfa9012c0fb47)
2025-09-04 12:22:26 +00:00
Shariq Ansari
8083fc46a8 chore: Polish translations
(cherry picked from commit df31d8820cf51aa4177610c2cfa6b4aa51879e87)
2025-09-04 12:22:26 +00:00
Shariq Ansari
7f6a20ff17 chore: Italian translations
(cherry picked from commit 4bd5e5a9cc2e4158bb71bbd367f4c3bd2ff219c5)
2025-09-04 12:22:26 +00:00
Shariq Ansari
95df85f676 chore: removed commented code
(cherry picked from commit f9f405cc00e156a64df045dc6df700bb6ece929f)
2025-09-04 12:21:26 +00:00
Aftab Shaikh
728150e324 fix: address creation not returning to organization modal
(cherry picked from commit 32993af090f2e741254ffb2ce8241ed11122f11b)
2025-09-04 12:21:25 +00:00
Shariq Ansari
2ac8a06bae
Merge pull request #1218 from frappe/mergify/bp/main-hotfix/pr-1192
fix: Popup doesn't close after deletion (backport #1192)
2025-09-03 12:48:05 +05:30
Shariq Ansari
2f56af0384 chore: indentation fix
(cherry picked from commit 899481d752209687c26390e8a037dc7c139891fa)
2025-09-03 07:17:24 +00:00
Shariq Ansari
06d647dd72 chore: indentation fix
(cherry picked from commit 8a1ebeb52d7682e00e6626990408d81386d5093a)
2025-09-03 07:17:24 +00:00
Yashpal Patle
ee964637ac fixed popup deletion
(cherry picked from commit b55bf0918fed0c5c997e12f983616f7f1f152567)
2025-09-03 07:17:24 +00:00
Shariq Ansari
4f113fab91
Merge pull request #1217 from frappe/mergify/bp/main-hotfix/pr-1198 2025-09-03 12:28:51 +05:30
Shariq Ansari
8be5535a2b chore: removed comment
(cherry picked from commit 8d0d234ac131b52266bdebb248b232b4923f97c0)
2025-09-03 06:40:30 +00:00
Shariq Ansari
c0050dda71 chore: removed comment
(cherry picked from commit 7fda0db51b75f3d4b2b79db47640bb8fdfac26df)
2025-09-03 06:40:30 +00:00
anup-dh
56eecdd260 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.

(cherry picked from commit 486a06baf0d77cf27c75b9303750969c12c47743)
2025-09-03 06:40:30 +00:00
Shariq Ansari
ead86735d4
Merge pull request #1216 from frappe/mergify/bp/main-hotfix/pr-1202 2025-09-03 12:02:01 +05:30
Shariq Ansari
76f6da88f3
Merge pull request #1215 from frappe/mergify/bp/main-hotfix/pr-1204 2025-09-03 12:01:54 +05:30
Shariq Ansari
e252ac8370 chore: Norwegian Bokmal translations
(cherry picked from commit 33a7f50fed852b6d2052c0f40ef85a2438b8aff6)
2025-09-03 06:25:24 +00:00
Shariq Ansari
03b920570e chore: Danish translations
(cherry picked from commit 6ca2f83c0564e1f21953526d241e1bb00d3d040e)
2025-09-03 06:25:24 +00:00
Shariq Ansari
da4e84d6d0 chore: Hungarian translations
(cherry picked from commit c4f76cea6cdb5a8f9d636ef50f2e8fa8a477dca0)
2025-09-03 06:25:24 +00:00
Shariq Ansari
2f90a075fc chore: Norwegian Bokmal translations
(cherry picked from commit 22369825e8ca2ee1b61ec2c2592d10a723deeb92)
2025-09-03 06:25:24 +00:00
Shariq Ansari
de85fa5d5b chore: Hungarian translations
(cherry picked from commit 27b286c6dee73edc607baca4143f00495d484ca2)
2025-09-03 06:25:23 +00:00
Shariq Ansari
e43500887f chore: Norwegian Bokmal translations
(cherry picked from commit 3fb888561b52e607265b81bb9a56f7afbd5879fd)
2025-09-03 06:25:23 +00:00
Shariq Ansari
8f69a49e2c chore: Norwegian Bokmal translations
(cherry picked from commit 50bf6be95fffc7f382d7ca50ba0927105fefd9cd)
2025-09-03 06:25:23 +00:00
frappe-pr-bot
31cbe78320 chore: update POT file
(cherry picked from commit f2f0a4ba2befc88be6b4ee4cd35cc9f32393d5e0)
2025-09-03 06:25:19 +00:00
Shariq Ansari
fa85c61a0a
Merge pull request #1197 from frappe/mergify/bp/main-hotfix/pr-1196
chore: sync translations from crowdin (backport #1196)
2025-08-29 18:56:18 +05:30
Shariq Ansari
e87e1ad61d chore: Norwegian Bokmal translations
(cherry picked from commit 84aacb071703a988eaddbc7b2033e0d7c7a0db95)
2025-08-29 07:45:27 +00:00
Shariq Ansari
bd75fed217 chore: Danish translations
(cherry picked from commit 4c1a4f956e736ae1cfae529018d798448ec44812)
2025-08-29 07:45:27 +00:00
Shariq Ansari
1ede125c80 chore: Swedish translations
(cherry picked from commit 9f1d75817e197e987a37665771bd00b51894b341)
2025-08-29 07:45:26 +00:00
Shariq Ansari
e1e2049b1f
Merge pull request #1193 from frappe/mergify/bp/main-hotfix/pr-1191 2025-08-28 12:10:42 +05:30
Shariq Ansari
32d9e1e2ba chore: Norwegian Bokmal translations
(cherry picked from commit 1706c05f931a7be63d4b9720d627609550cd16b0)
2025-08-28 06:38:27 +00:00
Shariq Ansari
ea5b0fdacd chore: Danish translations
(cherry picked from commit f3bd3de81ce6078151223075cc61c01d197cc070)
2025-08-28 06:38:27 +00:00
Shariq Ansari
a7374bedb2 chore: Croatian translations
(cherry picked from commit 91187f4db0118c7508ec0a4b7c653bb4fbf43451)
2025-08-28 06:38:27 +00:00
Shariq Ansari
5b7437d36a chore: Thai translations
(cherry picked from commit 0d5ad337f66a81002e89bcb60b707336547c2ee0)
2025-08-28 06:38:26 +00:00
Shariq Ansari
8fca1842c2 chore: Persian translations
(cherry picked from commit d3fa9cf98ae49037cebfba38941b081f6ed3eaeb)
2025-08-28 06:38:26 +00:00
Shariq Ansari
2473cf88ef chore: Turkish translations
(cherry picked from commit 2251d4671108790981170e4b4c637a244337a908)
2025-08-28 06:38:26 +00:00
Shariq Ansari
4de04d6760 chore: Spanish translations
(cherry picked from commit 962418c37dde49ffaebf5dca17a5218b5ce89fdc)
2025-08-28 06:38:26 +00:00
Shariq Ansari
f4dc6f8338 chore: German translations
(cherry picked from commit 1d633eabdc8203ec5ac42f49ec4278d0decc09c8)
2025-08-28 06:38:25 +00:00
Shariq Ansari
df5ee5a50c chore: Bosnian translations
(cherry picked from commit 5a0e68b0e8ed5d9399ad0e6815c7eb66f84c1a73)
2025-08-28 06:38:25 +00:00
Shariq Ansari
7b4a3dee6e chore: Portuguese, Brazilian translations
(cherry picked from commit 76f984325111e093cd53399720f174cd7870b2ce)
2025-08-28 06:38:25 +00:00
Shariq Ansari
3dd6c5d1ed chore: Polish translations
(cherry picked from commit 1a6a1854fc60c7eda58db58cdc62bddf33807565)
2025-08-28 06:38:24 +00:00
Shariq Ansari
bc7a148999 chore: Esperanto translations
(cherry picked from commit 5f9fb5a68f65e1f32c1d9667b370f6b7f9bbfdac)
2025-08-28 06:38:24 +00:00
Shariq Ansari
f3f0322003 chore: Croatian translations
(cherry picked from commit 469177182a4920054425f2b83dc2512081000ec9)
2025-08-28 06:38:24 +00:00
Shariq Ansari
aa128a3411 chore: Thai translations
(cherry picked from commit a72e580e1f84196328dd3ce7b2ec3c494b0eda3c)
2025-08-28 06:38:24 +00:00
Shariq Ansari
57f74dbbff chore: Persian translations
(cherry picked from commit 9c88ba879db04576f9f648f11f6ef06d3a237be0)
2025-08-28 06:38:23 +00:00
Shariq Ansari
88b9c6af1d chore: Vietnamese translations
(cherry picked from commit 9d45dea8b304ffb5b071fd6395a3b25fcb22e1ff)
2025-08-28 06:38:23 +00:00
Shariq Ansari
243832812f chore: Chinese Simplified translations
(cherry picked from commit f1732780ccd71da4236d13cc8151b85bf9e308ce)
2025-08-28 06:38:23 +00:00
Shariq Ansari
be09a8fe30 chore: Turkish translations
(cherry picked from commit ae70eee7e0748b0111f471a7812d88ca05858952)
2025-08-28 06:38:23 +00:00
Shariq Ansari
f5e54eefef chore: Russian translations
(cherry picked from commit 03277e240ef2728ac7c0a2cff2d03c6ae3e45a2b)
2025-08-28 06:38:22 +00:00
Shariq Ansari
867da93a39 chore: Portuguese translations
(cherry picked from commit 510f7301fd6ad53cd3c51cec8937cd708ee3704b)
2025-08-28 06:38:22 +00:00
Shariq Ansari
580f61ab71 chore: Dutch translations
(cherry picked from commit 32f42a4009ae6f5a6e87771675c4dfe8b9673d98)
2025-08-28 06:38:22 +00:00
Shariq Ansari
b55011a58e chore: Hungarian translations
(cherry picked from commit 267016cff92a5c1acd04999d086e9b72bc79f6e4)
2025-08-28 06:38:21 +00:00
Shariq Ansari
a8504a910e chore: Czech translations
(cherry picked from commit fc02800a359195f34eb71f1fb2ff92abfa2aa867)
2025-08-28 06:38:21 +00:00
Shariq Ansari
ffc048977f chore: Arabic translations
(cherry picked from commit b33f09c76b494de0205de2822f3b75f0360c8a88)
2025-08-28 06:38:21 +00:00
Shariq Ansari
212709782a chore: Spanish translations
(cherry picked from commit 2d68d1d29aa172a8ea393066c17b6a27ffdf6dc3)
2025-08-28 06:38:21 +00:00
Shariq Ansari
9fb0d3175d chore: French translations
(cherry picked from commit ec14798d9c2efe6ba9dfb758cbc5e8bb39d1fd4a)
2025-08-28 06:38:20 +00:00
Shariq Ansari
4839298ba4 chore: German translations
(cherry picked from commit a2e438ceeae080bf88cd81c53f2bd7a31132153f)
2025-08-28 06:38:20 +00:00
Shariq Ansari
b40c72b95c chore: Serbian (Latin) translations
(cherry picked from commit e606e56ce7643631c91800354a0dd8ed5ded161d)
2025-08-28 06:38:20 +00:00
Shariq Ansari
5a941e0944 chore: Bosnian translations
(cherry picked from commit a8a75f6e977b150f2c54fd753b957057cabad974)
2025-08-28 06:38:19 +00:00
Shariq Ansari
4987545595 chore: Indonesian translations
(cherry picked from commit 35e07b321ca30d9bc22ccbc299ebcde817bfbb5d)
2025-08-28 06:38:19 +00:00
Shariq Ansari
f53e35117a chore: Portuguese, Brazilian translations
(cherry picked from commit 28ce5762f8071da27f6d5a2ce4e5f865e22e7922)
2025-08-28 06:38:19 +00:00
Shariq Ansari
de2939d863 chore: Swedish translations
(cherry picked from commit 97367afed113e2a96b73a6258f916cfc4e90a9b7)
2025-08-28 06:38:19 +00:00
Shariq Ansari
25a26d3e2c chore: Serbian (Cyrillic) translations
(cherry picked from commit d1b229c4590f004226e5499e4b66a90835398609)
2025-08-28 06:38:18 +00:00
Shariq Ansari
efd02c3459 chore: Polish translations
(cherry picked from commit 335f73a0e6fb84d222498848d245ae3e6f30a915)
2025-08-28 06:38:18 +00:00
Shariq Ansari
13e72bf7f3 chore: Italian translations
(cherry picked from commit ef38c4a882634e104b14054f954ad60b15f7fbe2)
2025-08-28 06:38:18 +00:00
Frappe PR Bot
7b8cc6caa3 chore(release): Bumped to Version 1.52.9 2025-08-26 07:03:49 +00:00
Shariq Ansari
d1e66cd5bb
Merge pull request #1187 from frappe/main-hotfix 2025-08-26 12:32:46 +05:30
Shariq Ansari
3a9bad7954
Merge pull request #1188 from frappe/mergify/bp/main-hotfix/pr-1182
fix: do not allow saving public view kanban changes for non managers (backport #1182)
2025-08-26 12:27:47 +05:30
Shariq Ansari
3f6e69c3f6
Merge pull request #1186 from frappe/mergify/bp/main-hotfix/pr-1185
fix: remove "read only" flag for primary email, mobile & phone no (backport #1185)
2025-08-26 12:27:32 +05:30
Shariq Ansari
57fb0e07cf fix: do not allow saving public view kanban changes for non managers
(cherry picked from commit 4301cd48061ab853eb975e7d47e2e6c39856f46a)
2025-08-26 06:56:49 +00:00
Shariq Ansari
4cfab1fbb6
Merge pull request #1183 from frappe/mergify/bp/main-hotfix/pr-1178 2025-08-26 12:25:46 +05:30
Pratik Badhe
c851b9f4b3 fix: remove "read only" flag for primary email, mobile & phone no
(cherry picked from commit 7807c12114b215be3f7471615492b982d2dca94d)
2025-08-26 06:54:45 +00:00
Shariq Ansari
7d8f980c87
Merge pull request #1184 from frappe/mergify/bp/main-hotfix/pr-1179 2025-08-26 12:24:22 +05:30
Shariq Ansari
2ccae25bfe
chore: Fix merge conflict in main.pot 2025-08-26 12:22:46 +05:30
Shariq Ansari
1da242fd37 chore: Indonesian translations
(cherry picked from commit 5ab41a5ebb6f1d9e14650dd1b7c61fcdc4e0ccd0)
2025-08-26 06:42:50 +00:00
Shariq Ansari
35b7e69426 chore: Italian translations
(cherry picked from commit e7c09b6f2ffe46e65299e40178f651bb07fe09cb)
2025-08-26 06:42:49 +00:00
frappe-pr-bot
fbaca7f154 chore: update POT file
(cherry picked from commit bf63bd54df26ff9d4e17a6ce321059742cc6d2bd)

# Conflicts:
#	crm/locale/main.pot
2025-08-26 06:42:37 +00:00
Shariq Ansari
913094dce3
Merge pull request #1174 from frappe/mergify/bp/main-hotfix/pr-1173
fix: reorder idx if grid row is reordered (backport #1173)
2025-08-21 11:35:05 +05:30
Shariq Ansari
4d619a908c fix: update button state to use document properties
(cherry picked from commit 41118eda97b9aeaa47814c2c499dc8e4c6f57b47)
2025-08-21 06:03:21 +00:00
Shariq Ansari
6dc8975c08 fix: reorder idx if grid row is reordered
(cherry picked from commit cd96171a4c1a784ffa2b00d28e2b22921b9c9f37)
2025-08-21 06:03:20 +00:00
Shariq Ansari
1b0a92c0c5
Merge pull request #1172 from frappe/mergify/bp/main-hotfix/pr-1133
fix(Org Modal): Setting loading false in case of Validation Error (backport #1133)
2025-08-20 14:35:43 +05:30
wasim3357
bd3aca85ac 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.

(cherry picked from commit ea2e44a2befd5cfd775f7e1b0d3c2321f6d075b0)
2025-08-20 09:05:12 +00:00
Shariq Ansari
6d7372240f
Merge pull request #1171 from frappe/mergify/bp/main-hotfix/pr-1167 2025-08-20 13:33:34 +05:30
Shariq Ansari
c799d1502b chore: Esperanto translations
(cherry picked from commit 8d7a5f22fda1cc62449ae0e9f49967f53964fae6)
2025-08-20 07:51:31 +00:00
Shariq Ansari
acdfe6c82b chore: Croatian translations
(cherry picked from commit a31ff7499934e03b4a1c98e884762fd0735f4cdc)
2025-08-20 07:51:31 +00:00
Shariq Ansari
17687690cf chore: Thai translations
(cherry picked from commit c60979f1ab8d7ad8b52fc64e0fff69215681b100)
2025-08-20 07:51:31 +00:00
Shariq Ansari
f28920dd60 chore: Persian translations
(cherry picked from commit b5739efbbc101dddc035581dd08a5ad20830eaa7)
2025-08-20 07:51:30 +00:00
Shariq Ansari
90f61dffa6 chore: Vietnamese translations
(cherry picked from commit 96e014e6cacbf9832a3ee2f2c825007b8abf3330)
2025-08-20 07:51:30 +00:00
Shariq Ansari
556f8e6b11 chore: Chinese Simplified translations
(cherry picked from commit d0020b8a90ecdda28c03a7ffd6d6f6e61ee16bed)
2025-08-20 07:51:30 +00:00
Shariq Ansari
78aea3bbac chore: Turkish translations
(cherry picked from commit f32b86e7e7ef5f1f5ec6ed0a48e6af2cd604d4cc)
2025-08-20 07:51:30 +00:00
Shariq Ansari
67f75289c7 chore: Russian translations
(cherry picked from commit 7cab5d981521524adcaeacc21a081cd6337983ab)
2025-08-20 07:51:29 +00:00
Shariq Ansari
8e86a06858 chore: Portuguese translations
(cherry picked from commit a6a22aa3930ccb1d5b7dbc2c605ef2b7b09ef55e)
2025-08-20 07:51:29 +00:00
Shariq Ansari
445f5d7ade chore: Dutch translations
(cherry picked from commit fd098a0766769b4cb1be8e24f2c02a1a66104cb7)
2025-08-20 07:51:29 +00:00
Shariq Ansari
015228488b chore: Hungarian translations
(cherry picked from commit 36326526d57a78ef2b4bde4db57bf7292e2ea433)
2025-08-20 07:51:28 +00:00
Shariq Ansari
9a0e0ed721 chore: Czech translations
(cherry picked from commit f20a903e784419e152800e42baf56f6924a350bb)
2025-08-20 07:51:28 +00:00
Shariq Ansari
89b392d59b chore: Arabic translations
(cherry picked from commit 0f0564066db24fd764bd678ad20e1259cd32e60a)
2025-08-20 07:51:28 +00:00
Shariq Ansari
799dedb582 chore: Spanish translations
(cherry picked from commit 7b6a4d3b307a5bddd9d619faf8fe16bcba19a01a)
2025-08-20 07:51:27 +00:00
Shariq Ansari
9418df86f9 chore: French translations
(cherry picked from commit 175c45055977811e38305662dde992855483b67a)
2025-08-20 07:51:27 +00:00
Shariq Ansari
57dd748cae chore: German translations
(cherry picked from commit 5b79141dd53efe48b243202348bba0cb84f3c298)
2025-08-20 07:51:27 +00:00
Shariq Ansari
06b4e4d544 chore: Serbian (Latin) translations
(cherry picked from commit 97de6543c20dcdec733becd778dd366ec27b52bc)
2025-08-20 07:51:27 +00:00
Shariq Ansari
e98d54cdd9 chore: Bosnian translations
(cherry picked from commit bc424265e029e45f941df43687ac4c70e2e5ef02)
2025-08-20 07:51:26 +00:00
Shariq Ansari
a00838b7a0 chore: Indonesian translations
(cherry picked from commit 15d057b63c13c8c1312973d41176dca324d0aa31)
2025-08-20 07:51:26 +00:00
Shariq Ansari
fad4bc994d chore: Portuguese, Brazilian translations
(cherry picked from commit 27a121c270d63e42c362e32f8811e9692ffb48de)
2025-08-20 07:51:26 +00:00
Shariq Ansari
b3752d63db chore: Swedish translations
(cherry picked from commit d99a4bc3ff7c45fb6d492e71db4dc7a348bb3ac7)
2025-08-20 07:51:25 +00:00
Shariq Ansari
4c13c5143f chore: Serbian (Cyrillic) translations
(cherry picked from commit d6251adae3f429e332a565d556a919fd0c1e01c1)
2025-08-20 07:51:25 +00:00
Shariq Ansari
9423af5cc1 chore: Polish translations
(cherry picked from commit 388d3e93693d8ee84ce0062bb65e035f2d2e537d)
2025-08-20 07:51:25 +00:00
Shariq Ansari
dcc3b88d4f chore: Italian translations
(cherry picked from commit f8f0800f97853d9710c13d8d8d11d7054ac24c8b)
2025-08-20 07:51:25 +00:00
Shariq Ansari
a55b69a945
Merge pull request #1170 from frappe/mergify/bp/main-hotfix/pr-1169
fix: dropdown item is not updating (backport #1169)
2025-08-20 13:20:05 +05:30
Shariq Ansari
89abee30bf fix: dropdown item is not updating
(cherry picked from commit 8ea94765ce351df2586ab71238ef6baa8068613e)
2025-08-20 07:45:21 +00:00
Frappe PR Bot
066371bd76 chore(release): Bumped to Version 1.52.8 2025-08-19 08:12:22 +00:00
Shariq Ansari
f61a40698d
Merge pull request #1166 from frappe/mergify/bp/main/pr-1164
fix: More fixes (backport #1164)
2025-08-19 13:39:38 +05:30
Shariq Ansari
0b9c0915c7
Merge pull request #1165 from frappe/mergify/bp/main-hotfix/pr-1164
fix: More fixes (backport #1164)
2025-08-19 13:39:35 +05:30
Shariq Ansari
e6781ea4bb fix: remove read-only attribute from TwiML SID field
(cherry picked from commit 247a7c4da63e8aa639383469ad11d433421f4c71)
2025-08-19 08:08:46 +00:00
Shariq Ansari
277fb85e32 fix: remove read-only attribute from TwiML SID field
(cherry picked from commit 247a7c4da63e8aa639383469ad11d433421f4c71)
2025-08-19 08:08:46 +00:00
Shariq Ansari
4592dfcd13 fix: add immediate execution to watch for assignees updates
(cherry picked from commit f2d87fa801b2c906e182f85bf8e7b29f52ccab4a)
2025-08-19 08:08:45 +00:00
Shariq Ansari
cf0f922f2f fix: add immediate execution to watch for assignees updates
(cherry picked from commit f2d87fa801b2c906e182f85bf8e7b29f52ccab4a)
2025-08-19 08:08:45 +00:00
Frappe PR Bot
bc35d6b98f chore(release): Bumped to Version 1.52.7 2025-08-19 06:58:06 +00:00
Shariq Ansari
3fbd40b591
Merge pull request #1163 from frappe/mergify/bp/main/pr-1161
fix: More fixes (backport #1161)
2025-08-19 12:27:16 +05:30
Shariq Ansari
f50b8a78eb
Merge pull request #1162 from frappe/mergify/bp/main-hotfix/pr-1161
fix: More fixes (backport #1161)
2025-08-19 12:27:12 +05:30
Shariq Ansari
5212a61388 fix: update Dropdown styling in SLASection component
(cherry picked from commit edd0ec5f68eac0bfd9005adbbbd95fedd0c8e337)
2025-08-19 06:56:52 +00:00
Shariq Ansari
0d1c057cf3 fix: align action buttons in GridFieldsEditorModal
(cherry picked from commit a76bd2cab2b4dd2a8a9038f6890f3b9294a375a2)
2025-08-19 06:56:52 +00:00
Shariq Ansari
5a243d29da fix: update Dropdown styling in SLASection component
(cherry picked from commit edd0ec5f68eac0bfd9005adbbbd95fedd0c8e337)
2025-08-19 06:56:51 +00:00
Shariq Ansari
992b47e531 fix: convert to deal modals's convert button
(cherry picked from commit 25d9d562e6b150d94ba1b3065945fd0c12f10c43)
2025-08-19 06:56:51 +00:00
Shariq Ansari
ee8f806f64 fix: align action buttons in GridFieldsEditorModal
(cherry picked from commit a76bd2cab2b4dd2a8a9038f6890f3b9294a375a2)
2025-08-19 06:56:51 +00:00
Shariq Ansari
bc0ca74f88 fix: convert to deal modals's convert button
(cherry picked from commit 25d9d562e6b150d94ba1b3065945fd0c12f10c43)
2025-08-19 06:56:50 +00:00
Frappe PR Bot
55dabaf877 chore(release): Bumped to Version 1.52.6 2025-08-19 05:46:20 +00:00
Shariq Ansari
006c7efc06
Merge pull request #1160 from frappe/mergify/bp/main/pr-1158
fix: reject button is rotated (backport #1158)
2025-08-19 11:14:02 +05:30
Shariq Ansari
4c809a9166
Merge pull request #1159 from frappe/mergify/bp/main-hotfix/pr-1158
fix: reject button is rotated (backport #1158)
2025-08-19 11:13:58 +05:30
Shariq Ansari
9e19e54f75 fix: reject button is rotated
(cherry picked from commit afa96c330bb123067b15526c22d46c6e932ace01)
2025-08-19 05:43:30 +00:00
Shariq Ansari
806f75a2fe fix: reject button is rotated
(cherry picked from commit afa96c330bb123067b15526c22d46c6e932ace01)
2025-08-19 05:43:28 +00:00
Frappe PR Bot
295b0f4c2a chore(release): Bumped to Version 1.52.5 2025-08-19 05:19:06 +00:00
Shariq Ansari
7945527fd6
Merge pull request #1157 from frappe/mergify/bp/main/pr-1155
fix: remove unnecessary cache from dashboardItems resource (backport #1155)
2025-08-19 10:48:17 +05:30
Shariq Ansari
696531f392 fix: remove unnecessary cache from dashboardItems resource
(cherry picked from commit c2a1a1b1d2de8a1640e077cc47a377311f5203d8)
2025-08-19 05:18:05 +00:00
Shariq Ansari
c0d43a9b58
Merge pull request #1156 from frappe/mergify/bp/main-hotfix/pr-1155
fix: remove unnecessary cache from dashboardItems resource (backport #1155)
2025-08-19 10:48:03 +05:30
Shariq Ansari
584250c4e5 fix: remove unnecessary cache from dashboardItems resource
(cherry picked from commit c2a1a1b1d2de8a1640e077cc47a377311f5203d8)
2025-08-19 05:17:48 +00:00
Frappe PR Bot
ec467ae126 chore(release): Bumped to Version 1.52.4 2025-08-18 20:56:34 +00:00
Shariq Ansari
579fe78e6f
Merge pull request #1154 from frappe/mergify/bp/main/pr-1152
fix: More fixes (backport #1152)
2025-08-19 02:25:32 +05:30
Shariq Ansari
a246a5e6e4
Merge pull request #1153 from frappe/mergify/bp/main-hotfix/pr-1152
fix: More fixes (backport #1152)
2025-08-19 02:25:27 +05:30
Shariq Ansari
daaf015462 fix: prevent adding a column with undefined value in ColumnSettings
(cherry picked from commit 5f0bb46bf4f3c5c99a4120409d84366cb2b969c8)
2025-08-18 20:50:30 +00:00
Shariq Ansari
edb68fe08b refactor: note/task modal
(cherry picked from commit f4551a92c553a8c26d9bcd36b1ae21d6a69c53d7)
2025-08-18 20:50:29 +00:00
Shariq Ansari
7e736b2892 fix: minor fix
(cherry picked from commit e9c197f46e9a23b8a3e118cf1af22218168f4cb3)
2025-08-18 20:50:29 +00:00
Shariq Ansari
3b18f3a86a fix: grid settings/edit-row button alignment
(cherry picked from commit 3a756630f3699c3f86aa74eff174b9a7e8a21623)
2025-08-18 20:50:29 +00:00
Shariq Ansari
f6cf935c9c refactor: update layout structure for CRM Deal-Data Fields to show products table
(cherry picked from commit a77bfd2acae6e6973d8a9e85c73b0e163a94ea88)
2025-08-18 20:50:28 +00:00
Shariq Ansari
1dfbcd1055 fix: ensure reactive access to document title in Lead component
(cherry picked from commit 1cebc1fed858d3e54bace0e46731e4fd0aff0502)
2025-08-18 20:50:28 +00:00
Shariq Ansari
3326230062 refactor: improve layout and structure of quick filter components
(cherry picked from commit 1a90876500afe5f104f8ff7d263cca942b3506f7)
2025-08-18 20:50:28 +00:00
Shariq Ansari
de4471876f patch: create default loast reasons
(cherry picked from commit c4065b95b8f16d7550ddaff543467fb92e59d17c)
2025-08-18 20:50:28 +00:00
Shariq Ansari
41ce361f04 fix: prevent adding a column with undefined value in ColumnSettings
(cherry picked from commit 5f0bb46bf4f3c5c99a4120409d84366cb2b969c8)
2025-08-18 20:50:26 +00:00
Shariq Ansari
466a2b58ee refactor: note/task modal
(cherry picked from commit f4551a92c553a8c26d9bcd36b1ae21d6a69c53d7)
2025-08-18 20:50:26 +00:00
Shariq Ansari
0e71880463 fix: minor fix
(cherry picked from commit e9c197f46e9a23b8a3e118cf1af22218168f4cb3)
2025-08-18 20:50:25 +00:00
Shariq Ansari
1afbc001b5 fix: grid settings/edit-row button alignment
(cherry picked from commit 3a756630f3699c3f86aa74eff174b9a7e8a21623)
2025-08-18 20:50:25 +00:00
Shariq Ansari
9e3eba8ab2 refactor: update layout structure for CRM Deal-Data Fields to show products table
(cherry picked from commit a77bfd2acae6e6973d8a9e85c73b0e163a94ea88)
2025-08-18 20:50:25 +00:00
Shariq Ansari
32405f3120 fix: ensure reactive access to document title in Lead component
(cherry picked from commit 1cebc1fed858d3e54bace0e46731e4fd0aff0502)
2025-08-18 20:50:24 +00:00
Shariq Ansari
d7735d634d refactor: improve layout and structure of quick filter components
(cherry picked from commit 1a90876500afe5f104f8ff7d263cca942b3506f7)
2025-08-18 20:50:24 +00:00
Shariq Ansari
b97a80249c patch: create default loast reasons
(cherry picked from commit c4065b95b8f16d7550ddaff543467fb92e59d17c)
2025-08-18 20:50:24 +00:00
Frappe PR Bot
9c3ddeaf7d chore(release): Bumped to Version 1.52.3 2025-08-18 17:46:55 +00:00
Shariq Ansari
de14eb3ffb
Merge pull request #1151 from frappe/main-hotfix 2025-08-18 23:15:56 +05:30
Shariq Ansari
74cce77dc5
Merge branch 'main' into main-hotfix 2025-08-18 23:08:12 +05:30
Shariq Ansari
2352f51838
Merge pull request #1149 from frappe/mergify/bp/main-hotfix/pr-1129 2025-08-18 23:03:26 +05:30
Shariq Ansari
0e2be93e92
chore: resolved conflict 2025-08-18 23:02:22 +05:30
Shariq Ansari
903c214c3d
Merge pull request #1150 from frappe/mergify/bp/main-hotfix/pr-1130 2025-08-18 22:56:35 +05:30
Shariq Ansari
9c653cf5e7
chore: resolved conflict 2025-08-18 22:54:01 +05:30
frappe-pr-bot
3c296a67a2 chore: update POT file
(cherry picked from commit 00e3bd12ccfa49e7d97527641924756c521dc808)

# Conflicts:
#	crm/locale/main.pot
2025-08-18 17:22:30 +00:00
Shariq Ansari
9196369c17
Merge pull request #1148 from frappe/mergify/bp/main-hotfix/pr-1142 2025-08-18 22:51:26 +05:30
Shariq Ansari
853ef4859d
Merge pull request #1147 from frappe/mergify/bp/main-hotfix/pr-1145 2025-08-18 22:49:32 +05:30
Shariq Ansari
c861fbda49 chore: Persian translations
(cherry picked from commit d4f99a411cc4a0a7b36866354ba4dbc22238de31)
2025-08-18 17:19:29 +00:00
Shariq Ansari
a81f3685bc chore: Persian translations
(cherry picked from commit 4884ca0bd6cfcb914fb91bc11de2d3494d2a34ea)
2025-08-18 17:19:29 +00:00
Shariq Ansari
73d13351b5 chore: Italian translations
(cherry picked from commit 2a7c9ef9e821d5ffd4743f26ce232bbadd87a169)

# Conflicts:
#	crm/locale/it.po
2025-08-18 17:19:28 +00:00
Shariq Ansari
43e8f2a48f chore: Italian translations
(cherry picked from commit cb3f67f2317d488a2da3ed6df331ad30b95a897e)

# Conflicts:
#	crm/locale/it.po
2025-08-18 17:19:28 +00:00
Shariq Ansari
f347919dbf chore: German translations
(cherry picked from commit d539bc075f97cbc44a96a4efcdb305e81b975db0)
2025-08-18 17:19:28 +00:00
Shariq Ansari
14622a00b3 chore: Italian translations
(cherry picked from commit 818fd6fcdd5586b323de90a075efa82c9251fb6e)

# Conflicts:
#	crm/locale/it.po
2025-08-18 17:19:28 +00:00
frappe-pr-bot
4a83b52ab5 chore: update POT file
(cherry picked from commit 73b2c36bbcedf696e4eff3cf0a83b36ac66a5af7)
2025-08-18 17:19:26 +00:00
Shariq Ansari
30fed5f6ad
Merge pull request #1146 from frappe/mergify/bp/main-hotfix/pr-1143
fixes to incorporate latest frappe-ui version  (backport #1143)
2025-08-18 22:47:46 +05:30
Shariq Ansari
96031d2288 build(deps): bump frappeui to 0.1.189
(cherry picked from commit 1679a67dc6a785db93fbf09ecb4b3ecf7e4e7c8f)
2025-08-18 17:13:23 +00:00
Shariq Ansari
58a0ef2d0e refactor: update tooltip bindings to use translation function and improve dropdown actions
(cherry picked from commit c5a8df19aeafdac60b74cadcf178ee297e9fc9b8)
2025-08-18 17:10:22 +00:00
Shariq Ansari
7b2168232e refactor: replace NestedPopover with Popover component across multiple files
(cherry picked from commit 38b6674cc134a2cffa907c03dbdfce9b7c916e01)
2025-08-18 17:10:22 +00:00
Shariq Ansari
d0dc642b12 refactor: Button components across multiple files to use icon/left-icon/right-icon prop
(cherry picked from commit 672c5eb7333fe4c48055f0acc2d287d545015970)
2025-08-18 17:10:21 +00:00
Shariq Ansari
e4722a79cc fix: show dashboard to all
(cherry picked from commit 948ce994824260b4ca6303f0b729bb1beb760b0c)
2025-08-18 17:10:21 +00:00
Shariq Ansari
671ce54380 fix: lead/deal status dropdown is not renderring
(cherry picked from commit 3791e2ae70067a1be9aba1e472a497e3dff8006a)
2025-08-18 17:10:20 +00:00
Shariq Ansari
d4ac8772ae fix: add toast import to CurrencySettings component
(cherry picked from commit 68d1172b8fee86603586b21271ff5dc3f627734b)
2025-08-18 17:10:20 +00:00
Shariq Ansari
1df71070d0 fix: adjust UserDropdown padding in AppSidebar
(cherry picked from commit c94e61bfcec1f0a12bfe52a4403e0ff6990a77fa)
2025-08-18 17:10:20 +00:00
Shariq Ansari
58d4b7afae fix: doc was not associated with value
(cherry picked from commit 8b557a5963d3651b697c859435a46f639510416b)
2025-08-18 17:10:20 +00:00
Shariq Ansari
9e08b68f22
Merge pull request #1127 from frappe/mergify/bp/main/pr-1126 2025-08-08 17:14:39 +05:30
Shariq Ansari
3a38ccace0 chore: Italian translations
(cherry picked from commit 840eb664ce09dc137f39c26053fcc4572f36cba7)
2025-08-08 11:30:19 +00:00
Frappe PR Bot
f18b1c56ed chore(release): Bumped to Version 1.52.2 2025-08-08 09:22:23 +00:00
Shariq Ansari
24e7e234be
Merge pull request #1124 from frappe/main-hotfix 2025-08-08 14:51:24 +05:30
Shariq Ansari
53f7b614b0
Merge pull request #1123 from frappe/mergify/bp/main-hotfix/pr-1121
fix: create quotation (backport #1121)
2025-08-08 14:07:22 +05:30
Pratik Badhe
277cebfe7b fix: create quotation
(cherry picked from commit 940e8d24c7e1ded869555cbc326a6927eb68455f)
2025-08-08 08:36:34 +00:00
Shariq Ansari
4500595a75
Merge pull request #1122 from frappe/mergify/bp/main-hotfix/pr-1116 2025-08-08 14:00:12 +05:30
Shariq Ansari
a1445903db chore: Serbian (Latin) translations
(cherry picked from commit 4813a861a66084003c03ed565c963b02c2fae9f5)
2025-08-08 08:28:30 +00:00
Shariq Ansari
1060f3a873 chore: Serbian (Cyrillic) translations
(cherry picked from commit afb30a256e4cd4dfdeafa0bac9516d518ab1f3e2)
2025-08-08 08:28:30 +00:00
Shariq Ansari
9f4c278a6b
Merge pull request #1114 from frappe/mergify/bp/main-hotfix/pr-1112 2025-08-07 12:18:53 +05:30
Shariq Ansari
c017397787 chore: Croatian translations
(cherry picked from commit 227359da62cbb8f162d42fc416d10423f3ea8058)
2025-08-06 07:14:00 +00:00
Shariq Ansari
1412600bdb chore: Bosnian translations
(cherry picked from commit 022b14c830e50dc54524b629d99d02de39709d72)
2025-08-06 07:14:00 +00:00
Shariq Ansari
c9b26e5559 chore: Swedish translations
(cherry picked from commit 58f970c6b1bfe6d674387de8764f0b418edee2df)
2025-08-06 07:14:00 +00:00
Shariq Ansari
9050137a39 chore: Esperanto translations
(cherry picked from commit d83ce2f2764bababc2ed5ed9741c5010e8d31f73)
2025-08-06 07:13:59 +00:00
Shariq Ansari
b464c7cc4f chore: Croatian translations
(cherry picked from commit 0c8f36bc36571593490bdbc55c4f9f6ff0d3f9fd)
2025-08-06 07:13:59 +00:00
Shariq Ansari
543310e55a chore: Thai translations
(cherry picked from commit 1286ecfc8f200153bf47c76c44572847425f59b0)
2025-08-06 07:13:59 +00:00
Shariq Ansari
15d0a29ed9 chore: Persian translations
(cherry picked from commit 24ebe94730e5d62d57cd70a3bd0e563c2f338ba8)
2025-08-06 07:13:58 +00:00
Shariq Ansari
f65cb3c4da chore: Vietnamese translations
(cherry picked from commit 90b0e0d7b6e911020aba2cbeef617ad1f9e86d92)
2025-08-06 07:13:58 +00:00
Shariq Ansari
fafa4f6541 chore: Chinese Simplified translations
(cherry picked from commit ebd115c129fc59dce0b21bcbf8fa991c5ed07f7f)
2025-08-06 07:13:58 +00:00
Shariq Ansari
2358198660 chore: Turkish translations
(cherry picked from commit 5f544416efb52b902e3676a026751d8234268f56)
2025-08-06 07:13:57 +00:00
Shariq Ansari
6342656477 chore: Russian translations
(cherry picked from commit 5a7a7a72572b55fc81b31b31449637001488a5db)
2025-08-06 07:13:57 +00:00
Shariq Ansari
966e7a832d chore: Portuguese translations
(cherry picked from commit 8e8bf4ed5e1fb49ec86853baccd887e4da8fb0d7)
2025-08-06 07:13:57 +00:00
Shariq Ansari
872f22e293 chore: Dutch translations
(cherry picked from commit 7244f69c7fd1e639eda747b033d220eab1344686)
2025-08-06 07:13:57 +00:00
Shariq Ansari
5c246c513a chore: Hungarian translations
(cherry picked from commit d5b992d7360610a69f69b444b58bb55645155bf2)
2025-08-06 07:13:56 +00:00
Shariq Ansari
e33fb939b3 chore: Czech translations
(cherry picked from commit 38cb7774582a00465c310e53a8653381ed43e405)
2025-08-06 07:13:56 +00:00
Shariq Ansari
61dddd76a0 chore: Arabic translations
(cherry picked from commit 1a569d45de2d10993132124ad7fee78440a9916f)
2025-08-06 07:13:56 +00:00
Shariq Ansari
9e5a6edba0 chore: Spanish translations
(cherry picked from commit 93a710f8c5b152a99f080229e870af3bf25e0387)
2025-08-06 07:13:55 +00:00
Shariq Ansari
8cbcd4dff3 chore: French translations
(cherry picked from commit 5414bbb1903c4c251b1aaeba2defa19c0c082e8a)
2025-08-06 07:13:55 +00:00
Shariq Ansari
5b747cbbff chore: German translations
(cherry picked from commit c70aac4f319da04514d4c86ceb442cc794d7672c)
2025-08-06 07:13:55 +00:00
Shariq Ansari
8cbd4291a5 chore: Serbian (Latin) translations
(cherry picked from commit 9471966bee35711ea3918e8513c9331833c23723)
2025-08-06 07:13:55 +00:00
Shariq Ansari
182259e7d2 chore: Bosnian translations
(cherry picked from commit 055a39cc0dbff09b5280957ab388acbeedf94eb5)
2025-08-06 07:13:54 +00:00
Shariq Ansari
ed6bdfae96 chore: Indonesian translations
(cherry picked from commit 4f075d4b235242ef71472d99b58f4fca14065819)
2025-08-06 07:13:54 +00:00
Shariq Ansari
6c382f7a0f chore: Portuguese, Brazilian translations
(cherry picked from commit 526c43c655ddfa917670da6b791b1338b7ce4372)
2025-08-06 07:13:54 +00:00
Shariq Ansari
ec655c17a4 chore: Swedish translations
(cherry picked from commit 084b446ae1c15bccbdb08c581252f0481e90c1ef)
2025-08-06 07:13:53 +00:00
Shariq Ansari
22ba79aebf chore: Serbian (Cyrillic) translations
(cherry picked from commit de9c04ff18bb638313140f4c8066da9fc922c964)
2025-08-06 07:13:53 +00:00
Shariq Ansari
b26593d8cc chore: Polish translations
(cherry picked from commit 2fb09126c0115602046f8901b1ac8083d7de9de9)
2025-08-06 07:13:53 +00:00
Shariq Ansari
57b1af5153 chore: Italian translations
(cherry picked from commit 8944295474f721ac9362984457cf49fc34c87a70)
2025-08-06 07:13:52 +00:00
Shariq Ansari
3d55706d60
Merge pull request #1111 from frappe/mergify/bp/main-hotfix/pr-1108 2025-08-04 12:53:18 +05:30
Shariq Ansari
b0009e1701
Merge pull request #1110 from frappe/mergify/bp/main-hotfix/pr-1104 2025-08-04 12:52:59 +05:30
frappe-pr-bot
c3b6b380f4 chore: update POT file
(cherry picked from commit fa14d4ad15d036be35656ea29ced747cf79de5ff)
2025-08-04 07:04:29 +00:00
Shariq Ansari
5b34142a40 refactor: update Activities component for improved z-index layering
(cherry picked from commit 2a18a556bf6fbefc6aee2d10c3e7e9d529f33298)
2025-08-04 07:03:54 +00:00
Shariq Ansari
d39500f706 refactor: update z-index values for activity components for better layering
(cherry picked from commit 4c1eaf507d9ea095ada7277d1a3ae8850184e961)
2025-08-04 07:03:54 +00:00
Shariq Ansari
29e8c73d50 refactor: update Activities component to scroll on success
(cherry picked from commit 76149b0c79f70fc903516bb3665312d01873f381)
2025-08-04 07:03:53 +00:00
Shariq Ansari
5ac003e860 refactor: update AssignTo component to use correct doctype for CRM Deal
(cherry picked from commit 564d2b1ac5bdee71d4b54b6ef672cd08ae2a87a1)
2025-08-04 07:03:53 +00:00
Shariq Ansari
9b988f638e refactor: update AssignTo component to use docname prop and streamline assignment logic
(cherry picked from commit faef5cb86629ace8a113bd5dc06cfaa272d55e88)
2025-08-04 07:03:53 +00:00
Shariq Ansari
2bbd0206c6 refactor: do not update modified field
(cherry picked from commit 3ed2c4812a98f6a08f21276e27d09070987af048)
2025-08-04 07:03:52 +00:00
Shariq Ansari
8c3733a212 refactor: replace json.loads with frappe.parse_json for assignees in remove_assignments function
(cherry picked from commit 5010cccc7158dca670530c564a4a4b01067e090f)
2025-08-04 07:03:52 +00:00
Shariq Ansari
7e53e0f4e4 refactor: assignment modal for bulk assign
(cherry picked from commit aeb3f150c58a24396824037f01ccf09624bdcc01)
2025-08-04 07:03:51 +00:00
Shariq Ansari
e5ed7e0daf refactor: Assign to as popover instead of dialog
(cherry picked from commit 995f3564193ec1a44c2a6bfa344e734bce415a46)
2025-08-04 07:03:51 +00:00
Shariq Ansari
0f2ad3590d refactor: simplify AssignmentModal component by streamlining dialog options and enhancing assignee management
(cherry picked from commit 819a669922b9105d7978d6b3242f1c2f0c4353d9)
2025-08-04 07:03:51 +00:00
Shariq Ansari
2d912e01b7
Merge pull request #1107 from frappe/mergify/bp/main-hotfix/pr-1103
chore: sync translations from crowdin (backport #1103)
2025-08-03 14:02:55 +05:30
Shariq Ansari
6bd1dd2f64 chore: Persian translations
(cherry picked from commit 2601c1d059271e6006de781a7c305b4564a51cb2)
2025-08-03 08:31:12 +00:00
Shariq Ansari
95aa5ac4d3 chore: Indonesian translations
(cherry picked from commit 7e51d963799639f87bd59ef44fc920b961d046ac)
2025-08-03 08:31:12 +00:00
Shariq Ansari
45a8bdaf5f chore: Persian translations
(cherry picked from commit 4c53dd6ea331d48bec12bd249d6575fcc05065ff)
2025-08-03 08:31:12 +00:00
Shariq Ansari
17f63d1484
Merge pull request #1102 from frappe/mergify/bp/main-hotfix/pr-1095 2025-07-31 16:40:21 +05:30
Shariq Ansari
50ada2ad64 chore: Croatian translations
(cherry picked from commit 72c31b9f2105a1aee00a5064310d235301bb3251)
2025-07-31 11:09:39 +00:00
Shariq Ansari
326cad3275 chore: Serbian (Latin) translations
(cherry picked from commit f2b1c24d19ce7f1756b82f3b2de5a551dcaa459b)
2025-07-31 11:09:38 +00:00
Shariq Ansari
7e1dde24d0 chore: Bosnian translations
(cherry picked from commit f86bb0ada220b770672e06d339928d3b6cbbb060)
2025-07-31 11:09:38 +00:00
Shariq Ansari
238d75c398 chore: Indonesian translations
(cherry picked from commit ec4866f39a4b00b03f08f857caf545b4467b88fd)
2025-07-31 11:09:38 +00:00
Shariq Ansari
24f4ae4294 chore: Swedish translations
(cherry picked from commit 7961b614f1ece2d69d4a6c84a5ec6e99e1c4844d)
2025-07-31 11:09:37 +00:00
Shariq Ansari
4dc6eb8c4e chore: Serbian (Cyrillic) translations
(cherry picked from commit 901d84d07028bc26403594fdeb05748fadc82f06)
2025-07-31 11:09:37 +00:00
Shariq Ansari
9c9d998ef5
Merge pull request #1101 from frappe/mergify/bp/main-hotfix/pr-1100
fix: update delete button click handler in Deal component (backport #1100)
2025-07-31 16:38:36 +05:30
Shariq Ansari
8fa583dbc6
Merge branch 'main-hotfix' into mergify/bp/main-hotfix/pr-1100 2025-07-31 16:37:42 +05:30
Shariq Ansari
d08e15a4b5
Merge pull request #1097 from frappe/mergify/bp/main-hotfix/pr-1096 2025-07-31 16:34:37 +05:30
Shariq Ansari
bad30d6232
Merge pull request #1099 from frappe/mergify/bp/main-hotfix/pr-1094 2025-07-31 16:34:29 +05:30
Shariq Ansari
63d3bc8bd5 fix: update delete button click handler in Deal component
(cherry picked from commit abc501825ae6cbaf1c1b939823dbe5c387b4c0b8)

# Conflicts:
#	frontend/src/pages/Deal.vue
2025-07-31 11:02:41 +00:00
Shariq Ansari
5eb3bcbf43 fix: update init scripts for consistent Redis configuration and branch usage
(cherry picked from commit c53e486bf0a0dfe902e16b1de6df3f5b59753c2d)
2025-07-31 10:59:37 +00:00
C.L.STARK
e3baeabbb4 Update init.sh
Fixed: docker setup error in crm-frappe container.
(cherry picked from commit b6a6152a492d31e8fd0ce600c968d0002c6fda95)
2025-07-31 10:59:37 +00:00
Shariq Ansari
4a3504fce3
chore: resolved conflict 2025-07-31 16:27:45 +05:30
Shariq Ansari
cde1084ed4
chore: resolved conflict 2025-07-31 16:25:58 +05:30
Shariq Ansari
b5925ef0e9
chore: resolved conflict 2025-07-31 16:23:44 +05:30
Shariq Ansari
fe02a9077f
chore: resolved conflict 2025-07-31 16:21:52 +05:30
Shariq Ansari
6b00ede6ad refactor: remove unused get_lead function and related imports from api.py
(cherry picked from commit d431d5b4b15e9b8fa984e27a0368c7f930dbaec4)
2025-07-30 12:44:45 +00:00
Shariq Ansari
d94c99b161 refactor: clean up unused variables and streamline tab management in Deal, Lead, and MobileLead components
(cherry picked from commit ba99d14f688de7eaa20be142e4b3184645b76305)
2025-07-30 12:44:44 +00:00
Shariq Ansari
12b92b3f21 refactor: update mobile lead/deal components
(cherry picked from commit 7e42599b494395b50305fcb806817d043d514637)
2025-07-30 12:44:44 +00:00
Shariq Ansari
9ebd7bde2c fix: update docname references to use dealId and leadId in Deal and Lead components
(cherry picked from commit c38c190d42eb1f5750dba97681d73bad5e7e37f6)
2025-07-30 12:44:43 +00:00
Shariq Ansari
6a729fb5e7 fix: update whatsappMessages auto property based on whatsappEnabled state
(cherry picked from commit 6e8d869afb6f588cb4e353974fa1eb23c56e3133)
2025-07-30 12:44:43 +00:00
Shariq Ansari
bed6e346ef refactor: update button icon rendering in AttachmentArea component
(cherry picked from commit 63d60626738be6b6dc911a8d6a78a9cb7f3e77b8)
2025-07-30 12:44:43 +00:00
Shariq Ansari
788c565e71 refactor: use doc in activity & child components
(cherry picked from commit af830b8782f2c9dbeca8ba1bce29565ab03388bc)
2025-07-30 12:44:42 +00:00
Shariq Ansari
72c61f6cc4 refactor: updateField & deleteDeal/Lead
(cherry picked from commit 0605cf5fd0c0de9ba22e4f504a8acb24a6cbdf3c)
2025-07-30 12:44:42 +00:00
Shariq Ansari
b1dfa6e9c9 fix: remount on route change with param and hash change
(cherry picked from commit 4acb4dd3a70c8aed5f8613a2db827a5441ea6148)
2025-07-30 12:44:41 +00:00
Shariq Ansari
971265d000 fix: use document.doc instead of lead.data/deal.data
(cherry picked from commit 0144bc109a83f80e4349508001d1cb752707043c)

# Conflicts:
#	frontend/src/pages/Deal.vue
#	frontend/src/pages/Lead.vue
2025-07-30 12:44:41 +00:00
Shariq Ansari
0e177818cc fix: handle errors when creating document resources
(cherry picked from commit ca5d82f5beb9395a88bbc576cc58911360b62b03)
2025-07-30 12:44:40 +00:00
Shariq Ansari
07bea95479
Merge pull request #1093 from frappe/mergify/bp/main-hotfix/pr-1090 2025-07-29 16:12:42 +05:30
Shariq Ansari
ab51a54ea2 chore: Esperanto translations
(cherry picked from commit 94b0077b2ae363a88af0b93541d727cc13db9c9c)
2025-07-29 10:41:41 +00:00
Shariq Ansari
f6e1b01645 chore: Croatian translations
(cherry picked from commit ea815d014767a8e843fd1da423a771a760baae8b)
2025-07-29 10:41:40 +00:00
Shariq Ansari
11c564835a chore: Thai translations
(cherry picked from commit 0ae048d3969d7d1b095bceaf52655ed9fee87ef8)
2025-07-29 10:41:40 +00:00
Shariq Ansari
9697af7417 chore: Persian translations
(cherry picked from commit 972558396e0650474cfa888429a5cb0d0b7c1626)
2025-07-29 10:41:40 +00:00
Shariq Ansari
9c6e2bb34b chore: Vietnamese translations
(cherry picked from commit c218241e80d6f0fabcd5dd97b5fe195436a8096b)
2025-07-29 10:41:40 +00:00
Shariq Ansari
ce77d3a705 chore: Chinese Simplified translations
(cherry picked from commit e616e69aa4a9e82151e214689713ef04b39b2f96)
2025-07-29 10:41:39 +00:00
Shariq Ansari
4cf1598dfe chore: Turkish translations
(cherry picked from commit 2627471b23dcdb6e3ca8774879d1640be31435a8)
2025-07-29 10:41:39 +00:00
Shariq Ansari
12422d6ad4 chore: Russian translations
(cherry picked from commit a2c42ee5a7833074cb7fff85dcf13d9257d2981a)
2025-07-29 10:41:39 +00:00
Shariq Ansari
4bd67bd993 chore: Portuguese translations
(cherry picked from commit 8d89caeba73048401bd74efea0f93bc75a51d6dd)
2025-07-29 10:41:38 +00:00
Shariq Ansari
ef80e5084e chore: Dutch translations
(cherry picked from commit b0393b532c19cfc3d25086c428a200776a4d04bf)
2025-07-29 10:41:38 +00:00
Shariq Ansari
b0f5cafc27 chore: Hungarian translations
(cherry picked from commit 2ea875f2cb8763fc28d165d14bd46a5d138d94b4)
2025-07-29 10:41:38 +00:00
Shariq Ansari
b049cbc3d2 chore: Czech translations
(cherry picked from commit d1d29008472c1c8a313fdd8abba86a45ec03db14)
2025-07-29 10:41:38 +00:00
Shariq Ansari
ff35a03f9d chore: Arabic translations
(cherry picked from commit 98d851d76d8089ded88f0d5073c929a60116fdcc)
2025-07-29 10:41:37 +00:00
Shariq Ansari
3a613a88ef chore: Spanish translations
(cherry picked from commit 30fdc1db4cc56a6b4e55ef58a7db7adce9f3a2b2)
2025-07-29 10:41:37 +00:00
Shariq Ansari
c9e9c9bd59 chore: French translations
(cherry picked from commit 12df15154dbda766775f39496a66ee926e3a4848)
2025-07-29 10:41:37 +00:00
Shariq Ansari
61930ec4a1 chore: German translations
(cherry picked from commit 0bf6c01f915b7a133797b01a71990d38c89e4771)
2025-07-29 10:41:36 +00:00
Shariq Ansari
02c4d4b9f1 chore: Serbian (Latin) translations
(cherry picked from commit 497263f3672aa95b14d88f0a9222ac76b001c544)
2025-07-29 10:41:36 +00:00
Shariq Ansari
352ddd6ed1 chore: Bosnian translations
(cherry picked from commit cd458d6d2288a9ac2af1ff3037bea22ad71857ee)
2025-07-29 10:41:36 +00:00
Shariq Ansari
eb5d8cd2c6 chore: Indonesian translations
(cherry picked from commit a2b55166ed91c0a5105f9a10cdff5518f08dfed6)
2025-07-29 10:41:36 +00:00
Shariq Ansari
7e89408105 chore: Portuguese, Brazilian translations
(cherry picked from commit 570d31b6d15145d5c5f1f9d7e54032af75c76de5)
2025-07-29 10:41:35 +00:00
Shariq Ansari
441c4f7edd chore: Swedish translations
(cherry picked from commit 2483dd6828426cb97f3db2000c92214c2019745f)
2025-07-29 10:41:35 +00:00
Shariq Ansari
6f9ec66d02 chore: Serbian (Cyrillic) translations
(cherry picked from commit 1adef98c57335e9ed2bb72742433f6e08f57db96)
2025-07-29 10:41:35 +00:00
Shariq Ansari
2b61b68cb5 chore: Polish translations
(cherry picked from commit dfd3c8f2bfc8ee924bad35cabf024a68db3b20fb)
2025-07-29 10:41:34 +00:00
Shariq Ansari
84f9b0589d chore: Italian translations
(cherry picked from commit 015c592978b4b128da0c98b412e811f4d201eeb9)
2025-07-29 10:41:34 +00:00
Shariq Ansari
3c464fe58e
Merge pull request #1092 from frappe/mergify/bp/main-hotfix/pr-1091
fix: reload doc after sending email (backport #1091)
2025-07-29 14:15:21 +05:30
Shariq Ansari
3ca2883efb fix: reload doc after sending email
(cherry picked from commit ea0011771b268ee60dce56cd9262e24a921a45d4)
2025-07-29 08:44:28 +00:00
Frappe PR Bot
2708274f9f chore(release): Bumped to Version 1.52.1 2025-07-29 06:23:51 +00:00
Shariq Ansari
5f9fe3a12e
Merge pull request #1088 from frappe/mergify/bp/main/pr-1087
fix: fields should not be mandatory in single doctype (backport #1087)
2025-07-29 11:53:02 +05:30
Shariq Ansari
f1786b7cd9
Merge pull request #1089 from frappe/mergify/bp/main-hotfix/pr-1087
fix: fields should not be mandatory in single doctype (backport #1087)
2025-07-29 11:52:36 +05:30
Shariq Ansari
32e6ba0645 fix: format NumberChart component for better readability
(cherry picked from commit c3cf63dfb79e1f6605fc7a0c6f5fd626329c9142)
2025-07-29 06:21:54 +00:00
Shariq Ansari
cfee08d8de fix: fields should not be mandatory in single doctype
(cherry picked from commit c532b61ef6e2335ba5c6f9467537874e3a42133a)
2025-07-29 06:21:53 +00:00
Shariq Ansari
268fff442b fix: format NumberChart component for better readability
(cherry picked from commit c3cf63dfb79e1f6605fc7a0c6f5fd626329c9142)
2025-07-29 06:05:49 +00:00
Shariq Ansari
b175f13974 fix: fields should not be mandatory in single doctype
(cherry picked from commit c532b61ef6e2335ba5c6f9467537874e3a42133a)
2025-07-29 06:05:49 +00:00
Frappe PR Bot
0340ae4ee4 chore(release): Bumped to Version 1.52.0 2025-07-28 13:00:29 +00:00
Shariq Ansari
c8a54e4d9f
Merge pull request #1086 from frappe/main-hotfix 2025-07-28 18:29:36 +05:30
Shariq Ansari
69b1237b10
Merge pull request #1085 from frappe/mergify/bp/main-hotfix/pr-1084
fix: fixed labels (backport #1084)
2025-07-28 18:20:51 +05:30
Shariq Ansari
97d9866c0e
Merge branch 'main-hotfix' into mergify/bp/main-hotfix/pr-1084 2025-07-28 18:17:45 +05:30
Shariq Ansari
aa7ebab3a1
Merge pull request #1083 from frappe/mergify/bp/main-hotfix/pr-1082 2025-07-28 18:13:20 +05:30
Shariq Ansari
03bc281763 fix: fixed labels
(cherry picked from commit 4c7a40d8bc882110784dff7a8db63a44fbd9d243)

# Conflicts:
#	frontend/src/components/Settings/General/CurrencySettings.vue
#	frontend/src/components/Settings/General/GeneralSettings.vue
2025-07-28 12:36:17 +00:00
Shariq Ansari
a525914420
Discard changes to crm/locale/sr.po 2025-07-28 18:05:00 +05:30
Shariq Ansari
361d82e982
Discard changes to crm/locale/sr_CS.po 2025-07-28 18:04:47 +05:30
Shariq Ansari
30cc791cc7 fix: remove unused Link component import from GeneralSettings.vue
(cherry picked from commit c72160b2a491ce440458911813859e5a94548777)
2025-07-28 12:28:28 +00:00
Shariq Ansari
acf47d7570 fix: update description for mandatory fields in deal value forecasting
(cherry picked from commit e06a3650294c73deb206d0332219b3e2f80e3688)
2025-07-28 12:28:28 +00:00
Shariq Ansari
14a9571fdc fix: added exchange rate provider & currency together in settings modal
(cherry picked from commit 36e79e49da2091dfca166f1c50452285577d7584)
2025-07-28 12:28:27 +00:00
Shariq Ansari
c4df4d3253 fix: removed currency exchange rate settings and moved it to crm settings
(cherry picked from commit 5bee7022b22395b1da2e0de90746cff12e298748)
2025-07-28 12:28:27 +00:00
Shariq Ansari
53781cbf1e fix: Improve error handling in document update process
(cherry picked from commit e578513eaf9a470271d11a69f151b29459fc4ff8)
2025-07-28 12:28:27 +00:00
Shariq Ansari
1c4dd8a59d chore: Serbian (Latin) translations
(cherry picked from commit 2a6f1c402b1332a6f8cafed76e8e906486758df5)

# Conflicts:
#	crm/locale/sr_CS.po
2025-07-28 12:28:26 +00:00
Shariq Ansari
5e1ae83b72 chore: Serbian (Cyrillic) translations
(cherry picked from commit 25d2b1889f6cc3a5f37ca8b4f0047723861c9189)

# Conflicts:
#	crm/locale/sr.po
2025-07-28 12:28:26 +00:00
Shariq Ansari
65366f3430 chore: Serbian (Latin) translations
(cherry picked from commit ee843fae26a1ad197972c2802b477921cac4f5c4)

# Conflicts:
#	crm/locale/sr_CS.po
2025-07-28 12:28:26 +00:00
Shariq Ansari
1f51a97f04 chore: Serbian (Cyrillic) translations
(cherry picked from commit 3b9ff8d58f6610b9a012fc70093d5a06591e0623)

# Conflicts:
#	crm/locale/sr.po
2025-07-28 12:28:26 +00:00
Shariq Ansari
cab54be0ab fix: update exchange rate fetching logic to include service provider context and improve error handling
(cherry picked from commit b46d5a4e5ebaf565fb998262bc5391b8bb7630b6)
2025-07-28 12:28:25 +00:00
Shariq Ansari
c9b4bf801d feat: enhance document handling with error triggering and settings helpers via app
(cherry picked from commit 23a823f2bbca6c21ef32ec55d10339b86c5a1f57)
2025-07-28 12:28:25 +00:00
Shariq Ansari
bdcd7c5487 fix: moved get_exchange_rate api to exchange rate settings
(cherry picked from commit 7e9d9a5fed5852f72f69ec76160c3d757fb52372)
2025-07-28 12:28:25 +00:00
Shariq Ansari
7072686565 fix: added currency exchange rate settings
(cherry picked from commit 45826e0a887be6d95918ea90ef3e144cda59f4fe)
2025-07-28 12:28:25 +00:00
Shariq Ansari
74063026c8 fix: get latest exchange rate
(cherry picked from commit 5bfcaf48097e5b097a76bc4056b4d2f7e2efecc2)
2025-07-28 12:28:24 +00:00
Shariq Ansari
1e0e9fce92
Merge pull request #1081 from frappe/mergify/bp/main-hotfix/pr-1077
fix: Correct field name from 'agent' to 'user' in CRM Telephony Agent… (backport #1077)
2025-07-28 15:58:10 +05:30
Meer Uzair
092249a159 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.

(cherry picked from commit 7f4f6ff6518bc6cf795d90ea9c74c48dfe0c8c88)
2025-07-28 10:27:32 +00:00
Shariq Ansari
1fdc8bbe34
Merge pull request #1079 from frappe/mergify/bp/main-hotfix/pr-1074 2025-07-28 15:56:31 +05:30
Shariq Ansari
2b84ca7fd6
Merge pull request #1080 from frappe/mergify/bp/main-hotfix/pr-1076 2025-07-28 15:56:21 +05:30
frappe-pr-bot
97826bccac chore: update POT file
(cherry picked from commit 7d9b7e92fb0124bd94154bdaf0429ac95f7c5f25)
2025-07-28 10:24:31 +00:00
Shariq Ansari
85b2650ccb chore: Serbian (Latin) translations
(cherry picked from commit 881543396291fc2655efd8e650f3f56caf41a418)
2025-07-28 10:24:28 +00:00
Shariq Ansari
7c5bde4d78 chore: Serbian (Cyrillic) translations
(cherry picked from commit e4261820d429c69af8b59907d0f1378d3d2c263f)
2025-07-28 10:24:28 +00:00
Shariq Ansari
43b13c30ac chore: Serbian (Latin) translations
(cherry picked from commit 63963414c140783f8b4157966da7ce53312a8c77)
2025-07-28 10:24:28 +00:00
Shariq Ansari
4537cc6e6c chore: Bosnian translations
(cherry picked from commit f0ee245f75109aa7c374d4800af7fd20c5fd7124)
2025-07-28 10:24:27 +00:00
Shariq Ansari
21e3d126e3 chore: Indonesian translations
(cherry picked from commit a4710a8b858fab7e1516d687c9852b65d4cfe740)
2025-07-28 10:24:27 +00:00
Shariq Ansari
8e6409dd9b chore: Swedish translations
(cherry picked from commit 201ad61e6da5f8840f8ffb59e57621960458cc88)
2025-07-28 10:24:27 +00:00
Shariq Ansari
8d92094324 chore: Serbian (Cyrillic) translations
(cherry picked from commit bbb9eefc9a4b60639f7d49b72b25973dc8920edb)
2025-07-28 10:24:26 +00:00
Shariq Ansari
b555449dcf
Merge pull request #1071 from frappe/mergify/bp/main-hotfix/pr-1070 2025-07-24 13:16:04 +05:30
Shariq Ansari
01418c43f6 refactor: MultiActionButton dropdown
(cherry picked from commit b1d90952c4b8f3d149a862d186b4e8bc8e00c797)
2025-07-24 07:45:51 +00:00
Shariq Ansari
a6e05c2a65 fix: update label for call log actions to "Log a Call"
(cherry picked from commit 742bd6e213a9397d2ec35357ea15f35483141ae0)
2025-07-24 07:45:51 +00:00
Shariq Ansari
59c4d90278
Merge pull request #1069 from frappe/mergify/bp/main-hotfix/pr-1068
fix: make mobile no primary on create of contact (backport #1068)
2025-07-24 12:39:39 +05:30
Shariq Ansari
657e758f5c fix: make mobile no primary on create of contact
(cherry picked from commit 8e08e6f415f2749f4ef79948e22dedacbf8336ba)
2025-07-24 07:03:09 +00:00
Shariq Ansari
d2b544dafd
Merge pull request #1067 from frappe/mergify/bp/main-hotfix/pr-1066 2025-07-24 12:30:27 +05:30
Shariq Ansari
2c2d49718a docs: add compatibility section with supported Frappe and ERPNext versions in README
(cherry picked from commit 0327b37d2f1e8758984917a479ca030bc463f4bf)
2025-07-24 06:27:05 +00:00
Shariq Ansari
5f347a8593
Merge pull request #1065 from frappe/mergify/bp/main-hotfix/pr-1064 2025-07-24 11:33:28 +05:30
Shariq Ansari
f6bd72411d chore: Bosnian translations
(cherry picked from commit a08fabaed9e48629590969c4996eb25e1c2c4c70)
2025-07-24 06:00:02 +00:00
Shariq Ansari
e33bfd82a8 chore: Croatian translations
(cherry picked from commit 61e276df37169f2e84b4b581569e163b94a0ed35)
2025-07-24 06:00:01 +00:00
Frappe PR Bot
6091f44650 chore(release): Bumped to Version 1.51.1 2025-07-23 08:13:06 +00:00
Shariq Ansari
f0b58ba28a
Merge pull request #1062 from frappe/main-hotfix 2025-07-23 13:42:20 +05:30
Shariq Ansari
b8dde8c41c
Merge pull request #1061 from frappe/mergify/bp/main-hotfix/pr-1059
fixes (backport #1059)
2025-07-23 13:38:02 +05:30
Shariq Ansari
bafe1c7e0a fix: improve exchange rate fetching with retry logic and default return value
(cherry picked from commit 9761989ea49fee7dacb3dcf756887f05f5a2cc9c)
2025-07-23 08:07:09 +00:00
Shariq Ansari
c345d5b5bd refactor: rename update_close_date to update_closed_date and adjust related logic
(cherry picked from commit c84ac2933265889a599bd1cc8e57fb802fa2baea)
2025-07-23 08:07:08 +00:00
Shariq Ansari
3e51d875f7 refactor: cache assignees
(cherry picked from commit cf8a1ce8a3e465c0762a8158c14d0ac8e7207663)
2025-07-23 08:07:08 +00:00
Shariq Ansari
96ff1c2fdb
Merge pull request #1060 from frappe/mergify/bp/main-hotfix/pr-1057 2025-07-23 13:34:31 +05:30
Shariq Ansari
6bb18198e8 chore: Serbian (Latin) translations
(cherry picked from commit 15077019810bd9a3c6eb0233066761b24d71685e)
2025-07-23 07:55:01 +00:00
Shariq Ansari
bead791e23 chore: Bosnian translations
(cherry picked from commit b4796efed16e1a65f826f62a47e6c32fe63dfe96)
2025-07-23 07:55:01 +00:00
Shariq Ansari
3b2cc05b3f chore: Croatian translations
(cherry picked from commit 273f7d7f07a562d1dc23768c6944a32278bd1149)
2025-07-23 07:55:01 +00:00
Shariq Ansari
b5283e73e5 chore: Thai translations
(cherry picked from commit 8474630f4c424595fab78a5dbee434dbf6e5d7c6)
2025-07-23 07:55:00 +00:00
Shariq Ansari
500664328d chore: Persian translations
(cherry picked from commit 907ec5fa3c083e6ea9f8627b53c253cb921e5dad)
2025-07-23 07:55:00 +00:00
Shariq Ansari
04eed192d2 chore: Indonesian translations
(cherry picked from commit 43001bee9f1183de91b9ad08580f6bdb79e73bcf)
2025-07-23 07:54:56 +00:00
Shariq Ansari
9e276352d5 chore: Portuguese, Brazilian translations
(cherry picked from commit 5479a6b885a3f992678b448031631dc5815f901b)
2025-07-23 07:54:56 +00:00
Shariq Ansari
155326cb83 chore: Vietnamese translations
(cherry picked from commit 594f7922f9b8f18612add59e2a60aed33ce337fd)
2025-07-23 07:54:55 +00:00
Shariq Ansari
ec10eb1c27 chore: Chinese Simplified translations
(cherry picked from commit 7aa9f768ea9f86debc910136cb93371a6cc1b1d7)
2025-07-23 07:54:55 +00:00
Shariq Ansari
866147ce6a chore: Turkish translations
(cherry picked from commit b796a30e1f1bfe6d38e052acbc26f351aca5c6f6)
2025-07-23 07:54:55 +00:00
Shariq Ansari
5347b9d858 chore: Swedish translations
(cherry picked from commit 5508eb013a5a01a0835e07ae972d4cb1650ea7fe)
2025-07-23 07:54:54 +00:00
Shariq Ansari
c03dd38433 chore: Serbian (Cyrillic) translations
(cherry picked from commit a3c7af7c8cdb4a0b0abe60ec3e5b80af4ec20f63)
2025-07-23 07:54:54 +00:00
Shariq Ansari
b07b80c8b9 chore: Russian translations
(cherry picked from commit d689bf21d2fb8e7c72e4a1822198a99d8ef3ebd6)
2025-07-23 07:54:54 +00:00
Shariq Ansari
40cd0b3bc2 chore: Portuguese translations
(cherry picked from commit 05ea067361fc20d23c66baf8ce878e9680125021)
2025-07-23 07:54:54 +00:00
Shariq Ansari
42f886d7f1 chore: Polish translations
(cherry picked from commit 2af8710a6f4d725c9f6db6b53b5655f086491aae)
2025-07-23 07:54:53 +00:00
Shariq Ansari
4eb21e2c46 chore: Dutch translations
(cherry picked from commit 6abc9f7f9fb491ed5a76e165a536dec784ba8bce)
2025-07-23 07:54:53 +00:00
Shariq Ansari
3d73dbd393 chore: Italian translations
(cherry picked from commit 7de21b70154bf45c2ae89873b78e3bcbfce2061d)
2025-07-23 07:54:53 +00:00
Shariq Ansari
bae3b574ec chore: Hungarian translations
(cherry picked from commit f9bae5d8fff576a1599fafe346b514d4e826d200)
2025-07-23 07:54:52 +00:00
Shariq Ansari
c9ed426231 chore: German translations
(cherry picked from commit 29322577aad610ef1e86fd1f68f8cebea0258369)
2025-07-23 07:54:52 +00:00
Shariq Ansari
504d23e920 chore: Czech translations
(cherry picked from commit a4f96c7c5b10a4226a7b0645605e1e646d250c5b)
2025-07-23 07:54:52 +00:00
Shariq Ansari
edb545b84b chore: Arabic translations
(cherry picked from commit b3fe85b8a067d73ca85b661d35f60360b7ec2294)
2025-07-23 07:54:51 +00:00
Shariq Ansari
bced2c5b29 chore: Spanish translations
(cherry picked from commit efc42133638c481bcc64670306dcde246b1eb4fe)
2025-07-23 07:54:51 +00:00
Shariq Ansari
e9f8af6f98 chore: French translations
(cherry picked from commit b983648f35120f17c2c18c87276769fed3ed7797)
2025-07-23 07:54:51 +00:00
Shariq Ansari
de5348f61e
Merge pull request #1056 from frappe/mergify/bp/main-hotfix/pr-1054 2025-07-22 10:55:19 +05:30
Shariq Ansari
02c2478cdc
Merge pull request #1055 from frappe/mergify/bp/main-hotfix/pr-1053
fix: updated crowdin.yml (backport #1053)
2025-07-22 10:54:51 +05:30
Shariq Ansari
f448c7315e chore: Esperanto translations
(cherry picked from commit e6f1bd50db7b576f4cb1b5065cfbf80ccc64d98d)
2025-07-22 05:24:27 +00:00
Shariq Ansari
23963edf88 chore: Serbian (Latin) translations
(cherry picked from commit c5458fb29c323fc1cc7c551cbd0b7783d1a17d0d)
2025-07-22 05:24:26 +00:00
Shariq Ansari
09a22264da chore: Bosnian translations
(cherry picked from commit 8e3daf482def8a55950ad56e2086d8e1fc47afc0)
2025-07-22 05:24:26 +00:00
Shariq Ansari
c0d00e7776 chore: Croatian translations
(cherry picked from commit 03edd1a0117f5a193896854eb9ea239c831444b2)
2025-07-22 05:24:26 +00:00
Shariq Ansari
2b10583b7c chore: Thai translations
(cherry picked from commit 246ed83a3d248f63bc067d6cb020b28d71a2adf3)
2025-07-22 05:24:25 +00:00
Shariq Ansari
e540dcc39e chore: Persian translations
(cherry picked from commit 53440476c409a7913d48f2ca4218d92ead95dc14)
2025-07-22 05:24:25 +00:00
Shariq Ansari
3c419a7cf3 chore: Indonesian translations
(cherry picked from commit 14f3fd3cd712473f67739a462395eff92dee6315)
2025-07-22 05:24:25 +00:00
Shariq Ansari
0cba0cf658 chore: Portuguese, Brazilian translations
(cherry picked from commit 6c9d56808bf0bfaf41dac47ccfbc6cc361e59695)
2025-07-22 05:24:25 +00:00
Shariq Ansari
0a3c84ae95 chore: Vietnamese translations
(cherry picked from commit 08b3107d92a5522bf3374fb6ae01618cd3588b69)
2025-07-22 05:24:24 +00:00
Shariq Ansari
15164b348a chore: Chinese Simplified translations
(cherry picked from commit dc8fa27ea15fb72906b608837f404ceca1afd7df)
2025-07-22 05:24:24 +00:00
Shariq Ansari
5e94726d42 chore: Turkish translations
(cherry picked from commit 445d7050b776f33b37c27722f47b2cd6833e119f)
2025-07-22 05:24:24 +00:00
Shariq Ansari
4f490fef0d chore: Swedish translations
(cherry picked from commit bfe0df4df3c9cedc2534418e838ab5084d4b6b9b)
2025-07-22 05:24:24 +00:00
Shariq Ansari
67ab8d2619 fix: updated crowdin.yml
(cherry picked from commit a5a37c61815566fc8853018f244ad7fc27ee69a6)
2025-07-22 05:24:23 +00:00
Shariq Ansari
98e5242d6e chore: Serbian (Cyrillic) translations
(cherry picked from commit 71bcca71cd56a5042c4b867bf51a17c3d33ac985)
2025-07-22 05:24:23 +00:00
Shariq Ansari
3324913959 chore: Russian translations
(cherry picked from commit 53864ac12c221a3a78d7a0c845adc658262c2a58)
2025-07-22 05:24:23 +00:00
Shariq Ansari
cd1355a6b6 chore: Portuguese translations
(cherry picked from commit f438500a57d84e10a54df1fedb8dcf10c58cad57)
2025-07-22 05:24:23 +00:00
Shariq Ansari
b74b137ff8 chore: Polish translations
(cherry picked from commit cef8aacf2f73765366385b7bce9fab84b3687659)
2025-07-22 05:24:22 +00:00
Shariq Ansari
2e209b6a5f chore: Dutch translations
(cherry picked from commit 1ab414c4bf30675d62f4b38656b8f9a707d92283)
2025-07-22 05:24:22 +00:00
Shariq Ansari
22391adbb9 chore: Italian translations
(cherry picked from commit fdffd7bf3a5b77934173582034ea0d7d97af5431)
2025-07-22 05:24:22 +00:00
Shariq Ansari
b38007f7b5 chore: Hungarian translations
(cherry picked from commit 6fc52aba6d08f7e366f68fc80e8a9df60bb98f59)
2025-07-22 05:24:22 +00:00
Shariq Ansari
f46609c242 chore: German translations
(cherry picked from commit dfd4cc068a72e1055c2eac0fd003b0c19fe518ea)
2025-07-22 05:24:21 +00:00
Shariq Ansari
25217e6214 chore: Czech translations
(cherry picked from commit 5ae21c858042ea081f7042877ec1c9bf7dcf24ef)
2025-07-22 05:24:21 +00:00
Shariq Ansari
bca8cdfe52 chore: Arabic translations
(cherry picked from commit 178a934fa386a81baff22d745f873487a6145eae)
2025-07-22 05:24:21 +00:00
Shariq Ansari
77b5c66e3d chore: Spanish translations
(cherry picked from commit 1ce508a4b1f37d53b31a095ab7324d8db60675ac)
2025-07-22 05:24:21 +00:00
Shariq Ansari
6dc7372658 chore: French translations
(cherry picked from commit d0678ec7c25e9d1784dfc5812a18bcf4fc4ebba6)
2025-07-22 05:24:20 +00:00
Shariq Ansari
b55d3da612
Merge pull request #1052 from frappe/mergify/bp/main-hotfix/pr-1050 2025-07-22 10:25:13 +05:30
frappe-pr-bot
69f8733f2b chore: update POT file
(cherry picked from commit 8de2e89b6833a5d5d11402406b4c9590fe99817f)
2025-07-22 04:53:20 +00:00
Frappe PR Bot
cd0e076952 chore(release): Bumped to Version 1.51.0 2025-07-15 10:00:06 +00:00
Shariq Ansari
b0989566d9
Merge pull request #1043 from frappe/main-hotfix 2025-07-15 15:22:40 +05:30
Shariq Ansari
fa5d17a121
Merge pull request #1042 from frappe/mergify/bp/main-hotfix/pr-1041
fix: Reset to default dashboard (backport #1041)
2025-07-15 15:13:16 +05:30
Shariq Ansari
51d39a1dbb fix: reset to default
(cherry picked from commit 7826565ce77a6d75b2e16011571f46512e7cb486)
2025-07-15 09:41:53 +00:00
Shariq Ansari
6d164cdac4 fix: only show edit button to system manager
(cherry picked from commit 713571469b81b773413e4f2287f25bde372cc044)
2025-07-15 09:41:53 +00:00
Shariq Ansari
98c830f3ae fix: set status correctly
(cherry picked from commit 2f34fdd40917bb084e0d648d03b75791ce2c7689)
2025-07-15 09:41:53 +00:00
Shariq Ansari
09b4e25500
Merge pull request #1040 from frappe/mergify/bp/main-hotfix/pr-1033 2025-07-15 13:42:44 +05:30
Shariq Ansari
78dc0f6af6 fix: forecasting chart is breaking if no data
(cherry picked from commit b344f412c9cf84fff35284b396788160e9852e31)
2025-07-15 08:00:12 +00:00
Shariq Ansari
52bc66dc3d fix: updated default manager dashboard
(cherry picked from commit c8f01f08ed36ee357778442ca9f04127806117bf)
2025-07-15 08:00:11 +00:00
Shariq Ansari
053650ee75 fix: minor fix
(cherry picked from commit 46e6ed2e6f4cb25855e019d7a405a3ad8e80dd5e)
2025-07-15 08:00:11 +00:00
Shariq Ansari
5c3ef0158c fix: decreased rowHeight to 42
(cherry picked from commit 266952c404dbdbb6443fcabb73a1bc00de6c84f9)
2025-07-15 08:00:11 +00:00
Shariq Ansari
99402b8e43 build(deps): bump frappeui to 0.1.171
(cherry picked from commit b77e59589a5270164aedcc890889df151767de51)
2025-07-15 08:00:11 +00:00
Shariq Ansari
4d7a5f17d6 fix: renamed blank card to spacer
(cherry picked from commit d79341b6d9b2c9fec00471f48cbb70cebd98e21d)
2025-07-15 08:00:10 +00:00
Shariq Ansari
ba0ef22911 fix: allow force reset manager dashboard
(cherry picked from commit 84738ba00cb08a71f4902617dff62b5ba1d99a09)
2025-07-15 08:00:10 +00:00
Shariq Ansari
d099d7e3e5 fix: updated default manager dashboard
(cherry picked from commit 3b0a8d8e4bb3248e56589d23f817e4b04c2cd2cd)
2025-07-15 08:00:10 +00:00
Shariq Ansari
859d93404d fix: minor fixes
(cherry picked from commit 2584cca128628b3cb7afa8b2307bfe6e61c303c5)
2025-07-15 08:00:10 +00:00
Shariq Ansari
6f71d738b3 fix: create default manager dashboard if not exists
(cherry picked from commit 05b8cea2066e27a8dbcf14aa5a8ae402f13e2130)
2025-07-15 08:00:09 +00:00
Shariq Ansari
ba4ffdac86 fix: add default Manager Dashboard on install
(cherry picked from commit 6e3d23a8e1cb2b6c4c1933a9cfa2d6fb04dd6c4c)
2025-07-15 08:00:09 +00:00
Shariq Ansari
151560fa5e fix: disabel save button if not dirty, reset to old items if cancel
(cherry picked from commit 2a38d0fb5f83e85665b295a808ac8ac9eb99a75e)
2025-07-15 08:00:09 +00:00
Shariq Ansari
d80f7965ec build(deps): bump frappeui to 0.1.170
(cherry picked from commit 97724c776bcbf2062bf3057726233d4511c037d1)
2025-07-15 08:00:08 +00:00
Shariq Ansari
3e72981993 build(deps): bump frappeui to 0.1.170
(cherry picked from commit 9b072058cc020455084e0f6234ca6628afe846be)
2025-07-15 08:00:08 +00:00
Shariq Ansari
67774f3014 fix: save edited dashboard
(cherry picked from commit d2e65feaa6fcf7759839fbb92ded68b525629260)
2025-07-15 08:00:08 +00:00
Shariq Ansari
55c4ad9533 feat: allow adding existing charts
(cherry picked from commit 37c2d3a2b07ae8a1836dfb80fe098810f0b69f74)
2025-07-15 08:00:08 +00:00
Shariq Ansari
c027bcf59b fix: rename card to chart
(cherry picked from commit 0909423fe9385fa33d110f7bc49693fe81902126)
2025-07-15 08:00:07 +00:00
Shariq Ansari
12814dc5b0 fix: added remove chart button
(cherry picked from commit 139bcb101ce3f903bcb840fbd4fecf84f55ca91f)
2025-07-15 08:00:07 +00:00
Shariq Ansari
ecccc6340f fix: use tooltip from data
(cherry picked from commit 0f06715d0cdf967240783aa97d996becc92dcd4c)
2025-07-15 08:00:07 +00:00
Shariq Ansari
1b7e337176 fix: show edit button to manager
(cherry picked from commit 4a783fcba8241ec73f0def366830144a8e2c870d)
2025-07-15 08:00:07 +00:00
Shariq Ansari
1be736cb6f fix: load dashboard layout from CRM Dashboard doctype and render
(cherry picked from commit fd38f0ac985360eae2e370e86b3e8dd5a8baa587)
2025-07-15 08:00:06 +00:00
Shariq Ansari
8defe6285f fix: added crm dashboard doctype to store dashboard layout
(cherry picked from commit ed2208fe75de2d4d7f2e6f27cf036d2f058088b1)
2025-07-15 08:00:06 +00:00
Shariq Ansari
3332a74dab fix: update status type patch was not working
(cherry picked from commit 4320142132c4812d9b6ece42cb8cc656e9065ff9)
2025-07-15 08:00:06 +00:00
Shariq Ansari
c879fa57cf fix: use GridLayout from frappe-ui to display dashboard
(cherry picked from commit 160649bf9750ef9ca6e5bee8e759a51ad4fd243a)
2025-07-15 08:00:05 +00:00
Shariq Ansari
92879d3cbe
Merge pull request #1039 from frappe/mergify/bp/main-hotfix/pr-1038
fix: to status type is not accessible (backport #1038)
2025-07-15 12:57:12 +05:30
Shariq Ansari
1a672dd274 fix: to status type is not accessible
(cherry picked from commit 28facd66c417e2733215c8efd807e4157586ec89)
2025-07-15 07:09:50 +00:00
Shariq Ansari
0e8758e798
Merge pull request #1037 from frappe/mergify/bp/main-hotfix/pr-1036
fix: to status type is not accessible (backport #1036)
2025-07-15 12:26:14 +05:30
Shariq Ansari
64f4ed62ce fix: to status type is not accessible
(cherry picked from commit 38a2fa87c32742bef1c8ee2bf3b1e662751a8475)
2025-07-15 06:49:32 +00:00
Shariq Ansari
bd27266b69
Merge pull request #1035 from frappe/mergify/bp/main-hotfix/pr-1034
fix: removed currency exchange and added exchange rate field (backport #1034)
2025-07-15 12:17:26 +05:30
Shariq Ansari
6efd81073d fix: removed currency exchange and added exchange rate field
(cherry picked from commit 7c4718ad0290629bc69ed9d170c384836b665f54)
2025-07-15 06:22:23 +00:00
Shariq Ansari
f091899da7
Merge pull request #1032 from frappe/mergify/bp/main-hotfix/pr-1029 2025-07-14 17:58:51 +05:30
frappe-pr-bot
6da91d67f3 chore: update POT file
(cherry picked from commit bb08f3d377d0a28a4e7c102923e93bff4e62d65d)
2025-07-13 09:52:19 +00:00
Shariq Ansari
eaf61005cd
Merge pull request #1031 from frappe/mergify/bp/main-hotfix/pr-1030 2025-07-13 15:20:59 +05:30
Shariq Ansari
65a8ba139d fix: updated funnel query to get status change count
(cherry picked from commit 5232da6ec3f7e0bdb4ca55e8f6a3e42ff62ff05c)
2025-07-13 09:46:22 +00:00
Shariq Ansari
da5192bee3 fix: store deal status type in status log
(cherry picked from commit e59547da30ad1dc783787e7d0760f94ea3b95272)
2025-07-13 09:46:21 +00:00
Shariq Ansari
72dc3904c0 fix: added deals by ongoing & won stages bar
(cherry picked from commit de85ccfc51fdf7ac5c87084baccd602930102504)
2025-07-13 09:46:21 +00:00
Shariq Ansari
107eeae116 fix: used closed_date instead of closed_on and set closed_date if status type is Won
(cherry picked from commit f82019e510612bd9803f9947240d155479d5d665)
2025-07-13 09:46:21 +00:00
Shariq Ansari
209da0f84e fix: used expected closed date & deal value for forecasting
(cherry picked from commit 7fc26a5202b89476ec5e277601243cf8299ed10f)
2025-07-13 09:46:21 +00:00
Shariq Ansari
a6c60ffecb fix: added closed_date removed closed_on & added expected_deal_value & expected_closure_date field
(cherry picked from commit dcb1e475646e0f0c7096241fcb5bbeb997685230)
2025-07-13 09:46:21 +00:00
Shariq Ansari
e6033dfb9a fix: avg time to close a deal number card
(cherry picked from commit 61259f3d2e843f851b7d08e9089de55e01496e6b)
2025-07-13 09:46:20 +00:00
Shariq Ansari
55ad85dda8 fix: added two more number cards
(cherry picked from commit 2dd2608c094226efe17d5bbdf1520afc667151ca)
2025-07-13 09:46:20 +00:00
Shariq Ansari
697ed4eb98 fix: get ongoing deals and won deals based on closed_on date
(cherry picked from commit 81dc4e1138c86a5ab4a80ab57d1a521bc65ecc1b)
2025-07-13 09:46:20 +00:00
Shariq Ansari
64dfa77022 fix: use status.type instead of status in all query
(cherry picked from commit cb1f9f760cbcda42654e99ff5e98583591ae6874)
2025-07-13 09:46:20 +00:00
Shariq Ansari
d52ee6653c fix: show lost reason modal if status of type Lost is set
(cherry picked from commit 51530b760830002e9ba3f8bc8cce69d94fd51d9c)
2025-07-13 09:46:19 +00:00
Shariq Ansari
f7bcc4b910 patch: added patch to update deal status type
(cherry picked from commit 4e6d4a1d77b062c531b8c84634c312b6cb3537fe)
2025-07-13 09:46:19 +00:00
Shariq Ansari
c5193f3105 fix: added type in default deak status while installing
(cherry picked from commit efc5dd93e91760aa73a4d8a360d642c4031df8ee)
2025-07-13 09:46:19 +00:00
Shariq Ansari
5bd01ca7d9 fix: added type of deal status field
(cherry picked from commit 210a9d8d0635f296a72e65e1ce2899d274b5a6fa)
2025-07-13 09:46:18 +00:00
Frappe PR Bot
2ce5e02d99 chore(release): Bumped to Version 1.50.2 2025-07-10 13:18:07 +00:00
Shariq Ansari
9d609e528c
Merge pull request #1026 from frappe/mergify/bp/main/pr-1024
fix: cannot save data fields in lead page (backport #1024)
2025-07-10 18:47:11 +05:30
Shariq Ansari
1f445b49cf
Merge pull request #1025 from frappe/mergify/bp/main-hotfix/pr-1024
fix: cannot save data fields in lead page (backport #1024)
2025-07-10 18:47:01 +05:30
Shariq Ansari
de4647f5ab fix: cannot save data fields in lead page
(cherry picked from commit 970c215f40f3bbecc21253ca7e05a5ec68508fd0)
2025-07-10 13:04:46 +00:00
Shariq Ansari
742fd750cf fix: cannot save data fields in lead page
(cherry picked from commit 970c215f40f3bbecc21253ca7e05a5ec68508fd0)
2025-07-10 13:04:33 +00:00
Shariq Ansari
3a88910711
Merge pull request #1023 from frappe/mergify/bp/main-hotfix/pr-1022
fix: apply user filter if sales user (backport #1022)
2025-07-10 17:40:46 +05:30
Shariq Ansari
7d695a13cf fix: apply user filter if sales user
(cherry picked from commit 1ae7018f792c4956c7db352fa18e94f562776693)
2025-07-10 12:10:03 +00:00
Shariq Ansari
3a27fb91c1
Merge pull request #1021 from frappe/mergify/bp/main-hotfix/pr-979 2025-07-10 17:33:15 +05:30
Shariq Ansari
b95565a70c
chore: resolved conflict 2025-07-10 17:26:27 +05:30
Shariq Ansari
b369211965 fix: better description
(cherry picked from commit cbc127e9470462a79ae5ef1c85590493eaf225a5)
2025-07-10 11:53:09 +00:00
Shariq Ansari
40f74b4316 fix: make autocomplete non clickable if disabled
(cherry picked from commit d91d4765b5502b5fa7970d51e499ee9cf15f67ae)
2025-07-10 11:53:09 +00:00
Shariq Ansari
c1983e8241 style: better spacing
(cherry picked from commit 328959cc394b7fd7b27403507bce91b855f87d2e)
2025-07-10 11:53:09 +00:00
Shariq Ansari
61c2180498 fix: remove mandatory from currency field in crm settings
(cherry picked from commit 36320f61aba9b7e1365f3c1ceccfbe53d181fd94)
2025-07-10 11:53:09 +00:00
Shariq Ansari
95773bec71 chore: minor fix
(cherry picked from commit faeacb9a7d87d5bcf6f0bbd904cb619b3fe84145)
2025-07-10 11:53:08 +00:00
Shariq Ansari
d75cde4bb0 fix: added forecasting & currency setting in general settings
(cherry picked from commit 5dcd416007e5f9e0515f2525deaa88323cedc11b)
2025-07-10 11:53:08 +00:00
Shariq Ansari
59030f8d44 fix: added disabled & placement prop in Link component
(cherry picked from commit 33e4072430d4fa117bcc95553a6f31593282a18d)
2025-07-10 11:53:08 +00:00
Shariq Ansari
f733ef2fe7 refactor: general settings
(cherry picked from commit c7fbd6f8f15b73fa2d69065eac32a014fef2596c)
2025-07-10 11:53:08 +00:00
Shariq Ansari
69780ecbd9 refactor: get exchange rate api
(cherry picked from commit a5d3694386bbeff789a8feea76323f5d41509198)
2025-07-10 11:53:08 +00:00
Shariq Ansari
e91ebc7eb9 fix: show dashboard to manager only
(cherry picked from commit b3075416e2d0df8549e920d837cbe532b47d6f8b)
2025-07-10 11:53:07 +00:00
Shariq Ansari
756fdd212a fix: use exchange rate in deal to calculate the deal value
(cherry picked from commit 2cb09dde4bddd28584b8c35c86efb091a5e94d0b)
2025-07-10 11:53:07 +00:00
Shariq Ansari
6e3737403d fix: store current day exchange rate when currency is updated in deal & organization
(cherry picked from commit d7ba5a5f629d5fe7cf3a00fddd8df7818e7b874d)

# Conflicts:
#	crm/fcrm/doctype/crm_deal/crm_deal.json
2025-07-10 11:53:07 +00:00
Shariq Ansari
910c1e0c78 fix: remove crm currency exchange doctype
(cherry picked from commit a00bba35f872816895711ca04599b23012897aa7)
2025-07-10 11:53:06 +00:00
Shariq Ansari
016af283ca fix: make currency read only once set
(cherry picked from commit 71db65d21c47db6098ff7e0a9ad3cfc8a966106b)
2025-07-10 11:53:06 +00:00
Shariq Ansari
da04edccb2 chore: updated/added number card tooltip
(cherry picked from commit 37d820a67c901e030b2034570cadddacf6d4a961)
2025-07-10 11:53:06 +00:00
Shariq Ansari
6e71321e7d fix: convert to system currency and show deal value
(cherry picked from commit 4f02f0a4d7c3b947028b193a935eadc7d1c3462f)
2025-07-10 11:53:06 +00:00
Shariq Ansari
e81c49ee7b fix: added date field in currency exchange doctype
(cherry picked from commit f4b81b376189dd1668a2391bff42e813c99af9e6)
2025-07-10 11:53:06 +00:00
Shariq Ansari
37c931c9c2 fix: store currency exchange in deal & organization
(cherry picked from commit 0be737914a7aaf70a55415419e31c0356b402d96)

# Conflicts:
#	crm/fcrm/doctype/crm_deal/crm_deal.json
2025-07-10 11:53:06 +00:00
Shariq Ansari
a59afeb327 fix: created currency exchange doctype
(cherry picked from commit 1b0d966db02dd53962abf61233e61e6eac37d7fc)
2025-07-10 11:53:05 +00:00
Shariq Ansari
39a419889f fix: only show sales user filter to manager
(cherry picked from commit f747e076ab6b1bc58eb4aa14fe01628317c0b2eb)
2025-07-10 11:53:05 +00:00
Shariq Ansari
6caff5cd59 fix: added filters and translated titles
(cherry picked from commit 4b12918ba5941ca34fc4149bb43354f8344513f8)
2025-07-10 11:53:05 +00:00
Shariq Ansari
02a60b01cb chore: cleanup
(cherry picked from commit 9d4106cd81b8dac21bf4c248b65b2d411d1d476d)
2025-07-10 11:53:05 +00:00
Shariq Ansari
10cf868df5 fix: show avg time number card based on closed_on date
(cherry picked from commit eddf8c9295d39a8c41db7ad67ef4fc2dd5ad671b)
2025-07-10 11:53:04 +00:00
Shariq Ansari
6ae7787811 fix: added avg time to close number card
(cherry picked from commit 4d2f054e4005c1f6c169994eac3daf99c2c0827a)
2025-07-10 11:53:04 +00:00
Shariq Ansari
63542f79c7 fix: capture closed on datetime when deal marked as Won
(cherry picked from commit 6450b69ae72ef2b7d57e30dacd314b27400e32ba)

# Conflicts:
#	crm/fcrm/doctype/crm_deal/crm_deal.json
2025-07-10 11:53:04 +00:00
Shariq Ansari
d5aefb3c98 fix: added more charts for dashboard
(cherry picked from commit 3b34f73cb3c302aeb5f92cbddda0257da5b4a726)
2025-07-10 11:53:03 +00:00
Shariq Ansari
1b3709c8a0 fix: added first cut queries for some charts and number cards
(cherry picked from commit 1fa6b5bb51f532db0eefeec1b66ef06fa8a0f536)
2025-07-10 11:53:03 +00:00
Shariq Ansari
0302e9958b fix: added breadcrumb and made header sticky
(cherry picked from commit 9949478b362c77690507bf7d921dd3d60d2ead07)
2025-07-10 11:53:03 +00:00
Saqib Ansari
1f8e3f3802 feat: initialize dashboard boilerplate
(cherry picked from commit 62d5c2a91f5f97b2483bbfb94b31190ba382de54)
2025-07-10 11:53:03 +00:00
Shariq Ansari
fab101aa66
Merge pull request #1020 from frappe/mergify/bp/main-hotfix/pr-1018
fix: set fieldname to handle bulk edit value modal (backport #1018)
2025-07-10 13:47:16 +05:30
Shariq Ansari
ca15b5e3b8 fix: fieldtype of value is not changing based on selected field's fieldtype
(cherry picked from commit 27f87883f75fb262c73b9ce0b49ba607868e5b69)
2025-07-10 07:00:09 +00:00
zaqouttahir
cd24337dfc fix: set fieldname to handle edit value modal
(cherry picked from commit c104b1b8b40d78e11d5a181c046bc4f77e40bb74)
2025-07-10 07:00:08 +00:00
Frappe PR Bot
4017a9373b chore(release): Bumped to Version 1.50.1 2025-07-07 09:06:42 +00:00
Shariq Ansari
c6e5fa2aea
Merge pull request #1017 from frappe/main-hotfix 2025-07-07 14:35:55 +05:30
Shariq Ansari
e8f81ec2e7
Merge pull request #1016 from frappe/mergify/bp/main-hotfix/pr-1015 2025-07-07 14:26:26 +05:30
frappe-pr-bot
ae9ffed017 chore: update POT file
(cherry picked from commit 223187c7ea84df336bd624dabf1c0ea4dc2a0cbe)
2025-07-07 08:52:30 +00:00
Shariq Ansari
3c6bfa3dd0
Merge pull request #1014 from frappe/mergify/bp/main-hotfix/pr-1013 2025-07-05 14:44:24 +05:30
Shariq Ansari
136aa73822
chore: resolved conflict 2025-07-05 14:39:32 +05:30
Shariq Ansari
8b04f3da3e
chore: resolved conflict 2025-07-05 14:38:21 +05:30
Shariq Ansari
a78a110914 fix: useDocument in organization page
(cherry picked from commit 6760798f180e1630612080905eebbded0ec81551)
2025-07-05 09:03:54 +00:00
Shariq Ansari
69277c5fb0 fix: useDocument in contact page
(cherry picked from commit 42ea1ad16e45cffab59c0bd6885be1312674e38f)

# Conflicts:
#	frontend/src/pages/Contact.vue
#	frontend/src/pages/MobileContact.vue
2025-07-05 09:03:53 +00:00
Shariq Ansari
be7154506f fix: update primary mobile_no & email in deal if contact is updated
(cherry picked from commit 96200aebe607ecfdabfcb0a4f0ea7dfa4beab213)
2025-07-05 09:03:53 +00:00
Shariq Ansari
ca52a29b6e fix: made mobile_no, email & phone readonly since it captures primary contacts data
(cherry picked from commit bcfe4b6a4991c731f40f1a17fbf3454b1879ffc8)
2025-07-05 09:03:53 +00:00
Frappe PR Bot
7a35c5224b chore(release): Bumped to Version 1.50.0 2025-07-02 12:49:24 +00:00
Shariq Ansari
2828e76657
Merge pull request #1011 from frappe/main-hotfix 2025-07-02 18:18:25 +05:30
Shariq Ansari
b6b5d47168
Merge pull request #1010 from frappe/mergify/bp/main-hotfix/pr-1009
fix: grid field is not getting set (backport #1009)
2025-07-02 17:52:45 +05:30
Shariq Ansari
8c91f38fee fix: grid field is not getting set
(cherry picked from commit 39eb5600d93ce27e4468db135db4c59ead410a74)
2025-07-02 12:21:46 +00:00
Shariq Ansari
042b740cf9
Merge pull request #1008 from frappe/mergify/bp/main-hotfix/pr-1007
fix: check reason.reason not reason (backport #1007)
2025-07-02 17:29:19 +05:30
Shariq Ansari
48006552ee fix: check reason.reason not reason
(cherry picked from commit cab80edf60c0453823e352577ebfa6b3b04cfe2f)
2025-07-02 11:57:21 +00:00
Shariq Ansari
02dc62d8ce
Merge pull request #1006 from frappe/mergify/bp/main-hotfix/pr-1005 2025-07-02 17:12:19 +05:30
Shariq Ansari
39d97e1e0b build(deps): bump frappeui to 0.1.166
(cherry picked from commit fc89c7b93caee3dbcde1db826a114f2f20d58313)
2025-07-02 11:40:14 +00:00
Shariq Ansari
412fa76875
Merge pull request #1004 from frappe/mergify/bp/main-hotfix/pr-1003
fix: add default lost reason on install (backport #1003)
2025-07-02 17:01:09 +05:30
Shariq Ansari
4d162cd0dd fix: add default lost reason on install
(cherry picked from commit 96cbdea8201301fd5b5c117742c7ecab83fff902)
2025-07-02 11:29:52 +00:00
Shariq Ansari
9f6832a5b6
Merge pull request #1002 from frappe/mergify/bp/main-hotfix/pr-984 2025-07-02 16:46:10 +05:30
Shariq Ansari
b50c2e6d00
chore: resolved conflict 2025-07-02 16:35:51 +05:30
Shariq Ansari
d0d67bf2ad fix: update default probability from deal status
(cherry picked from commit c96e5ff6c58ca991aca8f705114317e96beb5d42)
2025-07-02 10:34:38 +00:00
Shariq Ansari
5f459f58cb fix: allow creating lost reason from lost reason modal field
(cherry picked from commit 144470877d943802e3fb3439fdfc6b8c1abb8359)
2025-07-02 10:34:38 +00:00
Shariq Ansari
e4abb0f9de fix: intercept data tab's before save and side panel's before field change to show lost reason modal
(cherry picked from commit 391844512a1e5955c866f77c7fde01cc40129c19)
2025-07-02 10:34:37 +00:00
Shariq Ansari
a7bc3abcdd fix: show lost reason modal if status changed to lost
(cherry picked from commit d89c304b134a7ec1f7a16bc667f2ee13858daac9)

# Conflicts:
#	frontend/components.d.ts
2025-07-02 10:34:37 +00:00
Shariq Ansari
9b315c2e0c refactor: statusOptions code
(cherry picked from commit 881126c7f1145fb2db1143b63c1e0f2f81ebb2ea)
2025-07-02 10:34:36 +00:00
Shariq Ansari
6647a83485 fix: renamed other_lost_reason to lost_notes
(cherry picked from commit 5bbec00803e299c3d997bd5d3335ef2a4ab78028)
2025-07-02 10:34:36 +00:00
Shariq Ansari
040692c13c fix: removed unused triggerOnChange
(cherry picked from commit 7730e46cfc2c0886c9bb1237d1558c31a05be712)
2025-07-02 10:34:36 +00:00
Shariq Ansari
e0cdeea2f9 fix: made lost notes as text and non mandatory if lost reason is not Other
(cherry picked from commit 97b2253e9d464e5a25dd1de8ffadd9d513cb3fda)
2025-07-02 10:34:35 +00:00
Shariq Ansari
6aa4a03b0f chore: resolved conflict
(cherry picked from commit 92d728072843b1449cb2e2e626cde7a218e68530)
2025-07-02 10:34:35 +00:00
Shariq Ansari
252fe05edc feat: created lost reason doctype
(cherry picked from commit 5d01b88a1e949f8388d8ca9f3e6ef62fe30a977a)
2025-07-02 10:34:35 +00:00
Shariq Ansari
b027ff0e73
Merge pull request #999 from frappe/mergify/bp/main-hotfix/pr-998
fix: show absolute day count not in decimals (backport #998)
2025-07-01 19:24:56 +05:30
Shariq Ansari
59e762d658 fix: show absolute day count not in decimels
(cherry picked from commit a7dc5e05b3b5dff845b8c5cf32b3dc540e85e9ad)
2025-07-01 13:54:13 +00:00
Shariq Ansari
5e0bc3c448
Merge pull request #995 from frappe/mergify/bp/main-hotfix/pr-994
fix: Forecasting fixes (backport #994)
2025-07-01 16:55:57 +05:30
Shariq Ansari
4cfe106144 fix: show forcasted sales section in sidepanel if forecasting is enabled
(cherry picked from commit 485360f29194a95749b1a6fd27108bec03b37b50)
2025-07-01 11:20:53 +00:00
Shariq Ansari
b1ea3edceb fix: add mandatory fields in convert to deal modal if not added
(cherry picked from commit 17fdbb05cedad890631465d1ad64fbc502dd00c9)
2025-07-01 11:20:53 +00:00
Shariq Ansari
57fb8b3abe fix: show error message on convert to deal modal
(cherry picked from commit adc22efcb1e20eda3c0c3b897e5c5456ccf67b98)
2025-07-01 11:20:52 +00:00
Shariq Ansari
08243530e7 fix: mandatory error
(cherry picked from commit 4c70b1a06bff81aac6baacffe34d624c7e3c4b86)
2025-07-01 11:20:52 +00:00
Shariq Ansari
47002deed6 fix: made deal value mandatory if forecasting is enabled
(cherry picked from commit 4f58aa110a39b431e58d1fd86c2dfe8e41d0034c)
2025-07-01 11:20:52 +00:00
Shariq Ansari
e3510b0e9c fix: added default probability to Lost status
(cherry picked from commit 4d3fe722e86a1e91e056418a173ad30f1a1b6c63)
2025-07-01 11:20:52 +00:00
Shariq Ansari
2cd08bebb9 refactor: moved convert to deal modal into separate component
(cherry picked from commit 6320e580ae556df683d50b5145e39039968ad9ad)
2025-07-01 11:20:51 +00:00
Shariq Ansari
336ac2ad34 fix: prettyDate is not accurate
(cherry picked from commit 611f4cde70d7d4d14f823b1875c57bc75fa66c0f)
2025-07-01 11:20:51 +00:00
Shariq Ansari
29132f6f23 fix: add default probabilities in deal status
(cherry picked from commit 6d3268a61ecd96710f2c7d1cede33a5cc6f939d6)
2025-07-01 11:20:51 +00:00
Frappe PR Bot
a8f3f0703c chore(release): Bumped to Version 1.49.1 2025-07-01 06:25:04 +00:00
Shariq Ansari
ba81ab772e
Merge pull request #993 from frappe/mergify/bp/main/pr-991
fix: show edit call log button in call log details modal (backport #991)
2025-07-01 11:54:14 +05:30
Shariq Ansari
76b5a2d7bb
Merge pull request #992 from frappe/mergify/bp/main-hotfix/pr-991
fix: show edit call log button in call log details modal (backport #991)
2025-07-01 11:53:47 +05:30
Shariq Ansari
c8c7a95ac0 fix: show edit call log button in call log details modal
(cherry picked from commit 693c0869302de05ae2b956542e51caf5ce732b57)
2025-07-01 06:23:08 +00:00
205 changed files with 127305 additions and 19124 deletions

1
.gitignore vendored
View File

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

View File

@ -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

View File

@ -1,4 +1,4 @@
__version__ = "1.49.0"
__version__ = "1.53.1"
__title__ = "Frappe CRM"

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,24 +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.get_doc("Contact", name)
contact.check_permission("read")
contact = contact.as_dict()
if not len(contact):
frappe.throw(_("Contact not found"), frappe.DoesNotExistError)
return contact
frappe.db.set_value(
"CRM Deal",
linked_deal.parent,
{
"email": doc.email_id,
"mobile_no": doc.mobile_no,
},
)
@frappe.whitelist()

1142
crm/api/dashboard.py Normal file

File diff suppressed because it is too large Load Diff

View File

@ -662,7 +662,7 @@ def get_fields_meta(doctype, restricted_fieldtypes=None, as_array=False, only_re
@frappe.whitelist()
def remove_assignments(doctype, name, assignees, ignore_permissions=False):
assignees = json.loads(assignees)
assignees = frappe.parse_json(assignees)
if not assignees:
return
@ -750,7 +750,11 @@ def getCounts(d, doctype):
@frappe.whitelist()
def get_linked_docs_of_document(doctype, docname):
doc = frappe.get_doc(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)
@ -759,7 +763,14 @@ def get_linked_docs_of_document(doctype, docname):
docs_data = []
for doc in linked_docs:
data = frappe.get_doc(doc["reference_doctype"], doc["reference_docname"])
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')}"
@ -767,6 +778,9 @@ def get_linked_docs_of_document(doctype, docname):
if data.doctype == "CRM Deal":
title = data.get("organization")
if data.doctype == "CRM Notification":
title = data.get("message")
docs_data.append(
{
"doc": data.doctype,
@ -779,25 +793,51 @@ def get_linked_docs_of_document(doctype, docname):
def remove_doc_link(doctype, docname):
linked_doc_data = frappe.get_doc(doctype, docname)
linked_doc_data.update(
{
"reference_doctype": None,
"reference_docname": None,
}
)
linked_doc_data.save(ignore_permissions=True)
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):
linked_doc_data = frappe.get_doc(doctype, docname)
linked_doc_data.update(
{
"contact": None,
"contacts": [],
}
)
linked_doc_data.save(ignore_permissions=True)
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()
@ -806,13 +846,19 @@ def remove_linked_doc_reference(items, remove_contact=None, delete=False):
items = frappe.parse_json(items)
for item in items:
if remove_contact:
remove_contact_link(item["doctype"], item["docname"])
else:
remove_doc_link(item["doctype"], item["docname"])
if not item.get("doctype") or not item.get("docname"):
continue
if delete:
frappe.delete_doc(item["doctype"], item["docname"])
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"
@ -821,19 +867,40 @@ def remove_linked_doc_reference(items, remove_contact=None, delete=False):
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:
linked_docs = get_linked_docs_of_document(doctype, doc)
for linked_doc in linked_docs:
remove_linked_doc_reference(
[
{
"doctype": linked_doc["reference_doctype"],
"docname": linked_doc["reference_docname"],
}
],
remove_contact=doctype == "Contact",
delete=delete_linked,
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:

View File

@ -23,9 +23,6 @@ def get_users():
if frappe.session.user == user.name:
user.session_user = True
user.is_manager = "Sales Manager" in frappe.get_roles(user.name)
user.is_admin = user.name == "Administrator"
user.roles = frappe.get_roles(user.name)
user.role = ""
@ -42,7 +39,7 @@ def get_users():
if frappe.session.user == user.name:
user.session_user = True
user.is_agent = frappe.db.exists("CRM Telephony Agent", {"user": user.name})
user.is_telephony_agent = frappe.db.exists("CRM Telephony Agent", {"user": user.name})
crm_users = []

View File

@ -1,90 +1,79 @@
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
):
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:
frappe.db.set_value(
doc.reference_type, doc.reference_name, fieldname, 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"
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, update_modified=False
)
if (
doc.reference_type in ["CRM Lead", "CRM Deal", "CRM Task"]
and doc.reference_name
and doc.allocated_to
):
notify_assigned_user(doc)
if doc.reference_type in ["CRM Lead", "CRM Deal", "CRM Task"] and doc.reference_name and doc.allocated_to:
notify_assigned_user(doc)
def on_update(doc, method):
if (
doc.has_value_changed("status")
and doc.status == "Cancelled"
and doc.reference_type in ["CRM Lead", "CRM Deal", "CRM Task"]
and doc.reference_name
and doc.allocated_to
):
notify_assigned_user(doc, is_cancelled=True)
if (
doc.has_value_changed("status")
and doc.status == "Cancelled"
and doc.reference_type in ["CRM Lead", "CRM Deal", "CRM Task"]
and doc.reference_name
and doc.allocated_to
):
notify_assigned_user(doc, is_cancelled=True)
def notify_assigned_user(doc, is_cancelled=False):
_doc = frappe.get_doc(doc.reference_type, doc.reference_name)
owner = frappe.get_cached_value("User", frappe.session.user, "full_name")
notification_text = get_notification_text(owner, doc, _doc, is_cancelled)
_doc = frappe.get_doc(doc.reference_type, doc.reference_name)
owner = frappe.get_cached_value("User", frappe.session.user, "full_name")
notification_text = get_notification_text(owner, doc, _doc, is_cancelled)
message = (
_("Your assignment on {0} {1} has been removed by {2}").format(
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
)
)
message = (
_("Your assignment on {0} {1} has been removed by {2}").format(
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)
)
redirect_to_doctype, redirect_to_name = get_redirect_to_doc(doc)
redirect_to_doctype, redirect_to_name = get_redirect_to_doc(doc)
notify_user(
{
"owner": frappe.session.user,
"assigned_to": doc.allocated_to,
"notification_type": "Assignment",
"message": message,
"notification_text": notification_text,
"reference_doctype": doc.reference_type,
"reference_docname": doc.reference_name,
"redirect_to_doctype": redirect_to_doctype,
"redirect_to_docname": redirect_to_name,
}
)
notify_user(
{
"owner": frappe.session.user,
"assigned_to": doc.allocated_to,
"notification_type": "Assignment",
"message": message,
"notification_text": notification_text,
"reference_doctype": doc.reference_type,
"reference_docname": doc.reference_name,
"redirect_to_doctype": redirect_to_doctype,
"redirect_to_docname": redirect_to_name,
}
)
def get_notification_text(owner, doc, reference_doc, is_cancelled=False):
name = doc.reference_name
doctype = doc.reference_type
name = doc.reference_name
doctype = doc.reference_type
if doctype.startswith("CRM "):
doctype = doctype[4:].lower()
if doctype.startswith("CRM "):
doctype = doctype[4:].lower()
if doctype in ["lead", "deal"]:
name = (
reference_doc.lead_name or name
if doctype == "lead"
else reference_doc.organization or reference_doc.lead_name or name
)
if doctype in ["lead", "deal"]:
name = (
reference_doc.lead_name or name
if doctype == "lead"
else reference_doc.organization or reference_doc.lead_name or name
)
if is_cancelled:
return f"""
if is_cancelled:
return f"""
<div class="mb-2 leading-5 text-ink-gray-5">
<span>{ _('Your assignment on {0} {1} has been removed by {2}').format(
doctype,
@ -94,7 +83,7 @@ def get_notification_text(owner, doc, reference_doc, is_cancelled=False):
</div>
"""
return f"""
return f"""
<div class="mb-2 leading-5 text-ink-gray-5">
<span class="font-medium text-ink-gray-9">{ owner }</span>
<span>{ _('assigned a {0} {1} to you').format(
@ -104,9 +93,9 @@ def get_notification_text(owner, doc, reference_doc, is_cancelled=False):
</div>
"""
if doctype == "task":
if is_cancelled:
return f"""
if doctype == "task":
if is_cancelled:
return f"""
<div class="mb-2 leading-5 text-ink-gray-5">
<span>{ _('Your assignment on task {0} has been removed by {1}').format(
f'<span class="font-medium text-ink-gray-9">{ reference_doc.title }</span>',
@ -114,7 +103,7 @@ def get_notification_text(owner, doc, reference_doc, is_cancelled=False):
) }</span>
</div>
"""
return f"""
return f"""
<div class="mb-2 leading-5 text-ink-gray-5">
<span class="font-medium text-ink-gray-9">{ owner }</span>
<span>{ _('assigned a new task {0} to you').format(
@ -125,8 +114,8 @@ def get_notification_text(owner, doc, reference_doc, is_cancelled=False):
def get_redirect_to_doc(doc):
if doc.reference_type == "CRM Task":
reference_doc = frappe.get_doc(doc.reference_type, doc.reference_name)
return reference_doc.reference_doctype, reference_doc.reference_docname
if doc.reference_type == "CRM Task":
reference_doc = frappe.get_doc(doc.reference_type, doc.reference_name)
return reference_doc.reference_doctype, reference_doc.reference_docname
return doc.reference_type, doc.reference_name
return doc.reference_type, doc.reference_name

View File

@ -10,8 +10,15 @@ 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"))
doc.reference_doctype = doctype
doc.reference_name = name
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
def on_update(doc, method):
@ -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">

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,20 +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)
deal.check_permission("read")
deal = deal.as_dict()
deal["fields_meta"] = get_fields_meta("CRM Deal")
deal["_form_script"] = get_form_script("CRM Deal")
return deal
@frappe.whitelist()
def get_deal_contacts(name):
@ -32,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

@ -14,11 +14,15 @@
"column_break_ijan",
"status",
"deal_owner",
"lost_reason",
"lost_notes",
"section_break_jgpm",
"probability",
"expected_deal_value",
"deal_value",
"column_break_kpxa",
"close_date",
"expected_closure_date",
"closed_date",
"contacts_tab",
"contacts",
"contact",
@ -35,6 +39,7 @@
"column_break_xbyf",
"territory",
"currency",
"exchange_rate",
"annual_revenue",
"industry",
"person_section",
@ -91,11 +96,6 @@
"fieldtype": "Data",
"label": "Website"
},
{
"fieldname": "close_date",
"fieldtype": "Date",
"label": "Close Date"
},
{
"fieldname": "next_step",
"fieldtype": "Data",
@ -128,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"
},
{
@ -248,7 +248,7 @@
{
"fieldname": "phone",
"fieldtype": "Data",
"label": "Phone",
"label": "Primary Phone",
"options": "Phone"
},
{
@ -391,12 +391,48 @@
{
"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": "2025-06-16 11:42:49.413483",
"modified": "2025-08-26 12:12:56.324245",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Deal",

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,7 +23,11 @@ class CRMDeal(Document):
self.assign_agent(self.deal_owner)
if self.has_value_changed("status"):
add_status_change_log(self)
self.update_close_date()
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:
@ -134,12 +137,59 @@ class CRMDeal(Document):
if sla:
sla.apply(self)
def update_close_date(self):
def update_closed_date(self):
"""
Update the close date based on the "Won" status.
Update the closed date based on the "Won" status.
"""
if self.status == "Won" and not self.close_date:
self.close_date = frappe.utils.nowdate()
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():

View File

@ -7,9 +7,11 @@
"engine": "InnoDB",
"field_order": [
"deal_status",
"color",
"type",
"position",
"probability"
"column_break_ojiu",
"probability",
"color"
],
"fields": [
{
@ -37,13 +39,26 @@
{
"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": "2025-06-11 13:00:34.518808",
"modified": "2025-07-11 16:03:28.077955",
"modified_by": "Administrator",
"module": "FCRM",
"name": "CRM Deal Status",

View File

@ -47,6 +47,13 @@ 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"):
@ -60,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 []
@ -83,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 []:
@ -100,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

@ -1,16 +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)
lead.check_permission("read")
lead = lead.as_dict()
lead["fields_meta"] = get_fields_meta("CRM Lead")
lead["_form_script"] = get_form_script("CRM Lead")
return lead

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,7 +81,8 @@
}
],
"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,7 +118,8 @@
"write": 1
}
],
"row_format": "Dynamic",
"sort_field": "modified",
"sort_order": "DESC",
"states": []
}
}

View File

@ -4,51 +4,65 @@
import frappe
from frappe.model.document import Document
from crm.fcrm.doctype.fcrm_settings.fcrm_settings import get_exchange_rate
class CRMOrganization(Document):
@staticmethod
def default_list_data():
columns = [
{
'label': 'Organization',
'type': 'Data',
'key': 'organization_name',
'width': '16rem',
},
{
'label': 'Website',
'type': 'Data',
'key': 'website',
'width': '14rem',
},
{
'label': 'Industry',
'type': 'Link',
'key': 'industry',
'options': 'CRM Industry',
'width': '14rem',
},
{
'label': 'Annual Revenue',
'type': 'Currency',
'key': 'annual_revenue',
'width': '14rem',
},
{
'label': 'Last Modified',
'type': 'Datetime',
'key': 'modified',
'width': '8rem',
},
]
rows = [
"name",
"organization_name",
"organization_logo",
"website",
"industry",
"currency",
"annual_revenue",
"modified",
]
return {'columns': columns, 'rows': rows}
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": "Website",
"type": "Data",
"key": "website",
"width": "14rem",
},
{
"label": "Industry",
"type": "Link",
"key": "industry",
"options": "CRM Industry",
"width": "14rem",
},
{
"label": "Annual Revenue",
"type": "Currency",
"key": "annual_revenue",
"width": "14rem",
},
{
"label": "Last Modified",
"type": "Datetime",
"key": "modified",
"width": "8rem",
},
]
rows = [
"name",
"organization_name",
"organization_logo",
"website",
"industry",
"currency",
"annual_revenue",
"modified",
]
return {"columns": columns, "rows": rows}

View File

@ -13,6 +13,8 @@
"column_break_mwmz",
"duration",
"last_status_change_log",
"from_type",
"to_type",
"log_owner"
],
"fields": [
@ -61,18 +63,31 @@
"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", {
"from": previous_status,
"to": "",
"from_date": now_minus_one_minute,
"to_date": "",
"log_owner": frappe.session.user,
})
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", {
"from": doc.status,
"to": "",
"from_date": datetime.now(),
"to_date": "",
"log_owner": frappe.session.user,
})
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,8 +151,9 @@
"write": 1
}
],
"row_format": "Dynamic",
"sort_field": "modified",
"sort_order": "DESC",
"states": [],
"track_changes": 1
}
}

View File

@ -128,14 +128,35 @@ 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):

View File

@ -8,6 +8,13 @@
"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",
@ -60,16 +67,58 @@
},
{
"default": "0",
"description": "It will make deal's \"Expected Closure Date\" mandatory to get accurate forecasting insights",
"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-06-11 19:12:16.762499",
"modified": "2025-09-16 17:33:26.406549",
"modified_by": "Administrator",
"module": "FCRM",
"name": "FCRM Settings",

View File

@ -2,6 +2,7 @@
# 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
@ -17,6 +18,7 @@ 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"):
@ -37,16 +39,38 @@ class FCRMSettings(Document):
delete_property_setter(
"CRM Deal",
"reqd",
"close_date",
"expected_closure_date",
)
delete_property_setter(
"CRM Deal",
"reqd",
"expected_deal_value",
)
else:
make_property_setter(
"CRM Deal",
"close_date",
"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():
@ -109,3 +133,76 @@ def get_forecasting_script():
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

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

View File

@ -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)

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

6392
crm/locale/cs.po Normal file

File diff suppressed because it is too large Load Diff

6392
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

6392
crm/locale/id.po Normal file

File diff suppressed because it is too large Load Diff

6392
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

6392
crm/locale/nb.po Normal file

File diff suppressed because it is too large Load Diff

6392
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

6392
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

6392
crm/locale/sr.po Normal file

File diff suppressed because it is too large Load Diff

6392
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

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

6392
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,4 +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.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,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)

View File

@ -1,10 +1,14 @@
from frappe import frappe
import functools
import frappe
import phonenumbers
import requests
from frappe import _
from frappe.model.docstatus import DocStatus
from frappe.model.dynamic_links import get_dynamic_link_map
from frappe.utils import floor
from phonenumbers import NumberParseException
from phonenumbers import PhoneNumberFormat as PNF
from frappe.model.docstatus import DocStatus
from frappe.model.dynamic_links import get_dynamic_link_map
def parse_phone_number(phone_number, default_country="IN"):
@ -97,6 +101,7 @@ def seconds_to_duration(seconds):
else:
return "0s"
# Extracted from frappe core frappe/model/delete_doc.py/check_if_doc_is_linked
def get_linked_docs(doc, method="Delete"):
from frappe.model.rename_doc import get_link_fields
@ -161,6 +166,7 @@ def get_linked_docs(doc, method="Delete"):
)
return docs
# Extracted from frappe core frappe/model/delete_doc.py/check_if_doc_is_dynamically_linked
def get_dynamic_linked_docs(doc, method="Delete"):
docs = []
@ -222,3 +228,42 @@ def get_dynamic_linked_docs(doc, method="Delete"):
}
)
return docs
def is_admin(user: str | None = None) -> bool:
"""
Check whether `user` is an admin
:param user: User to check against, defaults to current user
:return: Whether `user` is an admin
"""
user = user or frappe.session.user
return user == "Administrator"
def is_sales_user(user: str | None = None) -> bool:
"""
Check whether `user` is an agent
:param user: User to check against, defaults to current user
:return: Whether `user` is an agent
"""
user = user or frappe.session.user
return is_admin() or "Sales Manager" in frappe.get_roles(user) or "Sales User" in frappe.get_roles(user)
def sales_user_only(fn):
"""Decorator to validate if user is an agent."""
@functools.wraps(fn)
def wrapper(*args, **kwargs):
if not is_sales_user():
frappe.throw(
msg=_("You are not permitted to access this resource."),
title=_("Not Allowed"),
exc=frappe.PermissionError,
)
return fn(*args, **kwargs)
return wrapper

View File

@ -1,3 +1,8 @@
files:
- source: /crm/locale/main.pot
translation: /crm/locale/%two_letters_code%.po
pull_request_title: "chore: sync translations from crowdin"
pull_request_labels:
- translation
commit_message: "chore: %language% translations"
append_commit_message: false

View File

@ -8,21 +8,21 @@ else
echo "Creating new bench..."
fi
bench init --skip-redis-config-generation frappe-bench
bench init --skip-redis-config-generation frappe-bench --version version-15
cd frappe-bench
# Use containers instead of localhost
bench set-mariadb-host mariadb
bench set-redis-cache-host redis:6379
bench set-redis-queue-host redis:6379
bench set-redis-socketio-host redis:6379
bench set-redis-cache-host redis://redis:6379
bench set-redis-queue-host redis://redis:6379
bench set-redis-socketio-host redis://redis:6379
# Remove redis, watch from Procfile
sed -i '/redis/d' ./Procfile
sed -i '/watch/d' ./Procfile
bench get-app crm --branch develop
bench get-app crm --branch main
bench new-site crm.localhost \
--force \
@ -32,8 +32,9 @@ bench new-site crm.localhost \
bench --site crm.localhost install-app crm
bench --site crm.localhost set-config developer_mode 1
bench --site crm.localhost clear-cache
bench --site crm.localhost set-config mute_emails 1
bench --site crm.localhost set-config server_script_enabled 1
bench --site crm.localhost clear-cache
bench use crm.localhost
bench start

@ -1 +1 @@
Subproject commit 424288f77af4779dd3bb71dc3d278fc627f95179
Subproject commit c9a0fc937cc897864857271b3708a0c675379015

3
frontend/.gitignore vendored
View File

@ -2,4 +2,5 @@ node_modules
.DS_Store
dist
dist-ssr
*.local
*.local
components.d.ts

10
frontend/auto-imports.d.ts vendored Normal file
View File

@ -0,0 +1,10 @@
/* eslint-disable */
/* prettier-ignore */
// @ts-nocheck
// noinspection JSUnusedGlobalSymbols
// Generated by unplugin-auto-import
// biome-ignore lint: disable
export {}
declare global {
}

View File

@ -12,6 +12,7 @@ declare module 'vue' {
Activities: typeof import('./src/components/Activities/Activities.vue')['default']
ActivityHeader: typeof import('./src/components/Activities/ActivityHeader.vue')['default']
ActivityIcon: typeof import('./src/components/Icons/ActivityIcon.vue')['default']
AddChartModal: typeof import('./src/components/Dashboard/AddChartModal.vue')['default']
AddExistingUserModal: typeof import('./src/components/Modals/AddExistingUserModal.vue')['default']
AddressIcon: typeof import('./src/components/Icons/AddressIcon.vue')['default']
AddressModal: typeof import('./src/components/Modals/AddressModal.vue')['default']
@ -24,6 +25,7 @@ declare module 'vue' {
AscendingIcon: typeof import('./src/components/Icons/AscendingIcon.vue')['default']
AssignmentModal: typeof import('./src/components/Modals/AssignmentModal.vue')['default']
AssignTo: typeof import('./src/components/AssignTo.vue')['default']
AssignToBody: typeof import('./src/components/AssignToBody.vue')['default']
AttachmentArea: typeof import('./src/components/Activities/AttachmentArea.vue')['default']
AttachmentIcon: typeof import('./src/components/Icons/AttachmentIcon.vue')['default']
AttachmentItem: typeof import('./src/components/AttachmentItem.vue')['default']
@ -31,6 +33,7 @@ declare module 'vue' {
Autocomplete: typeof import('./src/components/frappe-ui/Autocomplete.vue')['default']
AvatarIcon: typeof import('./src/components/Icons/AvatarIcon.vue')['default']
BrandLogo: typeof import('./src/components/BrandLogo.vue')['default']
BrandSettings: typeof import('./src/components/Settings/BrandSettings.vue')['default']
BulkDeleteLinkedDocModal: typeof import('./src/components/BulkDeleteLinkedDocModal.vue')['default']
CalendarIcon: typeof import('./src/components/Icons/CalendarIcon.vue')['default']
CallArea: typeof import('./src/components/Activities/CallArea.vue')['default']
@ -56,11 +59,15 @@ declare module 'vue' {
ContactsIcon: typeof import('./src/components/Icons/ContactsIcon.vue')['default']
ContactsListView: typeof import('./src/components/ListViews/ContactsListView.vue')['default']
ConvertIcon: typeof import('./src/components/Icons/ConvertIcon.vue')['default']
ConvertToDealModal: typeof import('./src/components/Modals/ConvertToDealModal.vue')['default']
CountUpTimer: typeof import('./src/components/CountUpTimer.vue')['default']
CreateDocumentModal: typeof import('./src/components/Modals/CreateDocumentModal.vue')['default']
CRMLogo: typeof import('./src/components/Icons/CRMLogo.vue')['default']
CurrencySettings: typeof import('./src/components/Settings/CurrencySettings.vue')['default']
CustomActions: typeof import('./src/components/CustomActions.vue')['default']
DashboardGrid: typeof import('./src/components/Dashboard/DashboardGrid.vue')['default']
DashboardIcon: typeof import('./src/components/Icons/DashboardIcon.vue')['default']
DashboardItem: typeof import('./src/components/Dashboard/DashboardItem.vue')['default']
DataFields: typeof import('./src/components/Activities/DataFields.vue')['default']
DataFieldsModal: typeof import('./src/components/Modals/DataFieldsModal.vue')['default']
DealModal: typeof import('./src/components/Modals/DealModal.vue')['default']
@ -78,7 +85,6 @@ declare module 'vue' {
DragIcon: typeof import('./src/components/Icons/DragIcon.vue')['default']
DragVerticalIcon: typeof import('./src/components/Icons/DragVerticalIcon.vue')['default']
Dropdown: typeof import('./src/components/frappe-ui/Dropdown.vue')['default']
DropdownItem: typeof import('./src/components/DropdownItem.vue')['default']
DuplicateIcon: typeof import('./src/components/Icons/DuplicateIcon.vue')['default']
DurationIcon: typeof import('./src/components/Icons/DurationIcon.vue')['default']
EditEmailTemplate: typeof import('./src/components/Settings/EmailTemplate/EditEmailTemplate.vue')['default']
@ -97,11 +103,9 @@ declare module 'vue' {
EmailIcon: typeof import('./src/components/Icons/EmailIcon.vue')['default']
EmailProviderIcon: typeof import('./src/components/Settings/EmailProviderIcon.vue')['default']
EmailTemplateIcon: typeof import('./src/components/Icons/EmailTemplateIcon.vue')['default']
EmailTemplateModal: typeof import('./src/components/Modals/EmailTemplateModal.vue')['default']
EmailTemplatePage: typeof import('./src/components/Settings/EmailTemplate/EmailTemplatePage.vue')['default']
EmailTemplates: typeof import('./src/components/Settings/EmailTemplate/EmailTemplates.vue')['default']
EmailTemplateSelectorModal: typeof import('./src/components/Modals/EmailTemplateSelectorModal.vue')['default']
EmailTemplatesListView: typeof import('./src/components/ListViews/EmailTemplatesListView.vue')['default']
ERPNextIcon: typeof import('./src/components/Icons/ERPNextIcon.vue')['default']
ERPNextSettings: typeof import('./src/components/Settings/ERPNextSettings.vue')['default']
ErrorPage: typeof import('./src/components/ErrorPage.vue')['default']
@ -123,10 +127,10 @@ declare module 'vue' {
FileVideoIcon: typeof import('./src/components/Icons/FileVideoIcon.vue')['default']
Filter: typeof import('./src/components/Filter.vue')['default']
FilterIcon: typeof import('./src/components/Icons/FilterIcon.vue')['default']
ForecastingSettings: typeof import('./src/components/Settings/ForecastingSettings.vue')['default']
FormattedInput: typeof import('./src/components/Controls/FormattedInput.vue')['default']
FrappeCloudIcon: typeof import('./src/components/Icons/FrappeCloudIcon.vue')['default']
GenderIcon: typeof import('./src/components/Icons/GenderIcon.vue')['default']
GeneralSettings: typeof import('./src/components/Settings/GeneralSettings.vue')['default']
GlobalModals: typeof import('./src/components/Modals/GlobalModals.vue')['default']
GoogleIcon: typeof import('./src/components/Icons/GoogleIcon.vue')['default']
Grid: typeof import('./src/components/Controls/Grid.vue')['default']
@ -137,6 +141,7 @@ declare module 'vue' {
GroupByIcon: typeof import('./src/components/Icons/GroupByIcon.vue')['default']
HeartIcon: typeof import('./src/components/Icons/HeartIcon.vue')['default']
HelpIcon: typeof import('./src/components/Icons/HelpIcon.vue')['default']
HomeActions: typeof import('./src/components/Settings/HomeActions.vue')['default']
Icon: typeof import('./src/components/Icon.vue')['default']
IconPicker: typeof import('./src/components/IconPicker.vue')['default']
ImageUploader: typeof import('./src/components/Controls/ImageUploader.vue')['default']
@ -161,12 +166,8 @@ declare module 'vue' {
ListIcon: typeof import('./src/components/Icons/ListIcon.vue')['default']
ListRows: typeof import('./src/components/ListViews/ListRows.vue')['default']
LoadingIndicator: typeof import('./src/components/Icons/LoadingIndicator.vue')['default']
LostReasonModal: typeof import('./src/components/Modals/LostReasonModal.vue')['default']
LucideCalendar: typeof import('~icons/lucide/calendar')['default']
LucideInfo: typeof import('~icons/lucide/info')['default']
LucideMoreHorizontal: typeof import('~icons/lucide/more-horizontal')['default']
LucidePlus: typeof import('~icons/lucide/plus')['default']
LucideSearch: typeof import('~icons/lucide/search')['default']
LucideX: typeof import('~icons/lucide/x')['default']
MarkAsDoneIcon: typeof import('./src/components/Icons/MarkAsDoneIcon.vue')['default']
MaximizeIcon: typeof import('./src/components/Icons/MaximizeIcon.vue')['default']
MenuIcon: typeof import('./src/components/Icons/MenuIcon.vue')['default']
@ -181,7 +182,6 @@ declare module 'vue' {
MultiSelectEmailInput: typeof import('./src/components/Controls/MultiSelectEmailInput.vue')['default']
MultiSelectUserInput: typeof import('./src/components/Controls/MultiSelectUserInput.vue')['default']
MuteIcon: typeof import('./src/components/Icons/MuteIcon.vue')['default']
NestedPopover: typeof import('./src/components/NestedPopover.vue')['default']
NewEmailTemplate: typeof import('./src/components/Settings/EmailTemplate/NewEmailTemplate.vue')['default']
NoteArea: typeof import('./src/components/Activities/NoteArea.vue')['default']
NoteIcon: typeof import('./src/components/Icons/NoteIcon.vue')['default']
@ -200,7 +200,8 @@ declare module 'vue' {
PlaybackSpeedOption: typeof import('./src/components/Activities/PlaybackSpeedOption.vue')['default']
PlayIcon: typeof import('./src/components/Icons/PlayIcon.vue')['default']
Popover: typeof import('./src/components/frappe-ui/Popover.vue')['default']
ProfileImageEditor: typeof import('./src/components/Settings/ProfileImageEditor.vue')['default']
PrimaryDropdown: typeof import('./src/components/PrimaryDropdown.vue')['default']
PrimaryDropdownItem: typeof import('./src/components/PrimaryDropdownItem.vue')['default']
ProfileSettings: typeof import('./src/components/Settings/ProfileSettings.vue')['default']
QuickEntryModal: typeof import('./src/components/Modals/QuickEntryModal.vue')['default']
QuickFilterField: typeof import('./src/components/QuickFilterField.vue')['default']
@ -227,6 +228,7 @@ declare module 'vue' {
SmileIcon: typeof import('./src/components/Icons/SmileIcon.vue')['default']
SortBy: typeof import('./src/components/SortBy.vue')['default']
SortIcon: typeof import('./src/components/Icons/SortIcon.vue')['default']
SparkleIcon: typeof import('./src/components/Icons/SparkleIcon.vue')['default']
SquareAsterisk: typeof import('./src/components/Icons/SquareAsterisk.vue')['default']
StepsIcon: typeof import('./src/components/Icons/StepsIcon.vue')['default']
SuccessIcon: typeof import('./src/components/Icons/SuccessIcon.vue')['default']

View File

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

View File

@ -1,7 +1,7 @@
<template>
<FrappeUIProvider>
<Layout v-if="session().isLoggedIn">
<router-view />
<router-view :key="$route.fullPath"/>
</Layout>
<Dialogs />
</FrappeUIProvider>

View File

@ -50,11 +50,13 @@
class="activity grid grid-cols-[30px_minmax(auto,_1fr)] gap-2 px-3 sm:gap-4 sm:px-10"
>
<div
class="relative flex justify-center after:absolute after:left-[50%] after:top-0 after:-z-10 after:border-l after:border-outline-gray-modals"
:class="i != activities.length - 1 ? 'after:h-full' : 'after:h-4'"
class="z-0 relative flex justify-center before:absolute before:left-[50%] before:-z-[1] before:top-0 before:border-l before:border-outline-gray-modals"
:class="
i != activities.length - 1 ? 'before:h-full' : 'before:h-4'
"
>
<div
class="z-10 flex h-8 w-7 items-center justify-center bg-surface-white"
class="flex h-8 w-7 items-center justify-center bg-surface-white"
>
<CommentIcon class="text-ink-gray-8" />
</div>
@ -72,11 +74,13 @@
class="activity grid grid-cols-[30px_minmax(auto,_1fr)] gap-4 px-3 sm:px-10"
>
<div
class="relative flex justify-center after:absolute after:left-[50%] after:top-0 after:-z-10 after:border-l after:border-outline-gray-modals"
:class="i != activities.length - 1 ? 'after:h-full' : 'after:h-4'"
class="z-0 relative flex justify-center before:absolute before:left-[50%] before:-z-[1] before:top-0 before:border-l before:border-outline-gray-modals"
:class="
i != activities.length - 1 ? 'before:h-full' : 'before:h-4'
"
>
<div
class="z-10 flex h-8 w-7 items-center justify-center bg-surface-white text-ink-gray-8"
class="flex h-8 w-7 items-center justify-center bg-surface-white text-ink-gray-8"
>
<MissedCallIcon
v-if="call.status == 'No Answer'"
@ -116,11 +120,11 @@
>
<div
v-if="['Activity', 'Emails'].includes(title)"
class="relative flex justify-center before:absolute before:left-[50%] before:top-0 before:-z-10 before:border-l before:border-outline-gray-modals"
class="z-0 relative flex justify-center before:absolute before:left-[50%] before:-z-[1] before:top-0 before:border-l before:border-outline-gray-modals"
:class="[i != activities.length - 1 ? 'before:h-full' : 'before:h-4']"
>
<div
class="z-10 flex h-7 w-7 items-center justify-center bg-surface-white"
class="flex h-7 w-7 items-center justify-center bg-surface-white"
:class="{
'mt-2.5': ['communication'].includes(activity.activity_type),
'bg-surface-white': ['added', 'removed', 'changed'].includes(
@ -234,12 +238,9 @@
<Button
class="!size-4"
variant="ghost"
:icon="SelectIcon"
@click="activity.show_others = !activity.show_others"
>
<template #icon>
<SelectIcon />
</template>
</Button>
/>
</div>
<div
v-else
@ -367,7 +368,8 @@
<div v-else-if="title == 'Data'" class="h-full flex flex-col px-3 sm:px-10">
<DataFields
:doctype="doctype"
:docname="doc.data.name"
:docname="docname"
@beforeSave="(data) => emit('beforeSave', data)"
@afterSave="(data) => emit('afterSave', data)"
/>
</div>
@ -437,10 +439,9 @@
:doc="doc"
/>
<FilesUploader
v-if="doc.data?.name"
v-model="showFilesUploader"
:doctype="doctype"
:docname="doc.data.name"
:docname="docname"
@after="
() => {
all_activities.reload()
@ -489,6 +490,7 @@ import { timeAgo, formatDate, startCase } from '@/utils'
import { globalStore } from '@/stores/global'
import { usersStore } from '@/stores/users'
import { whatsappEnabled, callEnabled } from '@/composables/settings'
import { useDocument } from '@/data/document'
import { capture } from '@/telemetry'
import { Button, Tooltip, createResource } from 'frappe-ui'
import { useElementVisibility } from '@vueuse/core'
@ -512,20 +514,27 @@ const props = defineProps({
type: String,
default: 'CRM Lead',
},
docname: {
type: String,
default: '',
},
tabs: {
type: Array,
default: () => [],
},
})
const emit = defineEmits(['afterSave'])
const emit = defineEmits(['beforeSave', 'afterSave'])
const route = useRoute()
const doc = defineModel()
const reload = defineModel('reload')
const tabIndex = defineModel('tabIndex')
const { document: _document } = useDocument(props.doctype, props.docname)
const doc = computed(() => _document.doc || {})
const reload_email = ref(false)
const modalRef = ref(null)
const showFilesUploader = ref(false)
@ -541,24 +550,25 @@ const changeTabTo = (tabName) => {
const all_activities = createResource({
url: 'crm.api.activities.get_activities',
params: { name: doc.value.data.name },
cache: ['activity', doc.value.data.name],
params: { name: props.docname },
cache: ['activity', props.docname],
auto: true,
transform: ([versions, calls, notes, tasks, attachments]) => {
return { versions, calls, notes, tasks, attachments }
},
onSuccess: () => nextTick(() => scroll()),
})
const showWhatsappTemplates = ref(false)
const whatsappMessages = createResource({
url: 'crm.api.whatsapp.get_whatsapp_messages',
cache: ['whatsapp_messages', doc.value.data.name],
cache: ['whatsapp_messages', props.docname],
params: {
reference_doctype: props.doctype,
reference_name: doc.value.data.name,
reference_name: props.docname,
},
auto: true,
auto: whatsappEnabled.value,
transform: (data) => sortByCreation(data),
onSuccess: () => nextTick(() => scroll()),
})
@ -571,7 +581,7 @@ onMounted(() => {
$socket.on('whatsapp_message', (data) => {
if (
data.reference_doctype === props.doctype &&
data.reference_name === doc.value.data.name
data.reference_name === props.docname
) {
whatsappMessages.reload()
}
@ -593,8 +603,8 @@ function sendTemplate(template) {
url: 'crm.api.whatsapp.send_whatsapp_template',
params: {
reference_doctype: props.doctype,
reference_name: doc.value.data.name,
to: doc.value.data.mobile_no,
reference_name: props.docname,
to: doc.value.mobile_no,
template,
},
auto: true,
@ -766,6 +776,7 @@ const whatsappBox = ref(null)
watch([reload, reload_email], ([reload_value, reload_email_value]) => {
if (reload_value || reload_email_value) {
all_activities.reload()
_document.reload()
reload.value = false
reload_email.value = false
}
@ -791,12 +802,12 @@ function scroll(hash) {
const callActions = computed(() => {
let actions = [
{
label: __('Create Call Log'),
label: __('Log a Call'),
onClick: () => modalRef.value.createCallLog(),
},
{
label: __('Make a Call'),
onClick: () => makeCall(doc.data.mobile_no),
onClick: () => makeCall(doc.value.mobile_no),
condition: () => callEnabled.value,
},
]

View File

@ -9,23 +9,17 @@
<Button
v-if="title == 'Emails'"
variant="solid"
:label="__('New Email')"
iconLeft="plus"
@click="emailBox.show = true"
>
<template #prefix>
<FeatherIcon name="plus" class="h-4 w-4" />
</template>
<span>{{ __('New Email') }}</span>
</Button>
/>
<Button
v-else-if="title == 'Comments'"
variant="solid"
:label="__('New Comment')"
iconLeft="plus"
@click="emailBox.showComment = true"
>
<template #prefix>
<FeatherIcon name="plus" class="h-4 w-4" />
</template>
<span>{{ __('New Comment') }}</span>
</Button>
/>
<MultiActionButton
v-else-if="title == 'Calls'"
variant="solid"
@ -34,59 +28,45 @@
<Button
v-else-if="title == 'Notes'"
variant="solid"
:label="__('New Note')"
iconLeft="plus"
@click="modalRef.showNote()"
>
<template #prefix>
<FeatherIcon name="plus" class="h-4 w-4" />
</template>
<span>{{ __('New Note') }}</span>
</Button>
/>
<Button
v-else-if="title == 'Tasks'"
variant="solid"
:label="__('New Task')"
iconLeft="plus"
@click="modalRef.showTask()"
>
<template #prefix>
<FeatherIcon name="plus" class="h-4 w-4" />
</template>
<span>{{ __('New Task') }}</span>
</Button>
/>
<Button
v-else-if="title == 'Attachments'"
variant="solid"
:label="__('Upload Attachment')"
iconLeft="plus"
@click="showFilesUploader = true"
>
<template #prefix>
<FeatherIcon name="plus" class="h-4 w-4" />
</template>
<span>{{ __('Upload Attachment') }}</span>
</Button>
/>
<div class="flex gap-2 shrink-0" v-else-if="title == 'WhatsApp'">
<Button
:label="__('Send Template')"
@click="showWhatsappTemplates = true"
/>
<Button variant="solid" @click="whatsappBox.show()">
<template #prefix>
<FeatherIcon name="plus" class="h-4 w-4" />
</template>
<span>{{ __('New Message') }}</span>
</Button>
<Button
variant="solid"
:label="__('New Message')"
iconLeft="plus"
@click="whatsappBox.show()"
/>
</div>
<Dropdown v-else :options="defaultActions" @click.stop>
<template v-slot="{ open }">
<Button variant="solid" class="flex items-center gap-1">
<template #prefix>
<FeatherIcon name="plus" class="h-4 w-4" />
</template>
<span>{{ __('New') }}</span>
<template #suffix>
<FeatherIcon
:name="open ? 'chevron-up' : 'chevron-down'"
class="h-4 w-4"
/>
</template>
</Button>
<Button
variant="solid"
class="flex items-center gap-1"
:label="__('New')"
iconLeft="plus"
:iconRight="open ? 'chevron-up' : 'chevron-down'"
/>
</template>
</Dropdown>
</div>
@ -134,13 +114,13 @@ const defaultActions = computed(() => {
},
{
icon: h(PhoneIcon, { class: 'h-4 w-4' }),
label: __('Create Call Log'),
label: __('Log a Call'),
onClick: () => props.modalRef.createCallLog(),
},
{
icon: h(PhoneIcon, { class: 'h-4 w-4' }),
label: __('Make a Call'),
onClick: () => makeCall(props.doc.data.mobile_no),
onClick: () => makeCall(props.doc.mobile_no),
condition: () => callEnabled.value,
},
{
@ -177,14 +157,14 @@ function getTabIndex(name) {
const callActions = computed(() => {
let actions = [
{
label: __('Create Call Log'),
label: __('Log a Call'),
icon: 'plus',
onClick: () => props.modalRef.createCallLog(),
},
{
label: __('Make a Call'),
icon: h(PhoneIcon, { class: 'h-4 w-4' }),
onClick: () => makeCall(props.doc.data.mobile_no),
onClick: () => makeCall(props.doc.mobile_no),
condition: () => callEnabled.value,
},
]

View File

@ -4,7 +4,7 @@
v-model:reloadTasks="activities"
:task="task"
:doctype="doctype"
:doc="doc.data?.name"
:doc="doc?.name"
@after="redirect('tasks')"
/>
<NoteModal
@ -12,7 +12,7 @@
v-model:reloadNotes="activities"
:note="note"
:doctype="doctype"
:doc="doc.data?.name"
:doc="doc?.name"
@after="redirect('notes')"
/>
<CallLogModal
@ -92,8 +92,8 @@ const referenceDoc = ref({})
function createCallLog() {
let doctype = props.doctype
let docname = props.doc.data?.name
referenceDoc.value = { ...props.doc.data }
let docname = props.doc?.name
referenceDoc.value = { ...props.doc }
callLog.value = {
reference_doctype: doctype,
reference_docname: docname,

View File

@ -38,35 +38,31 @@
</div>
</Tooltip>
<div class="flex gap-1">
<Tooltip
:text="
<Button
:tooltip="
attachment.is_private ? __('Make public') : __('Make private')
"
class="!size-5"
@click.stop="
togglePrivate(attachment.name, attachment.is_private)
"
>
<div>
<Button
class="!size-5"
@click.stop="
togglePrivate(attachment.name, attachment.is_private)
"
>
<FeatherIcon
:name="attachment.is_private ? 'lock' : 'unlock'"
class="size-3 text-ink-gray-7"
/>
</Button>
</div>
</Tooltip>
<Tooltip :text="__('Delete attachment')">
<div>
<Button
class="!size-5"
@click.stop="() => deleteAttachment(attachment.name)"
>
<FeatherIcon name="trash-2" class="size-3 text-ink-gray-7" />
</Button>
</div>
</Tooltip>
<template #icon>
<FeatherIcon
:name="attachment.is_private ? 'lock' : 'unlock'"
class="size-3 text-ink-gray-7"
/>
</template>
</Button>
<Button
:tooltip="__('Delete attachment')"
class="!size-5"
@click.stop="() => deleteAttachment(attachment.name)"
>
<template #icon>
<FeatherIcon name="trash-2" class="size-3 text-ink-gray-7" />
</template>
</Button>
</div>
</div>
</div>

View File

@ -1,12 +1,12 @@
<template>
<div class="w-full text-sm text-ink-gray-5">
<div class="flex items-center gap-2">
<Button variant="ghost" @click="playPause">
<template #icon>
<PlayIcon v-if="isPaused" class="size-4 text-ink-gray-5" />
<PauseIcon v-else class="size-4 text-ink-gray-5" />
</template>
</Button>
<Button
variant="ghost"
class="text-ink-gray-5"
:icon="isPaused ? PlayIcon : PauseIcon"
@click="playPause"
/>
<div class="flex gap-2 items-center justify-between flex-1">
<input
class="w-full slider !h-[0.5] bg-surface-gray-3 [&::-webkit-slider-thumb]:shadow [&::-webkit-slider-thumb:hover]:outline [&::-webkit-slider-thumb:hover]:outline-[0.5px]"
@ -61,11 +61,11 @@
</Button>
</div>
<Dropdown :options="options">
<Button variant="ghost" @click="showPlaybackSpeed = false">
<template #icon>
<FeatherIcon class="size-4" name="more-horizontal" />
</template>
</Button>
<Button
icon="more-horizontal"
variant="ghost"
@click="showPlaybackSpeed = false"
/>
</Dropdown>
</div>
</div>

View File

@ -1,5 +1,5 @@
<template>
<div @click="showCallLogDetailModal = true" class="cursor-pointer">
<div>
<div class="mb-1 flex items-center justify-stretch gap-2 py-1 text-base">
<div class="inline-flex items-center flex-wrap gap-1 text-ink-gray-5">
<Avatar
@ -25,7 +25,8 @@
</div>
</div>
<div
class="flex flex-col gap-2 border border-outline-gray-modals rounded-md bg-surface-cards px-3 py-2.5 text-ink-gray-9"
@click="showCallLogDetailModal = true"
class="flex flex-col gap-2 border cursor-pointer border-outline-gray-modals rounded-md bg-surface-cards px-3 py-2.5 text-ink-gray-9"
>
<div class="flex items-center justify-between">
<div class="inline-flex gap-2 items-center text-base font-medium">

View File

@ -14,12 +14,10 @@
<div class="flex gap-1">
<Button
v-if="isManager() && !isMobileView"
:tooltip="__('Edit fields layout')"
:icon="EditIcon"
@click="showDataFieldsModal = true"
>
<template #icon>
<EditIcon />
</template>
</Button>
/>
<Button
label="Save"
:disabled="!document.isDirty"
@ -66,7 +64,7 @@ import LoadingIndicator from '@/components/Icons/LoadingIndicator.vue'
import { usersStore } from '@/stores/users'
import { useDocument } from '@/data/document'
import { isMobileView } from '@/composables/settings'
import { ref, watch } from 'vue'
import { ref, watch, getCurrentInstance } from 'vue'
const props = defineProps({
doctype: {
@ -79,10 +77,13 @@ const props = defineProps({
},
})
const emit = defineEmits(['afterSave'])
const emit = defineEmits(['beforeSave', 'afterSave'])
const { isManager } = usersStore()
const instance = getCurrentInstance()
const attrs = instance?.vnode?.props ?? {}
const showDataFieldsModal = ref(false)
const { document } = useDocument(props.doctype, props.docname)
@ -107,9 +108,15 @@ function saveChanges() {
return acc
}, {})
document.save.submit(null, {
onSuccess: () => emit('afterSave', changes),
})
const hasListener = attrs['onBeforeSave'] !== undefined
if (hasListener) {
emit('beforeSave', changes)
} else {
document.save.submit(null, {
onSuccess: () => emit('afterSave', changes),
})
}
}
watch(

View File

@ -2,7 +2,9 @@
<div
class="cursor-pointer flex flex-col rounded-md shadow bg-surface-cards px-3 py-1.5 text-base transition-all duration-300 ease-in-out"
>
<div class="-mb-0.5 flex items-center justify-between gap-2 truncate text-ink-gray-9">
<div
class="-mb-0.5 flex items-center justify-between gap-2 truncate text-ink-gray-9"
>
<div class="flex items-center gap-2 truncate">
<span>{{ activity.data.sender_full_name }}</span>
<span class="sm:flex hidden text-sm text-ink-gray-5">
@ -28,32 +30,20 @@
</div>
</Tooltip>
<div class="flex gap-0.5">
<Tooltip :text="__('Reply')">
<div>
<Button
variant="ghost"
class="text-ink-gray-7"
@click="reply(activity.data)"
>
<template #icon>
<ReplyIcon />
</template>
</Button>
</div>
</Tooltip>
<Tooltip :text="__('Reply All')">
<div>
<Button
variant="ghost"
class="text-ink-gray-7"
@click="reply(activity.data, true)"
>
<template #icon>
<ReplyAllIcon />
</template>
</Button>
</div>
</Tooltip>
<Button
:tooltip="__('Reply')"
variant="ghost"
class="text-ink-gray-7"
:icon="ReplyIcon"
@click="reply(activity.data)"
/>
<Button
:tooltip="__('Reply All')"
variant="ghost"
:icon="ReplyAllIcon"
class="text-ink-gray-7"
@click="reply(activity.data, true)"
/>
</div>
</div>
</div>

View File

@ -41,13 +41,13 @@
:options="taskStatusOptions(modalRef.updateTaskStatus, task)"
@click.stop
>
<Tooltip :text="__('Change Status')">
<div>
<Button variant="ghosted" class="hover:bg-surface-gray-4">
<TaskStatusIcon :status="task.status" />
</Button>
</div>
</Tooltip>
<Button
:tooltip="__('Change status')"
variant="ghosted"
class="hover:bg-surface-gray-4"
>
<TaskStatusIcon :status="task.status" />
</Button>
</Dropdown>
<Dropdown
:options="[

View File

@ -107,9 +107,9 @@ function sendTextMessage(event) {
async function sendWhatsAppMessage() {
let args = {
reference_doctype: props.doctype,
reference_name: doc.value.data.name,
reference_name: doc.value.name,
message: content.value,
to: doc.value.data.mobile_no,
to: doc.value.mobile_no,
attach: whatsapp.value.attach || '',
reply_to: reply.value?.name || '',
content_type: whatsapp.value.content_type,

View File

@ -1,31 +1,99 @@
<template>
<component
v-if="assignees?.length"
:is="assignees?.length == 1 ? 'Button' : 'div'"
>
<MultipleAvatar :avatars="assignees" @click="showAssignmentModal = true" />
</component>
<Button v-else @click="showAssignmentModal = true">
{{ __('Assign to') }}
</Button>
<AssignmentModal
v-if="showAssignmentModal"
v-model="showAssignmentModal"
v-model:assignees="assignees"
:doctype="doctype"
:doc="data"
/>
<Popover placement="bottom-end">
<template #target="{ togglePopover }">
<div class="flex items-center" @click="togglePopover">
<component
v-if="assignees?.length"
:is="assignees?.length == 1 ? 'Button' : 'div'"
>
<MultipleAvatar :avatars="assignees" />
</component>
<Button v-else :label="__('Assign to')" />
</div>
</template>
<template #body="{ isOpen }">
<AssignToBody
v-show="isOpen"
v-model="assignees"
:docname="docname"
:doctype="doctype"
:open="isOpen"
:onUpdate="ownerField && saveAssignees"
/>
</template>
</Popover>
</template>
<script setup>
import MultipleAvatar from '@/components/MultipleAvatar.vue'
import AssignmentModal from '@/components/Modals/AssignmentModal.vue'
import { ref } from 'vue'
import AssignToBody from '@/components/AssignToBody.vue'
import { useDocument } from '@/data/document'
import { toast, Popover } from 'frappe-ui'
import { computed } from 'vue'
const props = defineProps({
data: Object,
doctype: String,
docname: String,
})
const showAssignmentModal = ref(false)
const { document } = useDocument(props.doctype, props.docname)
const assignees = defineModel()
const ownerField = computed(() => {
if (props.doctype === 'CRM Lead') {
return 'lead_owner'
} else if (props.doctype === 'CRM Deal') {
return 'deal_owner'
} else {
return null
}
})
async function saveAssignees(
addedAssignees,
removedAssignees,
addAssignees,
removeAssignees,
) {
removedAssignees.length && (await removeAssignees.submit(removedAssignees))
addedAssignees.length && (await addAssignees.submit(addedAssignees))
const nextAssignee = assignees.value.find(
(a) => a.name !== document.doc[ownerField.value],
)
let owner = ownerField.value.replace('_', ' ')
if (
document.doc[ownerField.value] &&
removedAssignees.includes(document.doc[ownerField.value])
) {
document.doc[ownerField.value] = nextAssignee ? nextAssignee.name : ''
document.save.submit()
if (nextAssignee) {
toast.info(
__(
'Since you removed {0} from the assignee, the {0} has been changed to the next available assignee {1}.',
[owner, nextAssignee.label || nextAssignee.name],
),
)
} else {
toast.info(
__(
'Since you removed {0} from the assignee, the {0} has also been removed.',
[owner],
),
)
}
} else if (!document.doc[ownerField.value] && nextAssignee) {
document.doc[ownerField.value] = nextAssignee ? nextAssignee.name : ''
toast.info(
__('Since you added a new assignee, the {0} has been set to {1}.', [
owner,
nextAssignee.label || nextAssignee.name,
]),
)
}
}
</script>

View File

@ -0,0 +1,211 @@
<template>
<div
class="flex flex-col gap-2 my-2 w-[470px] rounded-lg bg-surface-modal shadow-2xl ring-1 ring-black p-3 ring-opacity-5 focus:outline-none"
>
<div class="text-base text-ink-gray-5">{{ __('Assign to') }}</div>
<Link
class="form-control"
value=""
doctype="User"
@change="(option) => addValue(option) && ($refs.input.value = '')"
:placeholder="__('John Doe')"
:filters="{
name: ['in', users.data.crmUsers?.map((user) => user.name)],
}"
:hideMe="true"
>
<template #target="{ togglePopover }">
<div
class="w-full min-h-12 flex flex-wrap items-center gap-1.5 p-1.5 pb-5 rounded-lg bg-surface-gray-2 cursor-text"
@click.stop="togglePopover"
>
<Tooltip
:text="assignee.name"
v-for="assignee in assignees"
:key="assignee.name"
@click.stop
>
<div
class="flex items-center text-sm p-0.5 text-ink-gray-6 border border-outline-gray-1 bg-surface-modal rounded-full cursor-pointer"
@click.stop
>
<UserAvatar :user="assignee.name" size="sm" />
<div class="ml-1">{{ getUser(assignee.name).full_name }}</div>
<Button
variant="ghost"
class="rounded-full !size-4 m-1"
@click.stop="removeValue(assignee.name)"
>
<template #icon>
<FeatherIcon name="x" class="h-3 w-3 text-ink-gray-6" />
</template>
</Button>
</div>
</Tooltip>
</div>
</template>
<template #item-prefix="{ option }">
<UserAvatar class="mr-2" :user="option.value" size="sm" />
</template>
<template #item-label="{ option }">
<Tooltip :text="option.value">
<div class="cursor-pointer text-ink-gray-9">
{{ getUser(option.value).full_name }}
</div>
</Tooltip>
</template>
</Link>
<div class="flex items-center justify-between gap-2">
<div
class="text-base text-ink-gray-5 cursor-pointer select-none"
@click="assignToMe = !assignToMe"
>
{{ __('Assign to me') }}
</div>
<Switch v-model="assignToMe" @click.stop />
</div>
</div>
</template>
<script setup>
import UserAvatar from '@/components/UserAvatar.vue'
import Link from '@/components/Controls/Link.vue'
import { usersStore } from '@/stores/users'
import { capture } from '@/telemetry'
import { Tooltip, Switch, createResource } from 'frappe-ui'
import { ref, watch } from 'vue'
const props = defineProps({
doctype: {
type: String,
default: '',
},
docname: {
type: Object,
default: null,
},
open: {
type: Boolean,
default: false,
},
onUpdate: {
type: Function,
default: null,
},
})
const emit = defineEmits(['reload'])
const assignees = defineModel()
const oldAssignees = ref([])
const assignToMe = ref(false)
const error = ref('')
const { users, getUser } = usersStore()
const removeValue = (value) => {
if (value === getUser('').name) {
assignToMe.value = false
}
assignees.value = assignees.value.filter(
(assignee) => assignee.name !== value,
)
}
const addValue = (value) => {
if (value === getUser('').name) {
assignToMe.value = true
}
error.value = ''
let obj = {
name: value,
image: getUser(value).user_image,
label: getUser(value).full_name,
}
if (!assignees.value.find((assignee) => assignee.name === value)) {
assignees.value.push(obj)
}
}
watch(assignToMe, (val) => {
let user = getUser('')
if (val) {
addValue(user.name)
} else {
removeValue(user.name)
}
})
watch(
() => props.open,
(val) => {
if (val) {
oldAssignees.value = [...(assignees.value || [])]
assignToMe.value = assignees.value.some(
(assignee) => assignee.name === getUser('').name,
)
} else {
updateAssignees()
}
},
{ immediate: true },
)
async function updateAssignees() {
if (JSON.stringify(oldAssignees.value) === JSON.stringify(assignees.value))
return
const removedAssignees = oldAssignees.value
.filter(
(assignee) => !assignees.value.find((a) => a.name === assignee.name),
)
.map((assignee) => assignee.name)
const addedAssignees = assignees.value
.filter(
(assignee) => !oldAssignees.value.find((a) => a.name === assignee.name),
)
.map((assignee) => assignee.name)
if (props.onUpdate) {
props.onUpdate(
addedAssignees,
removedAssignees,
addAssignees,
removeAssignees,
)
} else {
if (removedAssignees.length) {
await removeAssignees.submit(removedAssignees)
}
if (addedAssignees.length) {
addAssignees.submit(addedAssignees)
}
}
}
const addAssignees = createResource({
url: 'frappe.desk.form.assign_to.add',
makeParams: (addedAssignees) => ({
doctype: props.doctype,
name: props.docname,
assign_to: addedAssignees,
}),
onSuccess: () => {
capture('assign_to', { doctype: props.doctype })
},
})
const removeAssignees = createResource({
url: 'crm.api.doc.remove_assignments',
makeParams: (removedAssignees) => ({
doctype: props.doctype,
name: props.docname,
assignees: removedAssignees,
}),
})
</script>

View File

@ -5,11 +5,9 @@
:label="label"
theme="gray"
variant="outline"
:iconLeft="getIcon()"
@click="toggleDialog()"
>
<template #prefix>
<component :is="getIcon()" class="h-4 w-4" />
</template>
<template #suffix>
<slot name="suffix" />
</template>

View File

@ -13,7 +13,7 @@
</div>
</div>
<div>
<div class="text-ink-gray-5">
<div class="text-ink-gray-5 text-base">
{{
__('Are you sure you want to delete {0} items?', [
props.items?.length,
@ -53,7 +53,7 @@
</div>
</div>
<div>
<div class="text-ink-gray-5">
<div class="text-ink-gray-5 text-base">
{{
confirmDeleteInfo.delete
? __(

View File

@ -1,7 +1,7 @@
<template>
<NestedPopover>
<template #target>
<Button :label="__('Columns')">
<Popover placement="bottom-end">
<template #target="{ togglePopover }">
<Button :label="__('Columns')" @click="togglePopover">
<template v-if="hideLabel">
<ColumnsIcon class="h-4" />
</template>
@ -65,37 +65,28 @@
<Button
class="w-full !justify-start !text-ink-gray-5"
variant="ghost"
@click="togglePopover()"
:label="__('Add Column')"
>
<template #prefix>
<FeatherIcon name="plus" class="h-4" />
</template>
</Button>
iconLeft="plus"
@click="togglePopover"
/>
</template>
</Autocomplete>
<Button
v-if="columnsUpdated"
class="w-full !justify-start !text-ink-gray-5"
variant="ghost"
@click="reset(close)"
:label="__('Reset Changes')"
>
<template #prefix>
<ReloadIcon class="h-4" />
</template>
</Button>
:iconLeft="ReloadIcon"
@click="reset(close)"
/>
<Button
v-if="!is_default"
class="w-full !justify-start !text-ink-gray-5"
variant="ghost"
@click="resetToDefault(close)"
:label="__('Reset to Default')"
>
<template #prefix>
<ReloadIcon class="h-4" />
</template>
</Button>
:iconLeft="ReloadIcon"
@click="resetToDefault(close)"
/>
</div>
</div>
<div v-else>
@ -144,7 +135,7 @@
</div>
</div>
</template>
</NestedPopover>
</Popover>
</template>
<script setup>
@ -152,9 +143,9 @@ import ColumnsIcon from '@/components/Icons/ColumnsIcon.vue'
import EditIcon from '@/components/Icons/EditIcon.vue'
import DragIcon from '@/components/Icons/DragIcon.vue'
import ReloadIcon from '@/components/Icons/ReloadIcon.vue'
import NestedPopover from '@/components/NestedPopover.vue'
import Autocomplete from '@/components/frappe-ui/Autocomplete.vue'
import { isTouchScreenDevice } from '@/utils'
import { Popover } from 'frappe-ui'
import Draggable from 'vuedraggable'
import { computed, ref } from 'vue'
import { watchOnce } from '@vueuse/core'
@ -219,6 +210,7 @@ const fields = computed(() => {
})
function addColumn(c) {
if (!c) return
let align = ['Float', 'Int', 'Percent', 'Currency'].includes(c.type)
? 'right'
: 'left'

View File

@ -45,11 +45,12 @@
v-slot="{ togglePopover }"
@update:modelValue="() => appendEmoji()"
>
<Button variant="ghost" @click="togglePopover()">
<template #icon>
<SmileIcon class="h-4" />
</template>
</Button>
<Button
:tooltip="__('Insert Emoji')"
:icon="SmileIcon"
variant="ghost"
@click="togglePopover()"
/>
</IconPicker>
<FileUploader
:upload-args="{
@ -61,14 +62,11 @@
>
<template #default="{ openFileSelector }">
<Button
theme="gray"
:tooltip="__('Attach a file')"
variant="ghost"
:icon="AttachmentIcon"
@click="openFileSelector()"
>
<template #icon>
<AttachmentIcon class="h-4" />
</template>
</Button>
/>
</template>
</FileUploader>
</div>

View File

@ -8,24 +8,18 @@
showEmailBox ? '!bg-surface-gray-4 hover:!bg-surface-gray-3' : '',
]"
:label="__('Reply')"
:iconLeft="Email2Icon"
@click="toggleEmailBox()"
>
<template #prefix>
<Email2Icon class="h-4" />
</template>
</Button>
/>
<Button
variant="ghost"
:label="__('Comment')"
:class="[
showCommentBox ? '!bg-surface-gray-4 hover:!bg-surface-gray-3' : '',
]"
:iconLeft="CommentIcon"
@click="toggleCommentBox()"
>
<template #prefix>
<CommentIcon class="h-4" />
</template>
</Button>
/>
</div>
</div>
<div
@ -45,7 +39,7 @@
onClick: () => {
showEmailBox = false
newEmailEditor.subject = subject
newEmailEditor.toEmails = doc.data.email ? [doc.data.email] : []
newEmailEditor.toEmails = doc.email ? [doc.email] : []
newEmailEditor.ccEmails = []
newEmailEditor.bccEmails = []
newEmailEditor.cc = false
@ -54,7 +48,7 @@
},
}"
:editable="showEmailBox"
v-model="doc.data"
v-model="doc"
v-model:attachments="attachments"
:doctype="doctype"
:subject="subject"
@ -79,7 +73,7 @@
},
}"
:editable="showCommentBox"
v-model="doc.data"
v-model="doc"
v-model:attachments="attachments"
:doctype="doctype"
:placeholder="__('@John, can you please check this?')"
@ -125,12 +119,12 @@ const attachments = ref([])
const subject = computed(() => {
let prefix = ''
if (doc.value.data?.lead_name) {
prefix = doc.value.data.lead_name
} else if (doc.value.data?.organization) {
prefix = doc.value.data.organization
if (doc.value?.lead_name) {
prefix = doc.value.lead_name
} else if (doc.value?.organization) {
prefix = doc.value.organization
}
return `${prefix} (#${doc.value.data.name})`
return `${prefix} (#${doc.value.name})`
})
const signature = createResource({
@ -199,7 +193,7 @@ async function sendMail() {
subject: subject,
content: newEmail.value,
doctype: props.doctype,
name: doc.value.data.name,
name: doc.value.name,
send_email: 1,
sender: getUser().email,
sender_full_name: getUser()?.full_name || undefined,
@ -209,7 +203,7 @@ async function sendMail() {
async function sendComment() {
let comment = await call('frappe.desk.form.utils.add_comment', {
reference_doctype: props.doctype,
reference_name: doc.value.data.name,
reference_name: doc.value.name,
content: newComment.value,
comment_email: getUser().email,
comment_by: getUser()?.full_name || undefined,

View File

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

View File

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

View File

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

View File

@ -52,16 +52,14 @@
>
</div>
</div>
<div class="w-12">
<div class="flex items-center justify-center w-12">
<Button
class="flex w-full items-center justify-center rounded !bg-surface-gray-2 border-0"
:tooltip="__('Edit grid fields')"
class="rounded !bg-surface-gray-2 border-0 !text-ink-gray-5"
variant="outline"
icon="settings"
@click="showGridFieldsEditorModal = true"
>
<template #icon>
<FeatherIcon name="settings" class="size-4 text-ink-gray-7" />
</template>
</Button>
/>
</div>
</div>
<!-- Rows -->
@ -72,6 +70,7 @@
:delay="isTouchScreenDevice() ? 200 : 0"
group="rows"
item-key="name"
@end="reorder"
>
<template #item="{ element: row, index }">
<div
@ -277,16 +276,14 @@
/>
</div>
</div>
<div class="edit-row w-12">
<div class="edit-row flex items-center justify-center w-12">
<Button
class="flex w-full items-center justify-center rounded border-0"
:tooltip="__('Edit row')"
class="rounded border-0 !text-ink-gray-7"
variant="outline"
:icon="EditIcon"
@click="showRowList[index] = true"
>
<template #icon>
<EditIcon class="text-ink-gray-7" />
</template>
</Button>
/>
</div>
<GridRowModal
v-if="showRowList[index]"
@ -350,7 +347,6 @@ import { usersStore } from '@/stores/users'
import { getMeta } from '@/stores/meta'
import { createDocument } from '@/composables/document'
import {
FeatherIcon,
FormControl,
Checkbox,
DateTimePicker,
@ -520,6 +516,13 @@ const deleteRows = () => {
selectedRows.clear()
}
const reorder = () => {
rows.value.forEach((row, index) => {
row.idx = index + 1
})
}
function fieldChange(value, field, row) {
triggerOnChange(field.fieldname, value, row)
}

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