|
56703
|
NULL
|
0
|
2026-04-20T11:26:00.642278+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776684360642_m1.jpg...
|
PhpStorm
|
PhpStorm
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Activity MonitorFileEditViewWindowHelpDOCKERLast l Activity MonitorFileEditViewWindowHelpDOCKERLast login: Mon Apr 20 13:26:00 on ttys008DEV (-zsh)O $82APP (-Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentsPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/Jiminny/app (JY-18909-automated-reports-ask-lahlActivity MonitorAll ProcessesProcess NamePhpStormkernel_taskscreenpipeWindowServerFirefoxCP Isolated Web ContentFirefoxCP Isolated Web ContentFirefoxCP Isolated Web ContentClaudelanguage_server_macos_armWispr Flow Helper (Renderer)FirefoxlaunchservicesdActivity MonitorWispr Flow Helper (Renderer)Wispr FlowDockerlocationdiTerm2Karabiner-Core-ServiceWispr Flow Helper (GPU)FirefoxCP Isolated Web ContentsyspolicydopendirectorydControl Centreairportdtccdreplaydio.kandji.KandjiAgent.ESF-ExtensionSystem:User:Idle:20,32%25,47%54,21%% CPU90,169,435,429,715,711,18,07,03,03,02,92,82,72,62,32,32,11,81,51,41,21,21,01,01,01,00,90,9CPU LOAD100% <78Mon 20 Apr 14:26:00CPUMemoryEnergyDiskNetworkCPU TimeThreadsIdie Wake-Ups39:02,891:57:19,5211:04,3715:08,691:57,3632,562:04,971:24,403:14,671:53,293:35,475:07,691:41,511:34,331:35,0525,4024,661:41,183:02,4355,261:19,084:06,811:54,8738,6732,1133,5729,735:36, KindThreads:Processes:3 814455...
|
NULL
|
-582933531296111576
|
NULL
|
click
|
ocr
|
NULL
|
Activity MonitorFileEditViewWindowHelpDOCKERLast l Activity MonitorFileEditViewWindowHelpDOCKERLast login: Mon Apr 20 13:26:00 on ttys008DEV (-zsh)O $82APP (-Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentsPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/Jiminny/app (JY-18909-automated-reports-ask-lahlActivity MonitorAll ProcessesProcess NamePhpStormkernel_taskscreenpipeWindowServerFirefoxCP Isolated Web ContentFirefoxCP Isolated Web ContentFirefoxCP Isolated Web ContentClaudelanguage_server_macos_armWispr Flow Helper (Renderer)FirefoxlaunchservicesdActivity MonitorWispr Flow Helper (Renderer)Wispr FlowDockerlocationdiTerm2Karabiner-Core-ServiceWispr Flow Helper (GPU)FirefoxCP Isolated Web ContentsyspolicydopendirectorydControl Centreairportdtccdreplaydio.kandji.KandjiAgent.ESF-ExtensionSystem:User:Idle:20,32%25,47%54,21%% CPU90,169,435,429,715,711,18,07,03,03,02,92,82,72,62,32,32,11,81,51,41,21,21,01,01,01,00,90,9CPU LOAD100% <78Mon 20 Apr 14:26:00CPUMemoryEnergyDiskNetworkCPU TimeThreadsIdie Wake-Ups39:02,891:57:19,5211:04,3715:08,691:57,3632,562:04,971:24,403:14,671:53,293:35,475:07,691:41,511:34,331:35,0525,4024,661:41,183:02,4355,261:19,084:06,811:54,8738,6732,1133,5729,735:36, KindThreads:Processes:3 814455...
|
56701
|
|
56678
|
NULL
|
0
|
2026-04-20T11:20:59.835014+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776684059835_m2.jpg...
|
Firefox
|
Firefox
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
FirefoxcalVIewMistorbookmarksProtllesToolsWindowme FirefoxcalVIewMistorbookmarksProtllesToolsWindowmelp• • www.figma.com/design/iXcUe1y9mx5Fiz8KosLAUn/Project-Phoenix?node-id=15100-49503&t=3ZhzmBDv2Kki6wl9-0|RookmarksProlect PhoenixJy 19798 evaluation for ai activityQ Search bookmarksPagesJY-20553 | Improve crm-sync delav la bookmarks loolba• Sorint BoardiCoverSRD-6793) Les Mills activity type→SRD Queue• SearchGithubJY-20698 handle failed field syncOnDemand8 Jiminny DEV•JY-20692 change confirmation paAsk liminnv Renorts bv nikolav-vankov . ....Plavback0 Circle Cö Deal Insights(JY-20543) AJ Reports > Trackina& PROD US4 Team Insiahts• = Bookmarks Menu(JY-18909] (Part2] Automated repOther BookmarkslAl ReportsAsk Jiminny Reports by nikolay-ya@ Org. Setting:- New Tabu Product Growth Plattorm UserpilgProduct Feedback EUtt Product Feedback USfix(security): composer dependertt Loss Report UKPipelines - jiminny/appCoaching Frameworks UK+* Coachina Frameworks US) Feed - jiminny - Sentry# Loss Report US8 JiminnyExec Summary US8JiminnyP Exec Report Adontion - PD-1908 JiminnyTA Don't show the page except if thep1 ALL(JY-20692] Issue with reconnectPAA• Jy-20692 change confirmation pa# Delete AJPanorama Prompt(JY-20692) Issue with reconnectirDelete Saved search• Drondown19 ISRD-67871 Issue with reconnecti# Emait for generated report*) Jiminny MCP Connector - Producttt Automated Reports(JY-20676] Notity the user if a Paltt. Automated RenortsProject Phoenix - Figma# Emait for not generated report#t A4-18Pipelines - jiminny/app# A4-16JL Now Tohtt Exporttt SettinasDelete AJPanorama PrompKinckOrganizationsserup Accountg+Automated ReportsORGANIZATIONORGANIZATIONTYPE→TEAM 3FREQUENCYThis prompt is used in reports"[Prompt Namel" is used in one or more Ask Jiminny reports. Deletineit will disable those reportsIf you want to keep them running, edit the reports to use a differentprompt first.CancolNeleto1280 x 832You can oniv view and comment on this fileStart editing XI.0.0-<>100% LzMon 20 AOr 14.-20:09SIAIUAllcomments.. Delete AJPanorama PromptVariable collecti... Auto (Mode 1)Width1280pyHeight832pxColors#FFFFFF100%vRECEIVERICNKМOвС...
|
NULL
|
-3818443489717561246
|
NULL
|
idle
|
ocr
|
NULL
|
FirefoxcalVIewMistorbookmarksProtllesToolsWindowme FirefoxcalVIewMistorbookmarksProtllesToolsWindowmelp• • www.figma.com/design/iXcUe1y9mx5Fiz8KosLAUn/Project-Phoenix?node-id=15100-49503&t=3ZhzmBDv2Kki6wl9-0|RookmarksProlect PhoenixJy 19798 evaluation for ai activityQ Search bookmarksPagesJY-20553 | Improve crm-sync delav la bookmarks loolba• Sorint BoardiCoverSRD-6793) Les Mills activity type→SRD Queue• SearchGithubJY-20698 handle failed field syncOnDemand8 Jiminny DEV•JY-20692 change confirmation paAsk liminnv Renorts bv nikolav-vankov . ....Plavback0 Circle Cö Deal Insights(JY-20543) AJ Reports > Trackina& PROD US4 Team Insiahts• = Bookmarks Menu(JY-18909] (Part2] Automated repOther BookmarkslAl ReportsAsk Jiminny Reports by nikolay-ya@ Org. Setting:- New Tabu Product Growth Plattorm UserpilgProduct Feedback EUtt Product Feedback USfix(security): composer dependertt Loss Report UKPipelines - jiminny/appCoaching Frameworks UK+* Coachina Frameworks US) Feed - jiminny - Sentry# Loss Report US8 JiminnyExec Summary US8JiminnyP Exec Report Adontion - PD-1908 JiminnyTA Don't show the page except if thep1 ALL(JY-20692] Issue with reconnectPAA• Jy-20692 change confirmation pa# Delete AJPanorama Prompt(JY-20692) Issue with reconnectirDelete Saved search• Drondown19 ISRD-67871 Issue with reconnecti# Emait for generated report*) Jiminny MCP Connector - Producttt Automated Reports(JY-20676] Notity the user if a Paltt. Automated RenortsProject Phoenix - Figma# Emait for not generated report#t A4-18Pipelines - jiminny/app# A4-16JL Now Tohtt Exporttt SettinasDelete AJPanorama PrompKinckOrganizationsserup Accountg+Automated ReportsORGANIZATIONORGANIZATIONTYPE→TEAM 3FREQUENCYThis prompt is used in reports"[Prompt Namel" is used in one or more Ask Jiminny reports. Deletineit will disable those reportsIf you want to keep them running, edit the reports to use a differentprompt first.CancolNeleto1280 x 832You can oniv view and comment on this fileStart editing XI.0.0-<>100% LzMon 20 AOr 14.-20:09SIAIUAllcomments.. Delete AJPanorama PromptVariable collecti... Auto (Mode 1)Width1280pyHeight832pxColors#FFFFFF100%vRECEIVERICNKМOвС...
|
56676
|
|
56677
|
NULL
|
0
|
2026-04-20T11:20:49.235844+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776684049235_m1.jpg...
|
Firefox
|
Firefox
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Activity MonitorFileEditViewWindowHelpDOCKERLast l Activity MonitorFileEditViewWindowHelpDOCKERLast login: Mon Apr 20 13:26:00 on ttys008DEV (-zsh)O $82APP (-Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentsPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/Jiminny/app (JY-18909-automated-reports-ask-IALActivity MonitorAll ProcessesProcess Namekernel_taskscreenpipeFirefoxCP Isolated Web ContentWindowServerPhpStormFirefoxCP Isolated Web Contentlanguage_server_macos_armlaunchdWispr Flow Helper (Renderer)Activity MonitoriTerm2Wispr FlowWispr Flow Helper (Renderer)FirefoxsyspolicydWispr Flow Helper (GPU)launchservicesdtccdControl CentreKarabiner-Core-ServicereplaydDockersysmondFirefoxCP Isolated Web Contentcom.apple.AppleUserHIDDriverstrustdFirefoxCP Isolated Web ContentrunningboarddSystem:User:Idle:% CPU13,48,58,26,86,05,55,13,73,12,82,82,82,52,51,81,61,51,31,21,11,00,90,90,80,80,70,70,7CPU LOAD100% <78Mon 20 Apr 14:20:49CPUMemoryEnergyDiskNetworkCPU TimeThreadsIdie Wake-Ups1:56:28,8210:28,441:46,6714:41,3538:39,5211,252:58,082:10,801:43,271:32,551:31,701:26,521:26,353:29,294:01,5650,275:03,6830,2235,232:59,0426,7921,781:33,091:48,811:44,152:27,821:02,6543, Kind7,13%6,17%86,71%Threads:Processes:3 832455...
|
NULL
|
-5431875368750204985
|
NULL
|
idle
|
ocr
|
NULL
|
Activity MonitorFileEditViewWindowHelpDOCKERLast l Activity MonitorFileEditViewWindowHelpDOCKERLast login: Mon Apr 20 13:26:00 on ttys008DEV (-zsh)O $82APP (-Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentsPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/Jiminny/app (JY-18909-automated-reports-ask-IALActivity MonitorAll ProcessesProcess Namekernel_taskscreenpipeFirefoxCP Isolated Web ContentWindowServerPhpStormFirefoxCP Isolated Web Contentlanguage_server_macos_armlaunchdWispr Flow Helper (Renderer)Activity MonitoriTerm2Wispr FlowWispr Flow Helper (Renderer)FirefoxsyspolicydWispr Flow Helper (GPU)launchservicesdtccdControl CentreKarabiner-Core-ServicereplaydDockersysmondFirefoxCP Isolated Web Contentcom.apple.AppleUserHIDDriverstrustdFirefoxCP Isolated Web ContentrunningboarddSystem:User:Idle:% CPU13,48,58,26,86,05,55,13,73,12,82,82,82,52,51,81,61,51,31,21,11,00,90,90,80,80,70,70,7CPU LOAD100% <78Mon 20 Apr 14:20:49CPUMemoryEnergyDiskNetworkCPU TimeThreadsIdie Wake-Ups1:56:28,8210:28,441:46,6714:41,3538:39,5211,252:58,082:10,801:43,271:32,551:31,701:26,521:26,353:29,294:01,5650,275:03,6830,2235,232:59,0426,7921,781:33,091:48,811:44,152:27,821:02,6543, Kind7,13%6,17%86,71%Threads:Processes:3 832455...
|
56671
|
|
56573
|
NULL
|
0
|
2026-04-20T11:15:56.818378+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776683756818_m2.jpg...
|
Firefox
|
Firefox
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
FirefoxcalVIewHistorybookmarksBookmarksJy 19798 ev FirefoxcalVIewHistorybookmarksBookmarksJy 19798 evaluation for ai activityQ Search bookmarksJY-20553 | Improve crm-sync dela|SRD-6793) Les Mills activity typeJY-20698 handle failed field syne•JY-20692 change confirmation pa(JY-20543) AJ Reports > Trackinav a bookmarks loolbaSprint Board# SRD QueueGithubJiminny DEVAsk Jiminny Reports by nikolay-yankov• ...© Circle CI& PROD US> = bookmarks Menu(UY-18909) (Part2) Automated rep/Other BookmarksAsk Jiminny Reports by nikolay-ya- New Tabu Product Growth Plattorm Userpilg(fix(security): composer dependerPipelines - jiminny/app) Feed - jiminny - Sentry8 Jiminny8Jiminny8 Jiminny(JY-20692] Issue with reconnect• Jy-20692 change confirmation pa# (UY-20692) Issue with reconnectin19 ISRD-67871 Issue with reconnect*) Jiminny MCP Connector - Product* (UY-20676] Notify the user if a Pan) Pinelines - liminnvlaor) Symfony|Component\ErrorHanJ New TabProtlles1OOISWindowmelpninny.sentry.io/issues/7417255437/?environment=production&environment=production-eu&project=82419&query=is%3Aunresolved&referrer=issue-stream&sort=news/crm/crmentitykepository.oho inIssuesFeed1-euvSince First Seen• Filter events..Errors & OutagesBreached MetricsExplore08WarningsUser FeedbackAor 15 9:00 PMLnUmm nulmApr 16 9:00 PMApr 17 9:00 PMem hmlnlamhuhIllAor 19 9:00 PMAll ViewsInsightsinutes ago | JSONconnoureSettinacAlertsnux 6.1.141-155.222.amzn2023.aarch64 @ 873060 @ production-eueftrorant FrrorHandler Error. SatalErrorize ot 268435456 bytes exhausted tried to allocate 16485766 bvteshandled truecodeerm//CrmEntitvRenositorv.nhn:102'config_id' => SconfigurationId,each (Sitems as Sitem) (Saccounts Sitem->crm nrovider idi = Sitem-sid»= memory aet usageo:l: info("ExternalAccountMap final',<> FirstTrace: Trace ID8bbf4e908dd84e2889410d06c3a21ecd73% 872868mechanismView all tags•100% aenericRecommendedView More EventsJump to: HighlightsStack TraceCopy asvContex4 Edit Displayv… Copyas vin Aon100% LzMon z0 AOr 14:10:00Priority ailvAssigneeLast seen 29 minutes agoFirst seen 4 days agoin release 872399v Seer Autonx aHave Seer..1. Determine the rootcause of your issueZ. Uutline a plan3.Create a code fy0 Start Analysisv Issue TrackingGitHub*i Jirav ActivityAdd a commen....First Seenl4 days agov PeopleOINIP viewedcimilar IssuesMeraed IssuesViewView Full Trace- Allowed memory size of 268435456 bytes exhausted (tried to allocate 10485760 bytes) Symfony\Component\ErrorHandler\Error \FatalError /app/Rep...
|
NULL
|
3929773506310846296
|
NULL
|
click
|
ocr
|
NULL
|
FirefoxcalVIewHistorybookmarksBookmarksJy 19798 ev FirefoxcalVIewHistorybookmarksBookmarksJy 19798 evaluation for ai activityQ Search bookmarksJY-20553 | Improve crm-sync dela|SRD-6793) Les Mills activity typeJY-20698 handle failed field syne•JY-20692 change confirmation pa(JY-20543) AJ Reports > Trackinav a bookmarks loolbaSprint Board# SRD QueueGithubJiminny DEVAsk Jiminny Reports by nikolay-yankov• ...© Circle CI& PROD US> = bookmarks Menu(UY-18909) (Part2) Automated rep/Other BookmarksAsk Jiminny Reports by nikolay-ya- New Tabu Product Growth Plattorm Userpilg(fix(security): composer dependerPipelines - jiminny/app) Feed - jiminny - Sentry8 Jiminny8Jiminny8 Jiminny(JY-20692] Issue with reconnect• Jy-20692 change confirmation pa# (UY-20692) Issue with reconnectin19 ISRD-67871 Issue with reconnect*) Jiminny MCP Connector - Product* (UY-20676] Notify the user if a Pan) Pinelines - liminnvlaor) Symfony|Component\ErrorHanJ New TabProtlles1OOISWindowmelpninny.sentry.io/issues/7417255437/?environment=production&environment=production-eu&project=82419&query=is%3Aunresolved&referrer=issue-stream&sort=news/crm/crmentitykepository.oho inIssuesFeed1-euvSince First Seen• Filter events..Errors & OutagesBreached MetricsExplore08WarningsUser FeedbackAor 15 9:00 PMLnUmm nulmApr 16 9:00 PMApr 17 9:00 PMem hmlnlamhuhIllAor 19 9:00 PMAll ViewsInsightsinutes ago | JSONconnoureSettinacAlertsnux 6.1.141-155.222.amzn2023.aarch64 @ 873060 @ production-eueftrorant FrrorHandler Error. SatalErrorize ot 268435456 bytes exhausted tried to allocate 16485766 bvteshandled truecodeerm//CrmEntitvRenositorv.nhn:102'config_id' => SconfigurationId,each (Sitems as Sitem) (Saccounts Sitem->crm nrovider idi = Sitem-sid»= memory aet usageo:l: info("ExternalAccountMap final',<> FirstTrace: Trace ID8bbf4e908dd84e2889410d06c3a21ecd73% 872868mechanismView all tags•100% aenericRecommendedView More EventsJump to: HighlightsStack TraceCopy asvContex4 Edit Displayv… Copyas vin Aon100% LzMon z0 AOr 14:10:00Priority ailvAssigneeLast seen 29 minutes agoFirst seen 4 days agoin release 872399v Seer Autonx aHave Seer..1. Determine the rootcause of your issueZ. Uutline a plan3.Create a code fy0 Start Analysisv Issue TrackingGitHub*i Jirav ActivityAdd a commen....First Seenl4 days agov PeopleOINIP viewedcimilar IssuesMeraed IssuesViewView Full Trace- Allowed memory size of 268435456 bytes exhausted (tried to allocate 10485760 bytes) Symfony\Component\ErrorHandler\Error \FatalError /app/Rep...
|
56571
|
|
56572
|
NULL
|
0
|
2026-04-20T11:15:56.758445+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776683756758_m1.jpg...
|
Firefox
|
Firefox
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Activity MonitorFileEditViewWindowHelpDOCKERLast l Activity MonitorFileEditViewWindowHelpDOCKERLast login: Mon Apr 20 13:26:00 on ttys008DEV (-zsh)O $82APP (-Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentsPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/Jiminny/app (JY-18909-automated-reports-ask-(aholActivity MonitorAll ProcessesProcess NameFirefoxCP Isolated Web ContentWindowServerscreenpipeFirefox GPU Helperkernel_taskFirefoxPhpStormlanguage_server_macos_armWispr Flow Helper (Renderer)iTerm2ClaudeActivity MonitorWispr Flow Helper (Renderer)Wispr FlowlaunchservicesdWispr Flow Helper (GPU)Karabiner-Core-ServicesyspolicydDockerControl CentrereplaydtccdsysmondFirefoxCP Isolated Web Contentbluetoothdcom.apple.AppleUserHIDDriverslogdtrustd% CPU39,937,224,223,118,88,05,24,13,33,23,12,62,62,31,81,61,41,31,01,00,90,90,80,70,70,70,60,6CPU LOAD100% <78Mon 20 Apr 14:15:56CPUMemoryEnergyDiskNetworkCPU TimeThreadsIdle Wake-Ups12,9312:56,559:19,934:21,371:55:21,453:01,1137:59,412:44,331:34,061:24,531:15,001:24,501:18,621:19,184:58,7845,882:55,583:56,7118,4332,4523,7126,991:30,891:00,262:22,991:42,171:17,122:25, KindSystem:User:Idle:9,22%19,91%70,87%Threads:Processes:3 763454...
|
NULL
|
5002325163562853956
|
NULL
|
click
|
ocr
|
NULL
|
Activity MonitorFileEditViewWindowHelpDOCKERLast l Activity MonitorFileEditViewWindowHelpDOCKERLast login: Mon Apr 20 13:26:00 on ttys008DEV (-zsh)O $82APP (-Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentsPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/Jiminny/app (JY-18909-automated-reports-ask-(aholActivity MonitorAll ProcessesProcess NameFirefoxCP Isolated Web ContentWindowServerscreenpipeFirefox GPU Helperkernel_taskFirefoxPhpStormlanguage_server_macos_armWispr Flow Helper (Renderer)iTerm2ClaudeActivity MonitorWispr Flow Helper (Renderer)Wispr FlowlaunchservicesdWispr Flow Helper (GPU)Karabiner-Core-ServicesyspolicydDockerControl CentrereplaydtccdsysmondFirefoxCP Isolated Web Contentbluetoothdcom.apple.AppleUserHIDDriverslogdtrustd% CPU39,937,224,223,118,88,05,24,13,33,23,12,62,62,31,81,61,41,31,01,00,90,90,80,70,70,70,60,6CPU LOAD100% <78Mon 20 Apr 14:15:56CPUMemoryEnergyDiskNetworkCPU TimeThreadsIdle Wake-Ups12,9312:56,559:19,934:21,371:55:21,453:01,1137:59,412:44,331:34,061:24,531:15,001:24,501:18,621:19,184:58,7845,882:55,583:56,7118,4332,4523,7126,991:30,891:00,262:22,991:42,171:17,122:25, KindSystem:User:Idle:9,22%19,91%70,87%Threads:Processes:3 763454...
|
NULL
|
|
56425
|
NULL
|
0
|
2026-04-20T11:10:44.748736+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776683444748_m2.jpg...
|
PhpStorm
|
PhpStorm
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormVIewINavigarecodeLaravelWindowmelpFV faVsc PhostormVIewINavigarecodeLaravelWindowmelpFV faVsco.jsProledey#11894 on JY-18909-automated-reports-askC) Ask liminnvReportActivityservice.ong© AutomatedReportsRepository.phpC) AutomatedReportsservice.onp© TrackProviderInstalledEvent.php• D OpportunitvMatchen© RequestGenerateReportJob.phpAutomatedkeponkesuitong© AutomatedReport.phpOpportunitySyncStrategyclass AuconacedkeporcsserviceProspectSearchStrategy• M CerviceTraitc(c) Client.php© DecorateActivity.pnp© DeleteObjectsTrait.phpc) rielaDerinitions.onp© PayloadBuilder.phpc) Pronile.pnp© QueryBuilder.phpc) @uerymandler.phpc) @uerviterator.ohoc) @uervkesulis.ono© Service.phpc) SvncBatchRedisService.ohu TraitsC Baseclient.ohv© BaseService.phoc) CachedcrmServiceDecorator.r© CountryCodeResolver.php(C) CrmActi vitvProviderintedratedC) CrmActivitvService.oho(C) CrmConfiaurationSettinasSen© CrmObjectsResolver.php© DefaultProspectSearchStrateg© EmailHelper.php© FindsProspectinterface.php© LayoutManager.php(0 MatchDomainRvEmailinterface© OpportunityActivityMatcher.pl© OpportunitySyncStrategyinterc Opportunitysyncstrategykesc(e) DrosnectCache.php€ ProspectSearchScope.phpC) ProspectSearchstrateavractol@ ProspectSearchStrategvinterf© ProviderRegistrv.phpRecordSelector.phpT ResolvecompanvNameByEmaC) TimePeriod terator.onolmoort7 InternallM Kioskv N AutomatedRenortsC) ActivitvTvoeService.ohoC) Ask.liminnvRenortActivitvS(c) AutomatedRenortsCallbackC) AutomatedRenortsService(C) Dea|StadecService nhn© RecipientsService.phppubLic tunction geukeportlyperzelavaral:string svalue = null, bool sshortversion = talse, tleam steam = null. arrayLabel' => 'Report Tvoe'.'options' => Stvoes.returnl'id' => 'report_type',"label' => "Renont Tvne!'inputType' => InputTypeEnum::DROPDOWN,'required' => true,"placenolder → select,'options' => $types,'value' => $value,'dependencies' => []'dependsOn' => [].6 usagespublic function getFrequencyFieldData(?string Svalue = null): arrayreturn"'id' => "Frequency')'inoutivoe' => InoutivoeEnum: : DROPDOWNI'placeholden' => "Select'.'ontions' e self.: FREQUENHIESI"value' => Svalue.'dependencies' => ['period'],'denendsin' => M.public function getPeriodFieldData(?string $valueStartDate = null, ?string $valueEndDate = null): arrayreturn'id' => 'period'.'label' => 'Select one-off period'.'inputType' => InputTypeEnum::DATE RANGE."required = true'placeholder' => 'Select''value' => ['startDate' => SvalueStartDate, 'endDate' => SvalueEndDatel.'queryParams' =>"startDate' => 'start date period'.'endDate' => 'end date period'.uure (4 minutes aaoB102 ~3 ×34 ^ Y 15911594159515961= laravel.log4 SF (jiminny@localhost]4 HS_local [jiminny@localhost]& console [Pkol)« console [EU] X console [STAGING]opportunity1d = 7594549 order by created at desc:10 = 60247select * from business_process_stages where stage_id = 16352;select * trom business process stageswhere business_process_ 1d = 60247select * from stages where team_id = 459;select * from teams where 1d = 4591SELECTCONCAT(u.id, CASE WHEN V.id = t.owner_id THEN ' (owner)' ELSE ' END) AS user_id,u.emallsa.*t.owner_id FROM social_accounts saJJouN users u on u.id = sa.sociable idAutomatedReportsService.phpInherited members (JR)Anonymous Classes (28))Lambdas (&L)M) & getCallTvpeFieldData([conferenceOn: bool = falsel. [dialerOn: bool = falsel): arrayo d getCalltypes(): array(m) ở qetcurrentDealStageFieldDatalteam: Teamnull = nulli. value: arrav = ...ID: arrav@ & getCurrentDealStagesUuids(report: AutomatedReport): arraym d getCustomReportNameFieldData([value: null|string = nullj): array@ & getDealAtCallStagesUuids(report: AutomatedReport): arraym d getDealStageAtCallFieldData([team: Team null = null), [value: array = [...))): array@ & getDealValueFieldData([valueMin: int|null = null], [valueMax: int|null = null]): arraym d getFilenameSuffix(result: AutomatedReportResult): null string0 d getFrequencies(): arrayd getFrequencyFieldData([value: null string = nullj): arraym & getGenerateReportPayload(automatedReport: AutomatedReport, reportResultUuid: strirm & getGroupRecipientUsers(report: AutomatedReport): array& getGroupsUuids (report: AutomatedReport): arraym & getJiminnyRecipientsFieldData([value: array = [...))): arraya getJiminnyRecipientUsers(report: AutomatedReport): arraym d getJiminnyUsersUuids(report: AutomatedReport): array& getMailSubjectSuffix(result: AutomatedReportResult): stringm & getMediaPath(result: AutomatedReportResult): null|string& getMediaTvpeFieldData([report: AutomatedReport|null = nulll): arravgetMediaTypeMetadata(result: AutomatedReportResult): nulialstringfn105056.15225.14555.6295.12098.1116070138.raza.qilanidvuelio.com162%SELECT * EROM eom confiaurations WHEREI1d = 380•— 16281629|SELECTCONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE "' END) AS user_id,u. email—1471|—16321634sa.*t.owner_id FROM social_accounts saJOIN users u on u.id = sa.sociable idJOIN teams t 1..n<->1: on t.id = u.team idWHERE u.team id = 472 and sa.provider = 'salesforce':100% S2Mon 20 Apr 14:10:44rliminny027 A9 A23 .3 У 105 ^1 1144WN Windsurf Toams 260•41UTF.8ih 4 spaces...
|
NULL
|
-1572162344466565439
|
NULL
|
visual_change
|
ocr
|
NULL
|
PhostormVIewINavigarecodeLaravelWindowmelpFV faVsc PhostormVIewINavigarecodeLaravelWindowmelpFV faVsco.jsProledey#11894 on JY-18909-automated-reports-askC) Ask liminnvReportActivityservice.ong© AutomatedReportsRepository.phpC) AutomatedReportsservice.onp© TrackProviderInstalledEvent.php• D OpportunitvMatchen© RequestGenerateReportJob.phpAutomatedkeponkesuitong© AutomatedReport.phpOpportunitySyncStrategyclass AuconacedkeporcsserviceProspectSearchStrategy• M CerviceTraitc(c) Client.php© DecorateActivity.pnp© DeleteObjectsTrait.phpc) rielaDerinitions.onp© PayloadBuilder.phpc) Pronile.pnp© QueryBuilder.phpc) @uerymandler.phpc) @uerviterator.ohoc) @uervkesulis.ono© Service.phpc) SvncBatchRedisService.ohu TraitsC Baseclient.ohv© BaseService.phoc) CachedcrmServiceDecorator.r© CountryCodeResolver.php(C) CrmActi vitvProviderintedratedC) CrmActivitvService.oho(C) CrmConfiaurationSettinasSen© CrmObjectsResolver.php© DefaultProspectSearchStrateg© EmailHelper.php© FindsProspectinterface.php© LayoutManager.php(0 MatchDomainRvEmailinterface© OpportunityActivityMatcher.pl© OpportunitySyncStrategyinterc Opportunitysyncstrategykesc(e) DrosnectCache.php€ ProspectSearchScope.phpC) ProspectSearchstrateavractol@ ProspectSearchStrategvinterf© ProviderRegistrv.phpRecordSelector.phpT ResolvecompanvNameByEmaC) TimePeriod terator.onolmoort7 InternallM Kioskv N AutomatedRenortsC) ActivitvTvoeService.ohoC) Ask.liminnvRenortActivitvS(c) AutomatedRenortsCallbackC) AutomatedRenortsService(C) Dea|StadecService nhn© RecipientsService.phppubLic tunction geukeportlyperzelavaral:string svalue = null, bool sshortversion = talse, tleam steam = null. arrayLabel' => 'Report Tvoe'.'options' => Stvoes.returnl'id' => 'report_type',"label' => "Renont Tvne!'inputType' => InputTypeEnum::DROPDOWN,'required' => true,"placenolder → select,'options' => $types,'value' => $value,'dependencies' => []'dependsOn' => [].6 usagespublic function getFrequencyFieldData(?string Svalue = null): arrayreturn"'id' => "Frequency')'inoutivoe' => InoutivoeEnum: : DROPDOWNI'placeholden' => "Select'.'ontions' e self.: FREQUENHIESI"value' => Svalue.'dependencies' => ['period'],'denendsin' => M.public function getPeriodFieldData(?string $valueStartDate = null, ?string $valueEndDate = null): arrayreturn'id' => 'period'.'label' => 'Select one-off period'.'inputType' => InputTypeEnum::DATE RANGE."required = true'placeholder' => 'Select''value' => ['startDate' => SvalueStartDate, 'endDate' => SvalueEndDatel.'queryParams' =>"startDate' => 'start date period'.'endDate' => 'end date period'.uure (4 minutes aaoB102 ~3 ×34 ^ Y 15911594159515961= laravel.log4 SF (jiminny@localhost]4 HS_local [jiminny@localhost]& console [Pkol)« console [EU] X console [STAGING]opportunity1d = 7594549 order by created at desc:10 = 60247select * from business_process_stages where stage_id = 16352;select * trom business process stageswhere business_process_ 1d = 60247select * from stages where team_id = 459;select * from teams where 1d = 4591SELECTCONCAT(u.id, CASE WHEN V.id = t.owner_id THEN ' (owner)' ELSE ' END) AS user_id,u.emallsa.*t.owner_id FROM social_accounts saJJouN users u on u.id = sa.sociable idAutomatedReportsService.phpInherited members (JR)Anonymous Classes (28))Lambdas (&L)M) & getCallTvpeFieldData([conferenceOn: bool = falsel. [dialerOn: bool = falsel): arrayo d getCalltypes(): array(m) ở qetcurrentDealStageFieldDatalteam: Teamnull = nulli. value: arrav = ...ID: arrav@ & getCurrentDealStagesUuids(report: AutomatedReport): arraym d getCustomReportNameFieldData([value: null|string = nullj): array@ & getDealAtCallStagesUuids(report: AutomatedReport): arraym d getDealStageAtCallFieldData([team: Team null = null), [value: array = [...))): array@ & getDealValueFieldData([valueMin: int|null = null], [valueMax: int|null = null]): arraym d getFilenameSuffix(result: AutomatedReportResult): null string0 d getFrequencies(): arrayd getFrequencyFieldData([value: null string = nullj): arraym & getGenerateReportPayload(automatedReport: AutomatedReport, reportResultUuid: strirm & getGroupRecipientUsers(report: AutomatedReport): array& getGroupsUuids (report: AutomatedReport): arraym & getJiminnyRecipientsFieldData([value: array = [...))): arraya getJiminnyRecipientUsers(report: AutomatedReport): arraym d getJiminnyUsersUuids(report: AutomatedReport): array& getMailSubjectSuffix(result: AutomatedReportResult): stringm & getMediaPath(result: AutomatedReportResult): null|string& getMediaTvpeFieldData([report: AutomatedReport|null = nulll): arravgetMediaTypeMetadata(result: AutomatedReportResult): nulialstringfn105056.15225.14555.6295.12098.1116070138.raza.qilanidvuelio.com162%SELECT * EROM eom confiaurations WHEREI1d = 380•— 16281629|SELECTCONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE "' END) AS user_id,u. email—1471|—16321634sa.*t.owner_id FROM social_accounts saJOIN users u on u.id = sa.sociable idJOIN teams t 1..n<->1: on t.id = u.team idWHERE u.team id = 472 and sa.provider = 'salesforce':100% S2Mon 20 Apr 14:10:44rliminny027 A9 A23 .3 У 105 ^1 1144WN Windsurf Toams 260•41UTF.8ih 4 spaces...
|
NULL
|
|
56423
|
NULL
|
0
|
2026-04-20T11:10:43.062123+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776683443062_m1.jpg...
|
PhpStorm
|
PhpStorm
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Activity MonitorFileEditViewWindowHelpDOCKERLast l Activity MonitorFileEditViewWindowHelpDOCKERLast login: Mon Apr 20 13:26:00 on ttys008DEV (-zsh)O $82APP (-Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentsPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/Jiminny/app (JY-18909-automated-reports-ask-Activity MonitorAll ProcessesProcess Namekernel_taskWindowServerFirefoxCP Isolated Web ContentFirefoxCP Isolated Web ContentscreenpipePhpStormSlack Helper (Renderer)language_server_macos_armSlack HelperWispr Flow Helper (Renderer)Wispr FlowFirefoxFirefoxCP Isolated Web ContentActivity MonitorWispr Flow Helper (Renderer)FirefoxCP Isolated Web ContentClaudeFirefox GPU HelperiTerm2ContextStoreAgentSlackWispr Flow Helper (GPU)launchservicesdKarabiner-Core-ServiceFirefoxCP Isolated Web ContentWindowManagerCursorUlViewServiceDockerSystem:User:Idle:% CPU27,526,021,920,916,815,113,64,34,03,13,03,02,82,72,72,42,31,81,81,81,81,51,31,31,31,21,11,0CPU LOAD100% <78Mon 20 Apr 14:10:42CPUMemoryEnergyDiskNetworkCPU TimeThreadsIdie Wake-Ups1:52:40,9411:31,8949,801:37,447:23,9726:48,661:17,292:21,0911,761:24,291:11,182:53,3110,621:15,441:10,4633,561:02,924:11,461:17,388,1017,4741,164:52,502:51,3240,6012,596,2014, Kind15,64%36,30%48,06%Threads:Processes:3243 812454...
|
NULL
|
9219904808411618688
|
NULL
|
click
|
ocr
|
NULL
|
Activity MonitorFileEditViewWindowHelpDOCKERLast l Activity MonitorFileEditViewWindowHelpDOCKERLast login: Mon Apr 20 13:26:00 on ttys008DEV (-zsh)O $82APP (-Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentsPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/Jiminny/app (JY-18909-automated-reports-ask-Activity MonitorAll ProcessesProcess Namekernel_taskWindowServerFirefoxCP Isolated Web ContentFirefoxCP Isolated Web ContentscreenpipePhpStormSlack Helper (Renderer)language_server_macos_armSlack HelperWispr Flow Helper (Renderer)Wispr FlowFirefoxFirefoxCP Isolated Web ContentActivity MonitorWispr Flow Helper (Renderer)FirefoxCP Isolated Web ContentClaudeFirefox GPU HelperiTerm2ContextStoreAgentSlackWispr Flow Helper (GPU)launchservicesdKarabiner-Core-ServiceFirefoxCP Isolated Web ContentWindowManagerCursorUlViewServiceDockerSystem:User:Idle:% CPU27,526,021,920,916,815,113,64,34,03,13,03,02,82,72,72,42,31,81,81,81,81,51,31,31,31,21,11,0CPU LOAD100% <78Mon 20 Apr 14:10:42CPUMemoryEnergyDiskNetworkCPU TimeThreadsIdie Wake-Ups1:52:40,9411:31,8949,801:37,447:23,9726:48,661:17,292:21,0911,761:24,291:11,182:53,3110,621:15,441:10,4633,561:02,924:11,461:17,388,1017,4741,164:52,502:51,3240,6012,596,2014, Kind15,64%36,30%48,06%Threads:Processes:3243 812454...
|
NULL
|
|
56284
|
NULL
|
0
|
2026-04-20T11:05:31.676476+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776683131676_m1.jpg...
|
Firefox
|
Firefox
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelp-zshDOCKERLast SlackFileEditViewGoHistoryWindowHelp-zshDOCKERLast login: Mon Apr 20 13:26:00 on ttys008DEV (-zsh)O $82APP (-zsh)Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentsPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ |*3A100% C-zsh8Mon 20 Apr 14:05:31screenpipe"T₴1**5...
|
NULL
|
7152512680728144406
|
NULL
|
visual_change
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelp-zshDOCKERLast SlackFileEditViewGoHistoryWindowHelp-zshDOCKERLast login: Mon Apr 20 13:26:00 on ttys008DEV (-zsh)O $82APP (-zsh)Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentsPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ |*3A100% C-zsh8Mon 20 Apr 14:05:31screenpipe"T₴1**5...
|
NULL
|
|
56283
|
NULL
|
0
|
2026-04-20T11:05:31.525688+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776683131525_m2.jpg...
|
Firefox
|
Firefox
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
FirefoxEditVIew… MnzApr 14:053187 OpenJY-20692 cha FirefoxEditVIew… MnzApr 14:053187 OpenJY-20692 change confirmation parameter #11986LakyLak wants to merge 3 commits into master from JY-20692-fix-inteqration-app-[API_KEY] 19798 evaluation for ai activityJY-20553 | Improve crm-sync dela19 ISRD-67931 Les Mills activity typeJY-20698 handle failed field sync. JY-20692 change confirmation *JY-205431 AJ Reports > Tracking(UY-18909) (Part2) Automated rep/Ask Jiminny Reports by nikolay-ya- New Tabu Product Growth Platform | UserpiloU Userpilot I Loaaed-activity(fix(security): composer dependerPipelines - jiminny/app) Feed - jiminny - Sentry8 Jiminny7 Jiminnv8 Jiminny(JY-20692] Issue with reconnect• Jy-20692 change confirmation pa(JY-20692) Issue with reconnectir19 ISRD-67871 Issue with reconnect*) Jiminny MCP Connector - Product* (UY-20676] Notify the user if a Pan6) Pinelines - liminnvlanr+ New TabMistorbookmarksProtllesToolsWindowmelp• github.com/jiminny/app/pull/11986Rookmarks• Search bookmarksv a bookmarks loolbaSprint Board# SRD QueueGithubJiminny DEVAsk Jiminny Reports by nikolay-yankov • ...© Circle CI& PROD US> E Bookmarks MenuOther Bookmarkssonarqubecloud bot commented 2 minutes ago~ Quality Gate passedIssuesV • New issues© 0 Accepted issuesMeasuresV • Security Hotsootsi~ 0.0% Coverage on New Codev 0.0% Duplication on New CodeSee analysis details on SonarQube Cloud• @ Merae branch 'master' into JY-20692-fix-integration-app-token-auth-re.. ...Verified) • 6e61731• This branch has not been deployed•No deploymentsx Review requiredAt least 1 approving review is required by reviewers with write access.& 3 pending reviews ›•Some checks haven't completed yet1 pending, 1 in progress, 1 expected checksA Merging is blockedAt least 1 approving review is required by reviewers with write access.Enable auto-merge You can also merge this with the command line. View command line instructionsStill in progress? Convert to draftAdd a commentWritePreviewAdd vour comment here…...
|
NULL
|
8164033851625910145
|
NULL
|
visual_change
|
ocr
|
NULL
|
FirefoxEditVIew… MnzApr 14:053187 OpenJY-20692 cha FirefoxEditVIew… MnzApr 14:053187 OpenJY-20692 change confirmation parameter #11986LakyLak wants to merge 3 commits into master from JY-20692-fix-inteqration-app-[API_KEY] 19798 evaluation for ai activityJY-20553 | Improve crm-sync dela19 ISRD-67931 Les Mills activity typeJY-20698 handle failed field sync. JY-20692 change confirmation *JY-205431 AJ Reports > Tracking(UY-18909) (Part2) Automated rep/Ask Jiminny Reports by nikolay-ya- New Tabu Product Growth Platform | UserpiloU Userpilot I Loaaed-activity(fix(security): composer dependerPipelines - jiminny/app) Feed - jiminny - Sentry8 Jiminny7 Jiminnv8 Jiminny(JY-20692] Issue with reconnect• Jy-20692 change confirmation pa(JY-20692) Issue with reconnectir19 ISRD-67871 Issue with reconnect*) Jiminny MCP Connector - Product* (UY-20676] Notify the user if a Pan6) Pinelines - liminnvlanr+ New TabMistorbookmarksProtllesToolsWindowmelp• github.com/jiminny/app/pull/11986Rookmarks• Search bookmarksv a bookmarks loolbaSprint Board# SRD QueueGithubJiminny DEVAsk Jiminny Reports by nikolay-yankov • ...© Circle CI& PROD US> E Bookmarks MenuOther Bookmarkssonarqubecloud bot commented 2 minutes ago~ Quality Gate passedIssuesV • New issues© 0 Accepted issuesMeasuresV • Security Hotsootsi~ 0.0% Coverage on New Codev 0.0% Duplication on New CodeSee analysis details on SonarQube Cloud• @ Merae branch 'master' into JY-20692-fix-integration-app-token-auth-re.. ...Verified) • 6e61731• This branch has not been deployed•No deploymentsx Review requiredAt least 1 approving review is required by reviewers with write access.& 3 pending reviews ›•Some checks haven't completed yet1 pending, 1 in progress, 1 expected checksA Merging is blockedAt least 1 approving review is required by reviewers with write access.Enable auto-merge You can also merge this with the command line. View command line instructionsStill in progress? Convert to draftAdd a commentWritePreviewAdd vour comment here…...
|
NULL
|
|
56171
|
NULL
|
0
|
2026-04-20T11:00:29.341229+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776682829341_m1.jpg...
|
Firefox
|
Firefox
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
iTerm2ShelllEditViewSessionScriptsProfilesWindowHe iTerm2ShelllEditViewSessionScriptsProfilesWindowHelp-zshDOCKERLast login: Mon Apr 20 13:26:00 on ttys008DEV (-zsh)O $82APP (-zsh)Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentsPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ |*3A100% C-zsh8Mon 20 Apr 14:00:29screenpipe"T81• *5...
|
NULL
|
-3429087256106325835
|
NULL
|
idle
|
ocr
|
NULL
|
iTerm2ShelllEditViewSessionScriptsProfilesWindowHe iTerm2ShelllEditViewSessionScriptsProfilesWindowHelp-zshDOCKERLast login: Mon Apr 20 13:26:00 on ttys008DEV (-zsh)O $82APP (-zsh)Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentsPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ |*3A100% C-zsh8Mon 20 Apr 14:00:29screenpipe"T81• *5...
|
NULL
|
|
56170
|
NULL
|
0
|
2026-04-20T11:00:04.414733+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776682804414_m2.jpg...
|
Firefox
|
Firefox
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
FirefoxJy 19798 evaluation for ai activityJY-20553 FirefoxJy 19798 evaluation for ai activityJY-20553 | Improve crm-sync delaSRD-6793) Les Mills activity typeJY-20698 handle failed field sync•JY-20692 change confirmation pa(JY-20543) AJ Reports > Trackina(UY-18909) (Part2) Automated rep/Ask Jiminny Reports by nikolay-ya- New Tabu Product Growth Plattorm UserpilgU Userpilot I Loaaed-activity(fix(security): composer dependePipelines - jiminny/app) Feed - jiminny - Sentry8 Jiminny8Jiminnyo Jimingy(JY-20692] Issue with reconnect• Jy-20692 change confirmation pa# (UY-20692) Issue with reconnectin19 ISRD-67871 Issue with reconnect& Jiminny MCP Connector - Prod XVIewMistorbookmarksProtllesToolsWindowmelpnny.atlassian.net/wiki/spaces/PROD/pages/3728244737/Jiminny+MCP+ConnectorBookmarksO JIMINNYQ Search bookmarks$ Productv la bookmarks loolba• Sprint Board# SRD QueueGithubJiminny DEVAsk Jiminny Reports by nikolay-yankov •..© Circle CI8 PROD US> = bookmarks MenuOther Bookmarks> N 1 Back to topfor..> * Product Documentati..v 1 Product Briefsi• V Activity Export•V Autoloaaina activit….• = Deal Insiahts - Mu....• E Reinvent Themes ....• V Billina Portall• V Uoload Video/Audi...• E White-Label Jimin...• E Win/Loss Analvsis..• • Hubspot app• V Automatically hard…..• V Ask Jiminny Anyth….• V Ask .liminnv for O...• V Ask Jiminny Anyth...• V Automatically reco…• V Product Tiering• V Recording Consent• E Automated CRM Fi...• V Automated Exec R...• V Auto-detect Activi…..• E AI Signals & Alerts• V AJA on Anvthinal• V AI Call Scoring1 • E Jiminny MCP Con..• E Desktop app to re...› • Feedback> 4 Research & User Fee...— Create© Jira.88 TeamsQ Search across all your apps+ CreateOA 04 8 Mon20 Apr 14:00:04E ASK ROVO A O @Updated 35m ago[ Edit& [EMAIL] MCP Connector@ By Galya Dimitrova C 11 min L27 € Add a reactionEpicLink to Epik in JiraDocument statusDRAFT© ObjectiveEnable customers to connect Jiminny data to external AI tools (Claude, OpenAI, Gemini) so it can beused as part of their broader knowledge base and workflows.Position Jiminny as a data layer for AI-driven revenue workflows, not just a standalone product.& Target user• Revenue teams using AI tools (Sales, CS, RevOps)• Companies already experimenting with Claude / OpenAI• Mid-market & Enterprise customers with multiple data sources (CRM, docs, CI tools, Supporttools etc)® Pain point or problem• Jiminny data is locked in the platform• Al tools lack access to high-value conversation context• Customers must manually export/copy transcripts• No easy way to combine calls with CRM + docs + other info - using the Jiminny API is not suitablefor non technical sales people• Peer pressure as almost all competitors have this1 Twnort ond hanaf'ta...
|
NULL
|
-4446270875508079239
|
NULL
|
idle
|
ocr
|
NULL
|
FirefoxJy 19798 evaluation for ai activityJY-20553 FirefoxJy 19798 evaluation for ai activityJY-20553 | Improve crm-sync delaSRD-6793) Les Mills activity typeJY-20698 handle failed field sync•JY-20692 change confirmation pa(JY-20543) AJ Reports > Trackina(UY-18909) (Part2) Automated rep/Ask Jiminny Reports by nikolay-ya- New Tabu Product Growth Plattorm UserpilgU Userpilot I Loaaed-activity(fix(security): composer dependePipelines - jiminny/app) Feed - jiminny - Sentry8 Jiminny8Jiminnyo Jimingy(JY-20692] Issue with reconnect• Jy-20692 change confirmation pa# (UY-20692) Issue with reconnectin19 ISRD-67871 Issue with reconnect& Jiminny MCP Connector - Prod XVIewMistorbookmarksProtllesToolsWindowmelpnny.atlassian.net/wiki/spaces/PROD/pages/3728244737/Jiminny+MCP+ConnectorBookmarksO JIMINNYQ Search bookmarks$ Productv la bookmarks loolba• Sprint Board# SRD QueueGithubJiminny DEVAsk Jiminny Reports by nikolay-yankov •..© Circle CI8 PROD US> = bookmarks MenuOther Bookmarks> N 1 Back to topfor..> * Product Documentati..v 1 Product Briefsi• V Activity Export•V Autoloaaina activit….• = Deal Insiahts - Mu....• E Reinvent Themes ....• V Billina Portall• V Uoload Video/Audi...• E White-Label Jimin...• E Win/Loss Analvsis..• • Hubspot app• V Automatically hard…..• V Ask Jiminny Anyth….• V Ask .liminnv for O...• V Ask Jiminny Anyth...• V Automatically reco…• V Product Tiering• V Recording Consent• E Automated CRM Fi...• V Automated Exec R...• V Auto-detect Activi…..• E AI Signals & Alerts• V AJA on Anvthinal• V AI Call Scoring1 • E Jiminny MCP Con..• E Desktop app to re...› • Feedback> 4 Research & User Fee...— Create© Jira.88 TeamsQ Search across all your apps+ CreateOA 04 8 Mon20 Apr 14:00:04E ASK ROVO A O @Updated 35m ago[ Edit& [EMAIL] MCP Connector@ By Galya Dimitrova C 11 min L27 € Add a reactionEpicLink to Epik in JiraDocument statusDRAFT© ObjectiveEnable customers to connect Jiminny data to external AI tools (Claude, OpenAI, Gemini) so it can beused as part of their broader knowledge base and workflows.Position Jiminny as a data layer for AI-driven revenue workflows, not just a standalone product.& Target user• Revenue teams using AI tools (Sales, CS, RevOps)• Companies already experimenting with Claude / OpenAI• Mid-market & Enterprise customers with multiple data sources (CRM, docs, CI tools, Supporttools etc)® Pain point or problem• Jiminny data is locked in the platform• Al tools lack access to high-value conversation context• Customers must manually export/copy transcripts• No easy way to combine calls with CRM + docs + other info - using the Jiminny API is not suitablefor non technical sales people• Peer pressure as almost all competitors have this1 Twnort ond hanaf'ta...
|
56168
|
|
56091
|
NULL
|
0
|
2026-04-20T10:55:07.993272+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776682507993_m2.jpg...
|
Firefox
|
Firefox
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
FirefoxcalVIewhistorybookmarksProtlles1OOISWindowm FirefoxcalVIewhistorybookmarksProtlles1OOISWindowmelpinny.sentry.io/issues/?environment=production-eu&environment=production&project=82419&statsPeriod=1hRookmarksFeedJy 19798 evaluation for ai activity• Search bookmarksFeeduapp vproduction-eu, productionv1H Vis unresoivedxJY-20553 | Improve crm-sync delav a bookmarks loolbaErrors & Outages• Sorint BoardiiecueSRD-6793) Les Mills activity type→SRD QueueBreached MetricdGithubExplore• Jiminny\Exceptions\SocialAccountTokenInvalidExceptionJY-20698 handle failed field syncwarnings8 Jiminny DEV•JY-20692 change confirmation paAsk liminnv Renorts bv nikolav-vankov . ....08Your salestorce account has become disconnected. Please login to Jiminny to reconnectuser reedbackLAPP-1E15/app/Services/crm/8aseService.php in Jiminny Services crm8aseServalidateUserAccountexists0 Circle C• Jiminny \Exceptions\SocialAccountTokenInvalidException(JY-20543) AJ Reports > Trackina& PROD USAll Views> = bookmarks Menu(JY-18909] (Part2] Automated repAPP-1BY5 /app/services/crm/Baseservice.php in Jiminny\servicescrm\baseservice:validateuseraccountexistsOther BookmarksconnoureAsk Jiminny Reports by nikolay-ya- New TabJiminny (Jobs\Crm\SyncObjects has been attempted too many times(8 APP-1902 |/app/Queue/Worker/Worker.php in Jiminny\Queue\Worker\Worker:process• Elastica Exception Response Exceptionu Product Growth Plattorm Userpilgdoc| 40012153 : document missing lindey. acrivitiesite APp-1064|/aon/Comnonent/ES/ElasticSearchDocumentPartialUndater.oho inJiminnv\Comnonent\ES\ElasticSearchD• Jiminny\Component\Transcription\TranscrIntionProcessor\Gladia\Exceptions\InvalidTranslationResponseException(fix(security): composer depender(P APP-1CGE apo/ComooPipelines - jiminny/app• Jiminny\Exceptions\JobTimeoutExceptionFeed - jiminny - SentryJob timed out Jiminny Jods ACuivily syncactivityUAPP-1FP6/app/Queue8Jiminny• Symfony\Component\ErrorHandler \Error\FatalErroiAllowed memory size of 268435456 bytes exhausted (tried to allocate 10485760 bytes)(P APP-1FNJ | /app/Repositories/Crm/CrmEntityRepository.php in ?8 JiminnyJiminny\Exceptions|SocialAccountTokenInvalidExceptior(JY-20692] Issue with reconnect1 Social account for HuhSnot cannot he found. Please loain to .Jiminnv to connect• Jy-20692 change confirmation pate APp-1BV3|lann/Services/Crm/RaseService.nhn inJiminnv|Services\Crm|RaseService«validateUserAccountFxistc(JY-20692) Issue with reconnectir• Jiminny\Exceptions\EmailActivitvImportException1 [Email Import] Sailed for InboxEmail ID: 121604483: Error: Call to a member function errorû on nulitr APP-1FN8|/aop/Services/Mail/InboxService.oho in Jiminnv|Services Mail\InboxService.processEmailActivity19 ISRD-67871 Issue with reconnecti- New Tab• Jiminny\Exceptions\HttpBadRequestWithErrorReasonExceptior| Al Last Call Summary: data value too large: Call ParticipantsCustomer:Laszlo Csurka / Associate Director, Feasibility Strategy / Thermo Fisher Scientific (customer)Javier Gayo / Senior Director, Therapy Area L..CP APP-1FK8 /apo/ServiceJiminny\Exceptions\HttpBadRequestWithErrorReasonExceptioninvalid cross reterence idCP APP-19SA |/app/Services/Crm/Sailluminate Broadcacting. BroadcastSycention1 Pusher error: The data content of this event exceeds the allowed maximum (10240 bytes). See https://pusher.com/docs/channels/server_api/http-api#publishing-events for more info .e App-1002 |lann/Queue/worker/worker.nhn in Jiminnv\Queue|Worker|workervprocossLast Seen19s agoZmin agoomin ago7min ago7min ago8min adoymin adoOmin ago12min ago12min ago13min ado14min agoAge3mo10mo1wkTrendOngoingOnaoinaOngoingOngoingOngoingOngoingGecalatingRearessedOngoingOngoing24h 1hI 12TT41iT---11--40TT-26Events100% LzMon 20 Apr 13:55:07UsersLast Seen vPriorityailval val yhil val val val vSave ASAssigneePCvPcv...
|
NULL
|
-1784310222330351
|
NULL
|
visual_change
|
ocr
|
NULL
|
FirefoxcalVIewhistorybookmarksProtlles1OOISWindowm FirefoxcalVIewhistorybookmarksProtlles1OOISWindowmelpinny.sentry.io/issues/?environment=production-eu&environment=production&project=82419&statsPeriod=1hRookmarksFeedJy 19798 evaluation for ai activity• Search bookmarksFeeduapp vproduction-eu, productionv1H Vis unresoivedxJY-20553 | Improve crm-sync delav a bookmarks loolbaErrors & Outages• Sorint BoardiiecueSRD-6793) Les Mills activity type→SRD QueueBreached MetricdGithubExplore• Jiminny\Exceptions\SocialAccountTokenInvalidExceptionJY-20698 handle failed field syncwarnings8 Jiminny DEV•JY-20692 change confirmation paAsk liminnv Renorts bv nikolav-vankov . ....08Your salestorce account has become disconnected. Please login to Jiminny to reconnectuser reedbackLAPP-1E15/app/Services/crm/8aseService.php in Jiminny Services crm8aseServalidateUserAccountexists0 Circle C• Jiminny \Exceptions\SocialAccountTokenInvalidException(JY-20543) AJ Reports > Trackina& PROD USAll Views> = bookmarks Menu(JY-18909] (Part2] Automated repAPP-1BY5 /app/services/crm/Baseservice.php in Jiminny\servicescrm\baseservice:validateuseraccountexistsOther BookmarksconnoureAsk Jiminny Reports by nikolay-ya- New TabJiminny (Jobs\Crm\SyncObjects has been attempted too many times(8 APP-1902 |/app/Queue/Worker/Worker.php in Jiminny\Queue\Worker\Worker:process• Elastica Exception Response Exceptionu Product Growth Plattorm Userpilgdoc| 40012153 : document missing lindey. acrivitiesite APp-1064|/aon/Comnonent/ES/ElasticSearchDocumentPartialUndater.oho inJiminnv\Comnonent\ES\ElasticSearchD• Jiminny\Component\Transcription\TranscrIntionProcessor\Gladia\Exceptions\InvalidTranslationResponseException(fix(security): composer depender(P APP-1CGE apo/ComooPipelines - jiminny/app• Jiminny\Exceptions\JobTimeoutExceptionFeed - jiminny - SentryJob timed out Jiminny Jods ACuivily syncactivityUAPP-1FP6/app/Queue8Jiminny• Symfony\Component\ErrorHandler \Error\FatalErroiAllowed memory size of 268435456 bytes exhausted (tried to allocate 10485760 bytes)(P APP-1FNJ | /app/Repositories/Crm/CrmEntityRepository.php in ?8 JiminnyJiminny\Exceptions|SocialAccountTokenInvalidExceptior(JY-20692] Issue with reconnect1 Social account for HuhSnot cannot he found. Please loain to .Jiminnv to connect• Jy-20692 change confirmation pate APp-1BV3|lann/Services/Crm/RaseService.nhn inJiminnv|Services\Crm|RaseService«validateUserAccountFxistc(JY-20692) Issue with reconnectir• Jiminny\Exceptions\EmailActivitvImportException1 [Email Import] Sailed for InboxEmail ID: 121604483: Error: Call to a member function errorû on nulitr APP-1FN8|/aop/Services/Mail/InboxService.oho in Jiminnv|Services Mail\InboxService.processEmailActivity19 ISRD-67871 Issue with reconnecti- New Tab• Jiminny\Exceptions\HttpBadRequestWithErrorReasonExceptior| Al Last Call Summary: data value too large: Call ParticipantsCustomer:Laszlo Csurka / Associate Director, Feasibility Strategy / Thermo Fisher Scientific (customer)Javier Gayo / Senior Director, Therapy Area L..CP APP-1FK8 /apo/ServiceJiminny\Exceptions\HttpBadRequestWithErrorReasonExceptioninvalid cross reterence idCP APP-19SA |/app/Services/Crm/Sailluminate Broadcacting. BroadcastSycention1 Pusher error: The data content of this event exceeds the allowed maximum (10240 bytes). See https://pusher.com/docs/channels/server_api/http-api#publishing-events for more info .e App-1002 |lann/Queue/worker/worker.nhn in Jiminnv\Queue|Worker|workervprocossLast Seen19s agoZmin agoomin ago7min ago7min ago8min adoymin adoOmin ago12min ago12min ago13min ado14min agoAge3mo10mo1wkTrendOngoingOnaoinaOngoingOngoingOngoingOngoingGecalatingRearessedOngoingOngoing24h 1hI 12TT41iT---11--40TT-26Events100% LzMon 20 Apr 13:55:07UsersLast Seen vPriorityailval val yhil val val val vSave ASAssigneePCvPcv...
|
NULL
|
|
56089
|
NULL
|
0
|
2026-04-20T10:55:02.410703+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776682502410_m1.jpg...
|
Firefox
|
Firefox
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
iTerm2Shell|EditViewSessionScriptsProfilesWindowHe iTerm2Shell|EditViewSessionScriptsProfilesWindowHelp-zshDOCKERLast login: Mon Apr 20 13:26:00 on ttys008DEV (-zsh)O $82APP (-zsh)Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentsPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ |*3A100% <8-zshscreenpipe"Mon 20 Apr 13:55:02T81*5...
|
NULL
|
-4118744553310833969
|
NULL
|
click
|
ocr
|
NULL
|
iTerm2Shell|EditViewSessionScriptsProfilesWindowHe iTerm2Shell|EditViewSessionScriptsProfilesWindowHelp-zshDOCKERLast login: Mon Apr 20 13:26:00 on ttys008DEV (-zsh)O $82APP (-zsh)Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentsPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ |*3A100% <8-zshscreenpipe"Mon 20 Apr 13:55:02T81*5...
|
56086
|
|
56024
|
NULL
|
0
|
2026-04-20T10:49:56.621624+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776682196621_m2.jpg...
|
Firefox
|
NULL
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Slack•0 ЕlActivityMoreVIewMistonWindowHelpQ Search Slack•0 ЕlActivityMoreVIewMistonWindowHelpQ Search: shared-activiJiminny …..→ Dratts & centi¿ . Aneliya Angelova• MessagesLo Add canvasur Files8 DirectoriesEb External connections# Starred8 jiminny-x-integrati...& platform-inner-teamE Channels# ai-chapter# alertsS hackendl# confusion-clinic# curiosity_lab# engineering# frontend# general# infra-changes# jiminny-bg# platform-tickets# product launches# random# releases# support# thank-yous# the_people_of_jimi...6? Direct messagesA. Aneliya Angelova®. Galya Dimitrova M2 Stefka StovanovalR. Stoyan TomovB Aneliya Angelova,..Nikolav Nikolov& Stoyan Tanev #*. Vasil Vasilev. Nikolay IvanovP. Vesдо сега друго не сьм виждалAneliya Angelova 9:35 AMдаже не знам от кога вес е счупил деплоя и колко време все съм тествала едно и сьщо без да се усетя че деплойването не е работелоLukas Kovalik 9:36 AMThursday, April 16thAneliva Angelova 10:00 AMукаш кога искаш ла се чуемза командитеLukas Kovalik 10:01 AMаиде след 15 мин че се зарових в зохоd1Lukas Kovalk 1032AMако искаш ла се чуем сегаAneliya Angelova 10:33 AMA huddle happened 10:33 AMImkac Kovalik 40.11 AMphp artisan automated-reports --report-id 30php artisan automated-reports:send --result-id 64Aneliya Angelova 9:41 AMLukas Kovalik 10:31 AMАни след малко може да се чуемAneliya Angelova 11:27 AMнаправо звьнни когато можешLukas Kovalik 11:35 AMЗдрасти Лукаш, струва ми се, че репортите се генерират върху всички активитита със съответния Saved search bez da e dobawen filtyr za dataA huddle happened 11:35 AMYou Aneliva Angelova, and Galva Dimitrova were in the huddle for 12mli: AppsS Jira Cloud• ToastMessage Aneliva Angelova+ Дạ.Checkout sourceJY-20692-fix-integration-app-[API_KEY] JY-20692 code review suggestion EJY-20692-fix-integration-app-[API_KEY] JY-20692 code review suggestion &masterffb7934 JY-20553 | cs (Trigger eventPush Commit pushedPush Commit pushed© Push Commit pushedlaal100% S2Mon 20 AOr 13.49:001 Manage triggersStart4m agoS Trigger Pipeline= Display optionsActionsCG@&.5m ago8m agoDuration4m 3sIM 43Sim 56s18s1m 21s49S50s36s34s8m 6s1m 11s1m 21s1m 39s52s1m 12sGGOg..GGOS......
|
NULL
|
4203661635400952051
|
NULL
|
visual_change
|
ocr
|
NULL
|
Slack•0 ЕlActivityMoreVIewMistonWindowHelpQ Search Slack•0 ЕlActivityMoreVIewMistonWindowHelpQ Search: shared-activiJiminny …..→ Dratts & centi¿ . Aneliya Angelova• MessagesLo Add canvasur Files8 DirectoriesEb External connections# Starred8 jiminny-x-integrati...& platform-inner-teamE Channels# ai-chapter# alertsS hackendl# confusion-clinic# curiosity_lab# engineering# frontend# general# infra-changes# jiminny-bg# platform-tickets# product launches# random# releases# support# thank-yous# the_people_of_jimi...6? Direct messagesA. Aneliya Angelova®. Galya Dimitrova M2 Stefka StovanovalR. Stoyan TomovB Aneliya Angelova,..Nikolav Nikolov& Stoyan Tanev #*. Vasil Vasilev. Nikolay IvanovP. Vesдо сега друго не сьм виждалAneliya Angelova 9:35 AMдаже не знам от кога вес е счупил деплоя и колко време все съм тествала едно и сьщо без да се усетя че деплойването не е работелоLukas Kovalik 9:36 AMThursday, April 16thAneliva Angelova 10:00 AMукаш кога искаш ла се чуемза командитеLukas Kovalik 10:01 AMаиде след 15 мин че се зарових в зохоd1Lukas Kovalk 1032AMако искаш ла се чуем сегаAneliya Angelova 10:33 AMA huddle happened 10:33 AMImkac Kovalik 40.11 AMphp artisan automated-reports --report-id 30php artisan automated-reports:send --result-id 64Aneliya Angelova 9:41 AMLukas Kovalik 10:31 AMАни след малко може да се чуемAneliya Angelova 11:27 AMнаправо звьнни когато можешLukas Kovalik 11:35 AMЗдрасти Лукаш, струва ми се, че репортите се генерират върху всички активитита със съответния Saved search bez da e dobawen filtyr za dataA huddle happened 11:35 AMYou Aneliva Angelova, and Galva Dimitrova were in the huddle for 12mli: AppsS Jira Cloud• ToastMessage Aneliva Angelova+ Дạ.Checkout sourceJY-20692-fix-integration-app-[API_KEY] JY-20692 code review suggestion EJY-20692-fix-integration-app-[API_KEY] JY-20692 code review suggestion &masterffb7934 JY-20553 | cs (Trigger eventPush Commit pushedPush Commit pushed© Push Commit pushedlaal100% S2Mon 20 AOr 13.49:001 Manage triggersStart4m agoS Trigger Pipeline= Display optionsActionsCG@&.5m ago8m agoDuration4m 3sIM 43Sim 56s18s1m 21s49S50s36s34s8m 6s1m 11s1m 21s1m 39s52s1m 12sGGOg..GGOS......
|
NULL
|
|
56023
|
NULL
|
0
|
2026-04-20T10:49:56.515708+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776682196515_m1.jpg...
|
Firefox
|
NULL
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
iTerm2ShellEditViewSessionScriptsProfilesWindowHel iTerm2ShellEditViewSessionScriptsProfilesWindowHelpDOCKER• ₴81Last login: Mon Apr 20 13:26:00 on ttys007DEV (-zsh)O $82APP (-zsh)APP (-zsh)*3-zshPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentsPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git statusOn branch JY-20692-fix-integration-app-[API_KEY] branch is up to date with 'origin/JY-20692-fix-integration-app-[API_KEY]'.Changes not staged for commit:use"gitadd ‹file›...to updatewhat will becommitted)Cuse "git restore ‹file›...to discard changesin working directory)modified:.env.localmodified:app/Console/Commands/JiminnyDebugCommand.phpmodified:app/Http/Controllers/API/ActivityController.phpmodified:app/Jobs/Team/SyncToIntercom.phpmodified:app/Services/PlaybackService.phpmodified:config/logging.phpmodified:front-end/src/components/connect/connect.vuemodified:routes/web.phpUntracked files:Cuse "git add<file>..." to include in what will be committed).env.nikilocal.env.otherWEBHOOK_FILTERING_IMPLEMENTATION.mdapp/Console/Commands/Crm/Hubspot/SimulateWebhooksCommand.phpapp/Console/Commands/Reports/CreateMockAskJiminnyReportResultCommand.phpids.txtraw_sql_query.sqltests/Unit/Policies/CanAccessAiReportsTest.phpnochanges added to commit (use "git add" and/or "git commit -a")lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20692-fix-integration-app-[API_KEY]) $git pullremote: Enumerating objects: 21, done.remote: Counting objects: 100% (21/21),remote: Compressing objects: 100% (21/21), done.remote: Total 21 (delta 2), reused 0 (delta 0), pack-reused 0 (from 0)Unpacking objects: 100% (21/21), 4.39 KiB | 195.00 KiB/s, done.From github.com:jiminny/app12ac2f1273..ffb7934cc3master-> origin/masterAlready up todate.lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20692-fix-integration-app-[API_KEY]) $J‹ $0 lhl*4100% C47 8 Mon 20 Apr 13:49:56T₴1|screenpipe"• 85APP...
|
NULL
|
6161168711192123693
|
NULL
|
click
|
ocr
|
NULL
|
iTerm2ShellEditViewSessionScriptsProfilesWindowHel iTerm2ShellEditViewSessionScriptsProfilesWindowHelpDOCKER• ₴81Last login: Mon Apr 20 13:26:00 on ttys007DEV (-zsh)O $82APP (-zsh)APP (-zsh)*3-zshPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentsPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git statusOn branch JY-20692-fix-integration-app-[API_KEY] branch is up to date with 'origin/JY-20692-fix-integration-app-[API_KEY]'.Changes not staged for commit:use"gitadd ‹file›...to updatewhat will becommitted)Cuse "git restore ‹file›...to discard changesin working directory)modified:.env.localmodified:app/Console/Commands/JiminnyDebugCommand.phpmodified:app/Http/Controllers/API/ActivityController.phpmodified:app/Jobs/Team/SyncToIntercom.phpmodified:app/Services/PlaybackService.phpmodified:config/logging.phpmodified:front-end/src/components/connect/connect.vuemodified:routes/web.phpUntracked files:Cuse "git add<file>..." to include in what will be committed).env.nikilocal.env.otherWEBHOOK_FILTERING_IMPLEMENTATION.mdapp/Console/Commands/Crm/Hubspot/SimulateWebhooksCommand.phpapp/Console/Commands/Reports/CreateMockAskJiminnyReportResultCommand.phpids.txtraw_sql_query.sqltests/Unit/Policies/CanAccessAiReportsTest.phpnochanges added to commit (use "git add" and/or "git commit -a")lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20692-fix-integration-app-[API_KEY]) $git pullremote: Enumerating objects: 21, done.remote: Counting objects: 100% (21/21),remote: Compressing objects: 100% (21/21), done.remote: Total 21 (delta 2), reused 0 (delta 0), pack-reused 0 (from 0)Unpacking objects: 100% (21/21), 4.39 KiB | 195.00 KiB/s, done.From github.com:jiminny/app12ac2f1273..ffb7934cc3master-> origin/masterAlready up todate.lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20692-fix-integration-app-[API_KEY]) $J‹ $0 lhl*4100% C47 8 Mon 20 Apr 13:49:56T₴1|screenpipe"• 85APP...
|
NULL
|
|
55950
|
NULL
|
0
|
2026-04-20T10:45:07.805340+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776681907805_m2.jpg...
|
PhpStorm
|
PhpStorm
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
9<>>PhostormVIewINavigarecodeLaravelKerac 9<>>PhostormVIewINavigarecodeLaravelKeractorloolsWindowFV faVsco.js#11986 on JY-20692-fix-integrationC) AutomatedReportsService.ong© ReportController.php> O config.Co Tokenbullder.ong© TeamSetupController.phppip apl.ongC Team.png> M contrib> M databaseM docs.wOpportunitysynclrait.pnpV connect.vue x V Onboard.vuev D front-end> D.vscode› D.yarn<scr1pt>Qee1.methods:• _ coverage• _ node modulesintegrationApponclicko/** If all is goodrefresh the page here *_ publicwindow. Location = "/dashboard";› _ resourcesreturn:a scriptsOSrC0mockthrow new Error(saveRequest.data.message).apos*catch (error) *C assetsconsole, Loa(error):showSnackbarError(normal.izeError(error)):Loo: oricin/Jy-18908-ask-iminny-on-demandLO0 X• Chanaes & filesSide-bv-side viewerDo not ignore=env local ann@ ad47aa83 front-end/src/co9) ActivitvController nhn ann/HttnlControllers/APIconnect.vue trontsnowPoweredby: talse@.liminnvDehuaCommand nhn ann/Console/CommandsaLLowrultzoleconnectzons: talse.php logging.php config© PlaybackService.php app/Services© SyncTolntercom.php app/Jobs/Teamif (connection &e connection.disconnected l== true &s connection.connected !== false) {pnp weo.onp routestry ">Unversioned Files 8 filesconst saveRequest = await axios.post("an/vivaintearat ion-aon-connect".if (saveRequest data §§ saveRequest data.success === true) {/** If all is good refresh the page here */window. location = "dashboard".neturn:thnow now Eonon caveRequoct data meccano).} catch (error) {concale loafennon)•showSnackbarError(normalizeError(error)):= custom..og=laravel.logA SF [jiminny@localhostj4 HS_local jiminny@localhost]A console (eu)« console (PROD] XA console [STAGING]58458758959210 5%Highlight wordsdo jiminny v034 A1 A34 V62 ^select * from teams where 1d = 5561select * from automated_reports where id = 54; # 4fdd41f6-dcf0-30d0-b339-7345381b6044|indfil "nodcacti)SELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;select x tron ducomaced_reportresucts order by zo descasclcul x rkun ductorE resulus WhCKe 10 = 27271selecc * rrom aucomaced reporc resulcs wickE reporc 10 = 54-select * from opportunities where id = 7594349:scuel * rkon reams whcke name LiKe "%eS%''#711, 0%4. 1000/3 -12minnvinteqrarzondlesmauls.comselect * from playbooks where team_id = 711: # event 226147SELECT * FROM Dlavbook categoriesWHERE DLAVbooK 10 = 55151SELECT * FROM crm fields WHERE 10 = 2261471SELECT * FROM crm field values WHERE crm field 1d = 2261475CascadeRetactor ConnectionWhat happens it connection.disconnected doesn't exist?onnected is not detined on the obiect, accessing it returns undetined .if connection ll connection.disconnected z== true ll connection.connected z== false) «Let's trace with disconnected missina lie. undefinedAsk anything (HAL)Claude Oous 477 Medium100% LzMon 20 Apr 13:45:07AutomatedReportsCommandTestv+0 ..what is the connection.disconnected doesn't exist?2 differencescurrent versionshowPoweredby: talseaLLowrulrzoleconnectzons: talse.if (Iconnection ll connection.disconnected === true |I connection.connected === false) {try&const saveRequest = await axios.nostdan:/viaintearation-ann-connect"Se cenvapenuaat dete ce envapanueet, dute euecnee eee tre) f/** If all is good refresh the page here */waindow location = "dachhoandii.notunn •throw new Error(saveRequest.data.message)} catch (error) {console.log(error):showSnackbarError(normalizeError(error)):io 2 spaces...
|
NULL
|
103513685591345740
|
NULL
|
visual_change
|
ocr
|
NULL
|
9<>>PhostormVIewINavigarecodeLaravelKerac 9<>>PhostormVIewINavigarecodeLaravelKeractorloolsWindowFV faVsco.js#11986 on JY-20692-fix-integrationC) AutomatedReportsService.ong© ReportController.php> O config.Co Tokenbullder.ong© TeamSetupController.phppip apl.ongC Team.png> M contrib> M databaseM docs.wOpportunitysynclrait.pnpV connect.vue x V Onboard.vuev D front-end> D.vscode› D.yarn<scr1pt>Qee1.methods:• _ coverage• _ node modulesintegrationApponclicko/** If all is goodrefresh the page here *_ publicwindow. Location = "/dashboard";› _ resourcesreturn:a scriptsOSrC0mockthrow new Error(saveRequest.data.message).apos*catch (error) *C assetsconsole, Loa(error):showSnackbarError(normal.izeError(error)):Loo: oricin/Jy-18908-ask-iminny-on-demandLO0 X• Chanaes & filesSide-bv-side viewerDo not ignore=env local ann@ ad47aa83 front-end/src/co9) ActivitvController nhn ann/HttnlControllers/APIconnect.vue trontsnowPoweredby: talse@.liminnvDehuaCommand nhn ann/Console/CommandsaLLowrultzoleconnectzons: talse.php logging.php config© PlaybackService.php app/Services© SyncTolntercom.php app/Jobs/Teamif (connection &e connection.disconnected l== true &s connection.connected !== false) {pnp weo.onp routestry ">Unversioned Files 8 filesconst saveRequest = await axios.post("an/vivaintearat ion-aon-connect".if (saveRequest data §§ saveRequest data.success === true) {/** If all is good refresh the page here */window. location = "dashboard".neturn:thnow now Eonon caveRequoct data meccano).} catch (error) {concale loafennon)•showSnackbarError(normalizeError(error)):= custom..og=laravel.logA SF [jiminny@localhostj4 HS_local jiminny@localhost]A console (eu)« console (PROD] XA console [STAGING]58458758959210 5%Highlight wordsdo jiminny v034 A1 A34 V62 ^select * from teams where 1d = 5561select * from automated_reports where id = 54; # 4fdd41f6-dcf0-30d0-b339-7345381b6044|indfil "nodcacti)SELECT * FROM automated_report_results WHERE uuid_to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131') = uuid;select x tron ducomaced_reportresucts order by zo descasclcul x rkun ductorE resulus WhCKe 10 = 27271selecc * rrom aucomaced reporc resulcs wickE reporc 10 = 54-select * from opportunities where id = 7594349:scuel * rkon reams whcke name LiKe "%eS%''#711, 0%4. 1000/3 -12minnvinteqrarzondlesmauls.comselect * from playbooks where team_id = 711: # event 226147SELECT * FROM Dlavbook categoriesWHERE DLAVbooK 10 = 55151SELECT * FROM crm fields WHERE 10 = 2261471SELECT * FROM crm field values WHERE crm field 1d = 2261475CascadeRetactor ConnectionWhat happens it connection.disconnected doesn't exist?onnected is not detined on the obiect, accessing it returns undetined .if connection ll connection.disconnected z== true ll connection.connected z== false) «Let's trace with disconnected missina lie. undefinedAsk anything (HAL)Claude Oous 477 Medium100% LzMon 20 Apr 13:45:07AutomatedReportsCommandTestv+0 ..what is the connection.disconnected doesn't exist?2 differencescurrent versionshowPoweredby: talseaLLowrulrzoleconnectzons: talse.if (Iconnection ll connection.disconnected === true |I connection.connected === false) {try&const saveRequest = await axios.nostdan:/viaintearation-ann-connect"Se cenvapenuaat dete ce envapanueet, dute euecnee eee tre) f/** If all is good refresh the page here */waindow location = "dachhoandii.notunn •throw new Error(saveRequest.data.message)} catch (error) {console.log(error):showSnackbarError(normalizeError(error)):io 2 spaces...
|
NULL
|
|
55948
|
NULL
|
0
|
2026-04-20T10:45:06.129569+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776681906129_m1.jpg...
|
PhpStorm
|
PhpStorm
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
iTerm2ShellEditViewSessionScriptsProfilesWindowHel iTerm2ShellEditViewSessionScriptsProfilesWindowHelpO $82‹ >0 lahlAPP (-zsh)APP (-zsh)DOCKER• 881Last login: Mon Apr 20 13:26:00 on ttys007DEV (-zsh)*3-zshPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentsPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git statusOn branch JY-20692-fix-integration-app-[API_KEY] branch is up to date with 'origin/JY-20692-fix-integration-app-[API_KEY]'.Changes not staged for commit:use"gitadd ‹file›...to updatewhat will becommitted)Cuse "git restore ‹file›...to discard changesin working directory)modified:.env.localmodified:app/Console/Commands/JiminnyDebugCommand.phpmodified:app/Http/Controllers/API/ActivityController.phpmodified:app/Jobs/Team/SyncToIntercom.phpmodified:app/Services/PlaybackService.phpmodified:config/logging.phpmodified:front-end/src/components/connect/connect.vuemodified:routes/web.phpUntracked files:Cuse "git add<file>..." to include in what will be committed).env.nikilocal.env.otherWEBHOOK_FILTERING_IMPLEMENTATION.mdapp/Console/Commands/Crm/Hubspot/SimulateWebhooksCommand.phpapp/Console/Commands/Reports/CreateMockAskJiminnyReportResultCommand.phpids.txtraw_sql_query.sqltests/Unit/Policies/CanAccessAiReportsTest.phpnochanges added to commit (use "git add" and/or "git commit -a")lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20692-fix-integration-app-[API_KEY]) $git pullremote: Enumerating objects: 21, done.remote: Counting objects: 100% (21/21),remote: Compressing objects: 100% (21/21), done.remote: Total 21 (delta 2), reused 0 (delta 0), pack-reused 0 (from 0)Unpacking objects: 100% (21/21), 4.39 KiB | 195.00 KiB/s, done.From github.com:jiminny/app12ac2f1273..ffb7934cc3master-> origin/masterAlready up todate.lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20692-fix-integration-app-[API_KEY]) $J*4100% C47 8 Mon 20 Apr 13:45:06T₴1|screenpipe"*5APP...
|
NULL
|
6254863030054526713
|
NULL
|
click
|
ocr
|
NULL
|
iTerm2ShellEditViewSessionScriptsProfilesWindowHel iTerm2ShellEditViewSessionScriptsProfilesWindowHelpO $82‹ >0 lahlAPP (-zsh)APP (-zsh)DOCKER• 881Last login: Mon Apr 20 13:26:00 on ttys007DEV (-zsh)*3-zshPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentsPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parentslukas@Lukas-Kovaliks-MacBook-Pro-Jiminny~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git statusOn branch JY-20692-fix-integration-app-[API_KEY] branch is up to date with 'origin/JY-20692-fix-integration-app-[API_KEY]'.Changes not staged for commit:use"gitadd ‹file›...to updatewhat will becommitted)Cuse "git restore ‹file›...to discard changesin working directory)modified:.env.localmodified:app/Console/Commands/JiminnyDebugCommand.phpmodified:app/Http/Controllers/API/ActivityController.phpmodified:app/Jobs/Team/SyncToIntercom.phpmodified:app/Services/PlaybackService.phpmodified:config/logging.phpmodified:front-end/src/components/connect/connect.vuemodified:routes/web.phpUntracked files:Cuse "git add<file>..." to include in what will be committed).env.nikilocal.env.otherWEBHOOK_FILTERING_IMPLEMENTATION.mdapp/Console/Commands/Crm/Hubspot/SimulateWebhooksCommand.phpapp/Console/Commands/Reports/CreateMockAskJiminnyReportResultCommand.phpids.txtraw_sql_query.sqltests/Unit/Policies/CanAccessAiReportsTest.phpnochanges added to commit (use "git add" and/or "git commit -a")lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20692-fix-integration-app-[API_KEY]) $git pullremote: Enumerating objects: 21, done.remote: Counting objects: 100% (21/21),remote: Compressing objects: 100% (21/21), done.remote: Total 21 (delta 2), reused 0 (delta 0), pack-reused 0 (from 0)Unpacking objects: 100% (21/21), 4.39 KiB | 195.00 KiB/s, done.From github.com:jiminny/app12ac2f1273..ffb7934cc3master-> origin/masterAlready up todate.lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20692-fix-integration-app-[API_KEY]) $J*4100% C47 8 Mon 20 Apr 13:45:06T₴1|screenpipe"*5APP...
|
55946
|
|
55876
|
NULL
|
0
|
2026-04-20T10:40:03.194287+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776681603194_m2.jpg...
|
PhpStorm
|
PhpStorm
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormFV faVsco.jsO config> M contrib> M d PhostormFV faVsco.jsO config> M contrib> M database>D docsv Mtrontcendl>@.vscode>D.yarn>@ coverage› node_modules• Ca public_ resources0 scriptsOSrCDmock• aposD assets" connect.lessN dashboardN Dealinsiahts• errorPagesM eynort-nortalMeytension-installedM Invitation.loinConferenceM lavouti liveCoachMlckodlD loginC MeetingConsentD mobileonboard> C mocks._> O tests._IMobileApoDownload.vueOnboard.lessV Onboard vueTs useProvidersSyncState.ts1 ondemandN olavbackN olavlistsMSettinas1 sharedM SoftnhoneCoachN SvalconcN TeaminsiahtsVIewINavigarecodeLaravelKeractorJOOIS#11986 on JY-20692-fix-inte© ReportController.php= custom.log=laravel.logA SF [jiminny@localhostj4 HS_local [jiminny@localhostA console (eu)« console (PROD] XCo Tokenbullder.ong© Team.phpA console [STAGING]wOpportunitysynclrait.pnpVOnboard.vue562<scr1pt>@×1^v564methods: "1145163164areinteqratzonAvoconnectiono566showSnackharEnrord568An error occurred while preparing che page.Try refreshing, if the error persists get in touch with the Jiminny team.'.570async integrationAppOnClick@) {const integrationApp = new IntegrationAppClient(&token: this.crmlokenconst connection = awalt inteqrationApp. integration(this.localProvider.name).onennewconnectzon579576577578579580581582583alLowiultinleconnections: false.God1f Cconnection connection.disconnected === trueIl connection.connected === false) • 587banl out early onCommand gl589if (connection && connection.disconnected !== true && connection.connected !== false) { 59€trysconst saveRequest = await axios.nostd"/am:/v1//aintearation-ann-connect"593if (saveRequest.data && saveRequest.data.success === true) {/** If all is good refresh the page here */window.location = "/dashboard";throw new Error(saveRequest.data.message):} catch (error) {console.Log errorshowSnackbarError(normalizeError(error)):Tx: Autovdo jiminny v034 A1 A34 V62 ^SELECT * FROM activities WHERE id = 76822967SELECT * FROM crm_profiles WHERE user id = 15440:SELECT * FROM crm_profiles WHERE crm confiquration id = 555:SELECT * FROM crm configurationsWHERE id = 555:SELECT * FROM Sers WHERE 1d + 15440; tean, 581, gr. 15440, pL. 3811, act, FLold 262182CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,u.emansa.*,t.owner_id FROM social_accounts saJOIN users u on U.id = sa.sociable_idJOIN teams t .n<->1: on t.id = u.team_idWHERE u.team_id = 581 and sa.provider = 'salesforce';SELECT * FROM automated_report_results order by id desc;select * from features;select * from team_features where feature_id = 40›colont + fnom tonme whono id = 55/.select * from automated_reports where id = 54; # 4fdd41f6-dcf0-30d0-b339-7345381b6044• ["pdf" "podcast"]SELECT * FROM automated_report_results WHERE uuid to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131°) = uuid:select * from automated report results order by id desc:SELECT * FROM automated_report_results WHERE id = 1919)select * from automated_report results WHERE report id = 54:select * from opportunities where id = 7594349:SELECT * FROM teams WHERE name LIKE '%Les%': # 711, 692. [EMAIL] * from plavbooks where team id = 711: # event 226147SELECT * FROM plavbook categories WHERE plavbook id = 5515,SELECT * FROM crm_fields WHERE id = 226147;SELECT * FROMerm field valuesWHERE crm field id = 226147:SELECT * FPOM con confiqunations WHERE id = 699.SELECTu. emailCONCAT(u.id, CASE WHEN U.id = t.owner_id THEN ' (owner)' ELSE "• END) AS user_idsa.*t.owner_id FROM social_accounts saLIATA ucone n on nid = ca cociablo idIOTN +oamc +1ne-s1: on + id= n toam ioWHERE U.team id = 711 and sa.provider = 'salesforce' :100% S2Mon 20 Apr 13:40:02+0 ..CascadeRetactor Connectionnected valueCurrent (lez false) Suggestion (ez= true)V passesExplanation of the Reviewer's SuggestionThe reviewer is proposina an inversion pattern (also called "earlv return" or "quard clause"). Let me break down why this is better.The Core IdeaInstead of checking "is everything OK? → do the work", tlip it to "is something wrong? → bail out early", then do the work afterwardSide-ov-Side ComparisonCurrent code (nositive check)• javascriptif (connection && connection.disconnected !== true && connection.connected !== false) {trySuagested pattern (quard clause):• javascriptsuccess path - do the work (no nesting!)trytconst saveRequest = await axios.post(...):Why This Is Better1. Removes the "double negation" readability issueThe current code forces vou to mentallv parse negatives:• disconnected le= true → "disconnected is not true" → think: "so it's... connected?"• connected !== false → "connected is not false" → think: "so it's... connected?"The inverted version reads naturallydisconnected == true → "disconnected is true" v cleatconnected =r= falce →) "connected is false" v cleal2 Dracorvae tha lonca chork hahavinrAsk anvthina (&4-D< CodeClaude Onus 4.7 MediumO01.W Windsurf Toam.151•1148 charc 1 line hroakllPo 2 spaces...
|
NULL
|
4049688180471762559
|
NULL
|
click
|
ocr
|
NULL
|
PhostormFV faVsco.jsO config> M contrib> M d PhostormFV faVsco.jsO config> M contrib> M database>D docsv Mtrontcendl>@.vscode>D.yarn>@ coverage› node_modules• Ca public_ resources0 scriptsOSrCDmock• aposD assets" connect.lessN dashboardN Dealinsiahts• errorPagesM eynort-nortalMeytension-installedM Invitation.loinConferenceM lavouti liveCoachMlckodlD loginC MeetingConsentD mobileonboard> C mocks._> O tests._IMobileApoDownload.vueOnboard.lessV Onboard vueTs useProvidersSyncState.ts1 ondemandN olavbackN olavlistsMSettinas1 sharedM SoftnhoneCoachN SvalconcN TeaminsiahtsVIewINavigarecodeLaravelKeractorJOOIS#11986 on JY-20692-fix-inte© ReportController.php= custom.log=laravel.logA SF [jiminny@localhostj4 HS_local [jiminny@localhostA console (eu)« console (PROD] XCo Tokenbullder.ong© Team.phpA console [STAGING]wOpportunitysynclrait.pnpVOnboard.vue562<scr1pt>@×1^v564methods: "1145163164areinteqratzonAvoconnectiono566showSnackharEnrord568An error occurred while preparing che page.Try refreshing, if the error persists get in touch with the Jiminny team.'.570async integrationAppOnClick@) {const integrationApp = new IntegrationAppClient(&token: this.crmlokenconst connection = awalt inteqrationApp. integration(this.localProvider.name).onennewconnectzon579576577578579580581582583alLowiultinleconnections: false.God1f Cconnection connection.disconnected === trueIl connection.connected === false) • 587banl out early onCommand gl589if (connection && connection.disconnected !== true && connection.connected !== false) { 59€trysconst saveRequest = await axios.nostd"/am:/v1//aintearation-ann-connect"593if (saveRequest.data && saveRequest.data.success === true) {/** If all is good refresh the page here */window.location = "/dashboard";throw new Error(saveRequest.data.message):} catch (error) {console.Log errorshowSnackbarError(normalizeError(error)):Tx: Autovdo jiminny v034 A1 A34 V62 ^SELECT * FROM activities WHERE id = 76822967SELECT * FROM crm_profiles WHERE user id = 15440:SELECT * FROM crm_profiles WHERE crm confiquration id = 555:SELECT * FROM crm configurationsWHERE id = 555:SELECT * FROM Sers WHERE 1d + 15440; tean, 581, gr. 15440, pL. 3811, act, FLold 262182CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,u.emansa.*,t.owner_id FROM social_accounts saJOIN users u on U.id = sa.sociable_idJOIN teams t .n<->1: on t.id = u.team_idWHERE u.team_id = 581 and sa.provider = 'salesforce';SELECT * FROM automated_report_results order by id desc;select * from features;select * from team_features where feature_id = 40›colont + fnom tonme whono id = 55/.select * from automated_reports where id = 54; # 4fdd41f6-dcf0-30d0-b339-7345381b6044• ["pdf" "podcast"]SELECT * FROM automated_report_results WHERE uuid to_bin('822fa41b-afd3-43a9-a248-86b0e36f3131°) = uuid:select * from automated report results order by id desc:SELECT * FROM automated_report_results WHERE id = 1919)select * from automated_report results WHERE report id = 54:select * from opportunities where id = 7594349:SELECT * FROM teams WHERE name LIKE '%Les%': # 711, 692. [EMAIL] * from plavbooks where team id = 711: # event 226147SELECT * FROM plavbook categories WHERE plavbook id = 5515,SELECT * FROM crm_fields WHERE id = 226147;SELECT * FROMerm field valuesWHERE crm field id = 226147:SELECT * FPOM con confiqunations WHERE id = 699.SELECTu. emailCONCAT(u.id, CASE WHEN U.id = t.owner_id THEN ' (owner)' ELSE "• END) AS user_idsa.*t.owner_id FROM social_accounts saLIATA ucone n on nid = ca cociablo idIOTN +oamc +1ne-s1: on + id= n toam ioWHERE U.team id = 711 and sa.provider = 'salesforce' :100% S2Mon 20 Apr 13:40:02+0 ..CascadeRetactor Connectionnected valueCurrent (lez false) Suggestion (ez= true)V passesExplanation of the Reviewer's SuggestionThe reviewer is proposina an inversion pattern (also called "earlv return" or "quard clause"). Let me break down why this is better.The Core IdeaInstead of checking "is everything OK? → do the work", tlip it to "is something wrong? → bail out early", then do the work afterwardSide-ov-Side ComparisonCurrent code (nositive check)• javascriptif (connection && connection.disconnected !== true && connection.connected !== false) {trySuagested pattern (quard clause):• javascriptsuccess path - do the work (no nesting!)trytconst saveRequest = await axios.post(...):Why This Is Better1. Removes the "double negation" readability issueThe current code forces vou to mentallv parse negatives:• disconnected le= true → "disconnected is not true" → think: "so it's... connected?"• connected !== false → "connected is not false" → think: "so it's... connected?"The inverted version reads naturallydisconnected == true → "disconnected is true" v cleatconnected =r= falce →) "connected is false" v cleal2 Dracorvae tha lonca chork hahavinrAsk anvthina (&4-D< CodeClaude Onus 4.7 MediumO01.W Windsurf Toam.151•1148 charc 1 line hroakllPo 2 spaces...
|
55874
|
|
55875
|
NULL
|
0
|
2026-04-20T10:40:03.146293+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776681603146_m1.jpg...
|
PhpStorm
|
PhpStorm
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
iTerm2ShellEditViewSessionScriptsProfilesWindowHel iTerm2ShellEditViewSessionScriptsProfilesWindowHelp‹$0alo]100% C47 8 Mon 20 Apr 13:40:03DOCKERO ₴1id: 2DEV (-zsh)O $82screenpipe"APP (-zsh)18183-zsh₴4screenpipe"audio devicesdisabledyou are using local processing. all your data stays on your computer.warning: telemetry is enabled. only error-level data will be sent.todisable, use the --disable-telemetry flag.check latestchanges here:https://github.com/screenpipe/screenpipe/releases2026-04-20T13:38:59.324778ZINFOscreenpipe:starting UIevent capture2026-04-20T13:38:59.3405072INFO screenpipe_engine::ui_recorder: Starting UIevent capture2026-04-20113:38:59.3556532INFO screenpipe_engine::ui_recorder: UI recording session started: cfa5a9fe-27a0-4b42-b9b3-17ae7414d61f2026-04-20T13:38:59.355663ZINFOscreenpipe_engine::calendar_speaker_id: speaker identification: started (user_name=<not set>)2026-04-20113:38:59.3557532INFOscreenpipe_engine::hot_frame_cache: hot_frame_cache: warmingfrom DB(2026-04-19 10:38:59.355751 UTC to 2026-04-2010:38:59.355751 UTC)2026-04-20T13:38:59.356123Z2026-04-20T13:38:59.364631ZINFO screenpipe_engine::meeting_detector: meeting v2: detection loop started (base_interval=5s, profiles=12)INFOscreenpipe_engine::server: Server listening on [IP_ADDRESS]:30302026-04-20T13:38:59.375782Z2026-04-20T13:38:59.386372ZINFOscreenpipe_connect: :mdns: mdns: advertising screenpipe on port 3030INFOscreenpipe_engine::vision_manager::manager: Starting vision recording for monitor 1 (1440x900)2026-04-20T13:38:59.386407ZINFO2026-04-20T13:38:59.386451ZINFOscreenpipe_engine::vision_manager::manager: Starting event-driven capture for monitor 1 (device: monitor_1)2026-04-20T13:38:59.422928Zscreenpipe_engine::event_driven_capture: event-driven capture started for monitor 1 (device: monitor_1)INFOscreenpipe_engine::vision_manager::manager: Starting vision recording for monitor 2 (3008x1253)2026-04-20T13:38:59.422958ZINFO screenpipe_engine::vision_manager::manager: Starting event-driven capture for monitor 2 (device: monitor_2)2026-04-20T13:38:59.422973ZINFO2026-04-20T13:38:59.422987Zscreenpipe_engine::event_driven_capture:event-driven capture started for monitor 2 (device: monitor_2)stoppoll)INFO screenpipe_engine::vision_manager::monitor_watcher: Starting monitor watcher (event-driven via CGDisplayRegisterReconfigurationCallback, 60s back2026-04-20T13:39:00.078575ZINFO sck_rs::stream_manager:persistent SCK stream started fordisplay 1 (1440x900, 2fps, 1 excluded)2026-04-20T13:39:00.162281ZINFO sck_rs::stream_manager:persistent SCKstream started for display 2 (3008x1253,2fps, 1 excluded)2026-04-20T13:39:00.839125ZINFO screenpipe_engine::event_driven_capture:startup capture for monitor 1:frame_id=55840, dur=704ms2026-04-20T13:39:01.119865ZINFOIscreenpipe_engine::event_driven_capture:startupcapture for monitor 2:frame_id=55841, dur=890ms2026-04-20T13:39:03.438357ZWARNsalx::query:CE(\nSUBSTR(f.full_text,summary="SELECT f.id,f.timestamp,f.offset_index,db.statement="\n\nSELECT\nf.id, \nf.timestamp, \nf.offset_index, \n COALES1, 200), \nSUBSTR(f.accessibility_text,1, 200), \nE\not.frame_id = f.id\nLIMIT\n1\n)\n(\nSELECT\nSUBSTR(ot.text, 1, 200)\nFROM\nocr_text ot\nWHER)as text, inCOALESCEC\nf.app_name, \nSELECT\not.app_name\nFROM\nocr_text ot\nWHERE\not.frame_id = f.id\nLIMIT\n1\n)\n) as app_name, \n COALESCE(\nf.window_name, \n(\nSELECT\not.window_name\nFROM\nocr_text ot\nWHERE\not.frame_id = f.id\nLIMIT\n1\n)\n ) as window_name, \nCOALESCE(vc.file_path,COALESCE(vc.device_name,f.device_name) asscreen_device, \nf.snapshot_path) as video_path,\nN f.video_chunk_id = vc.id\nWHERE\nf.timestamp >=?1\nCOALESCE(vc.fps, 0.033) as chunk_fps, \nf.browser_url, \nf.machine_id\nFR0M\nframes f\nLEFT JOIN video_chunks vc 0ANDf.timestamp<= ?2\nAND COALESCE(vc.file_path,SC, \nf.offset_index DESC\nLIMIT\n10000\n'rows_affected=0 rows_returned=43332026-04-20T13:39:03.449190Zelapsed=4.081886333sf.snapshot_path,'') NOT LIKE 'cloud://%'\nORDER BY\nf.timestamp DEINFO screenpipe_engine::hot_frame_cache: hot_frame_cache: warmedwith 4333frameentries, coverage from 2026-04-19 10:38:59.355751 UTC2026-04-20T13:40:03.125129ZWARN sqlx::query:ROM\nsummary="SELECT id, snapshot_path, device_name,AND-"db.statement="\n\nSELECT\n id,\nsnapshot_path, In device_name, \ntimestamp\nfframes \nWHERE\nsnapshot_path IS NOT NULL\ntimestamp < ?1\nORDER BY\ndevice_name, \ntimestamp ASC\nLIMIT\n 5000\n" rows_affected-0 rows_returned-48 elapsed-3.803901167s2026-04-20T13:40:03.125381ZINFO screenpipe_engine::snapshot_compaction:snapshot compaction: found 48 eligible frames...
|
NULL
|
3687066965720186290
|
NULL
|
click
|
ocr
|
NULL
|
iTerm2ShellEditViewSessionScriptsProfilesWindowHel iTerm2ShellEditViewSessionScriptsProfilesWindowHelp‹$0alo]100% C47 8 Mon 20 Apr 13:40:03DOCKERO ₴1id: 2DEV (-zsh)O $82screenpipe"APP (-zsh)18183-zsh₴4screenpipe"audio devicesdisabledyou are using local processing. all your data stays on your computer.warning: telemetry is enabled. only error-level data will be sent.todisable, use the --disable-telemetry flag.check latestchanges here:https://github.com/screenpipe/screenpipe/releases2026-04-20T13:38:59.324778ZINFOscreenpipe:starting UIevent capture2026-04-20T13:38:59.3405072INFO screenpipe_engine::ui_recorder: Starting UIevent capture2026-04-20113:38:59.3556532INFO screenpipe_engine::ui_recorder: UI recording session started: cfa5a9fe-27a0-4b42-b9b3-17ae7414d61f2026-04-20T13:38:59.355663ZINFOscreenpipe_engine::calendar_speaker_id: speaker identification: started (user_name=<not set>)2026-04-20113:38:59.3557532INFOscreenpipe_engine::hot_frame_cache: hot_frame_cache: warmingfrom DB(2026-04-19 10:38:59.355751 UTC to 2026-04-2010:38:59.355751 UTC)2026-04-20T13:38:59.356123Z2026-04-20T13:38:59.364631ZINFO screenpipe_engine::meeting_detector: meeting v2: detection loop started (base_interval=5s, profiles=12)INFOscreenpipe_engine::server: Server listening on [IP_ADDRESS]:30302026-04-20T13:38:59.375782Z2026-04-20T13:38:59.386372ZINFOscreenpipe_connect: :mdns: mdns: advertising screenpipe on port 3030INFOscreenpipe_engine::vision_manager::manager: Starting vision recording for monitor 1 (1440x900)2026-04-20T13:38:59.386407ZINFO2026-04-20T13:38:59.386451ZINFOscreenpipe_engine::vision_manager::manager: Starting event-driven capture for monitor 1 (device: monitor_1)2026-04-20T13:38:59.422928Zscreenpipe_engine::event_driven_capture: event-driven capture started for monitor 1 (device: monitor_1)INFOscreenpipe_engine::vision_manager::manager: Starting vision recording for monitor 2 (3008x1253)2026-04-20T13:38:59.422958ZINFO screenpipe_engine::vision_manager::manager: Starting event-driven capture for monitor 2 (device: monitor_2)2026-04-20T13:38:59.422973ZINFO2026-04-20T13:38:59.422987Zscreenpipe_engine::event_driven_capture:event-driven capture started for monitor 2 (device: monitor_2)stoppoll)INFO screenpipe_engine::vision_manager::monitor_watcher: Starting monitor watcher (event-driven via CGDisplayRegisterReconfigurationCallback, 60s back2026-04-20T13:39:00.078575ZINFO sck_rs::stream_manager:persistent SCK stream started fordisplay 1 (1440x900, 2fps, 1 excluded)2026-04-20T13:39:00.162281ZINFO sck_rs::stream_manager:persistent SCKstream started for display 2 (3008x1253,2fps, 1 excluded)2026-04-20T13:39:00.839125ZINFO screenpipe_engine::event_driven_capture:startup capture for monitor 1:frame_id=55840, dur=704ms2026-04-20T13:39:01.119865ZINFOIscreenpipe_engine::event_driven_capture:startupcapture for monitor 2:frame_id=55841, dur=890ms2026-04-20T13:39:03.438357ZWARNsalx::query:CE(\nSUBSTR(f.full_text,summary="SELECT f.id,f.timestamp,f.offset_index,db.statement="\n\nSELECT\nf.id, \nf.timestamp, \nf.offset_index, \n COALES1, 200), \nSUBSTR(f.accessibility_text,1, 200), \nE\not.frame_id = f.id\nLIMIT\n1\n)\n(\nSELECT\nSUBSTR(ot.text, 1, 200)\nFROM\nocr_text ot\nWHER)as text, inCOALESCEC\nf.app_name, \nSELECT\not.app_name\nFROM\nocr_text ot\nWHERE\not.frame_id = f.id\nLIMIT\n1\n)\n) as app_name, \n COALESCE(\nf.window_name, \n(\nSELECT\not.window_name\nFROM\nocr_text ot\nWHERE\not.frame_id = f.id\nLIMIT\n1\n)\n ) as window_name, \nCOALESCE(vc.file_path,COALESCE(vc.device_name,f.device_name) asscreen_device, \nf.snapshot_path) as video_path,\nN f.video_chunk_id = vc.id\nWHERE\nf.timestamp >=?1\nCOALESCE(vc.fps, 0.033) as chunk_fps, \nf.browser_url, \nf.machine_id\nFR0M\nframes f\nLEFT JOIN video_chunks vc 0ANDf.timestamp<= ?2\nAND COALESCE(vc.file_path,SC, \nf.offset_index DESC\nLIMIT\n10000\n'rows_affected=0 rows_returned=43332026-04-20T13:39:03.449190Zelapsed=4.081886333sf.snapshot_path,'') NOT LIKE 'cloud://%'\nORDER BY\nf.timestamp DEINFO screenpipe_engine::hot_frame_cache: hot_frame_cache: warmedwith 4333frameentries, coverage from 2026-04-19 10:38:59.355751 UTC2026-04-20T13:40:03.125129ZWARN sqlx::query:ROM\nsummary="SELECT id, snapshot_path, device_name,AND-"db.statement="\n\nSELECT\n id,\nsnapshot_path, In device_name, \ntimestamp\nfframes \nWHERE\nsnapshot_path IS NOT NULL\ntimestamp < ?1\nORDER BY\ndevice_name, \ntimestamp ASC\nLIMIT\n 5000\n" rows_affected-0 rows_returned-48 elapsed-3.803901167s2026-04-20T13:40:03.125381ZINFO screenpipe_engine::snapshot_compaction:snapshot compaction: found 48 eligible frames...
|
NULL
|
|
55839
|
NULL
|
0
|
2026-04-20T10:20:10.411325+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776680410411_m2.jpg...
|
Music
|
Music
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Search
Apple Music
Home
Radio
Library
Recently Add Search
Apple Music
Home
Radio
Library
Recently Added
Artists
Albums
Songs
Store
iTunes Store
Playlists
All Playlists
Internet Songs
start machine
start machine
ChatLLM Teams TTS
ChatLLM Teams TTS
Call to Robinson Crusoe Nov 22 2024
Call to Robinson Crusoe Nov 22 2024
output 2
output 2
ffc1839a-520f-4619-8c06-3fc496622364
ffc1839a-520f-4619-8c06-3fc496622364
6e5cbce9-0b1e-4556-ae01-10b2e491ee17
6e5cbce9-0b1e-4556-ae01-10b2e491ee17
105f8bc8-d065-4fdd-abf6-27d8afad9513
105f8bc8-d065-4fdd-abf6-27d8afad9513
ed9e817e-f202-4d5f-b8b3-92a19fde8535
ed9e817e-f202-4d5f-b8b3-92a19fde8535
ccd1cb82-bd8a-42b4-b14e-4a446013b77b
ccd1cb82-bd8a-42b4-b14e-4a446013b77b
3ddefbad-4f8b-4647-aeaa-f89a2d4d6ff8
3ddefbad-4f8b-4647-aeaa-f89a2d4d6ff8
7cb51831-4023-4bc7-9065-20e16b1551cb
7cb51831-4023-4bc7-9065-20e16b1551cb
91d15fbe-afa7-4017-8d87-8eb13ce954e2
91d15fbe-afa7-4017-8d87-8eb13ce954e2
00aebb8f-d789-4809-b01b-151ffd7a56c6
00aebb8f-d789-4809-b01b-151ffd7a56c6
2025
Recently Added
Search
airplay
Lyrics
playing next
ChatLLM Teams TTS
not favourited
More
0:05
-0:49
previous
pause
next
shuffle
do not repeat
Mute
Full Volume...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Search","depth":7,"bounds":{"left":0.27426863,"top":1.0,"width":0.00831117,"height":-0.072625756},"role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXStaticText","text":"Apple Music","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"Home","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"Radio","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"Library","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"Recently Added","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"Artists","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"Albums","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"Songs","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"Store","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"iTunes Store","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"Playlists","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"All Playlists","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"Internet Songs","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"start machine","depth":5,"role_description":"text"},{"role":"AXStaticText","text":"ChatLLM Teams TTS","depth":5,"role_description":"text"},{"role":"AXStaticText","text":"Call to Robinson Crusoe Nov 22 2024","depth":5,"role_description":"text"},{"role":"AXStaticText","text":"output 2","depth":5,"role_description":"text"},{"role":"AXStaticText","text":"ffc1839a-520f-4619-8c06-3fc496622364","depth":5,"role_description":"text"},{"role":"AXStaticText","text":"6e5cbce9-0b1e-4556-ae01-10b2e491ee17","depth":5,"role_description":"text"},{"role":"AXStaticText","text":"105f8bc8-d065-4fdd-abf6-27d8afad9513","depth":5,"role_description":"text"},{"role":"AXStaticText","text":"ed9e817e-f202-4d5f-b8b3-92a19fde8535","depth":5,"role_description":"text"},{"role":"AXStaticText","text":"ccd1cb82-bd8a-42b4-b14e-4a446013b77b","depth":5,"role_description":"text"},{"role":"AXStaticText","text":"3ddefbad-4f8b-4647-aeaa-f89a2d4d6ff8","depth":5,"role_description":"text"},{"role":"AXStaticText","text":"7cb51831-4023-4bc7-9065-20e16b1551cb","depth":5,"role_description":"text"},{"role":"AXStaticText","text":"91d15fbe-afa7-4017-8d87-8eb13ce954e2","depth":5,"role_description":"text"},{"role":"AXStaticText","text":"00aebb8f-d789-4809-b01b-151ffd7a56c6","depth":5,"role_description":"text"},{"role":"AXStaticText","text":"2025","depth":4,"bounds":{"left":0.3570479,"top":1.0,"width":0.3863032,"height":-0.09976053},"role_description":"text"},{"role":"AXStaticText","text":"Recently Added","depth":2,"bounds":{"left":0.5269282,"top":1.0,"width":0.038896278,"height":-0.06823623},"automation_id":"pageTitle","role_description":"text"},{"role":"AXButton","text":"Search","depth":2,"bounds":{"left":0.73620343,"top":1.0,"width":0.009142287,"height":-0.06544292},"automation_id":"filterBtn","help_text":"Show Filter Field","role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXPopUpButton","text":"airplay","depth":2,"bounds":{"left":0.70977396,"top":1.0,"width":0.013962766,"height":-0.024740577},"automation_id":"ITID:4001","role_description":"pop-up button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"Lyrics","depth":2,"bounds":{"left":0.72041225,"top":1.0,"width":0.014960106,"height":-0.024740577},"automation_id":"ITID:4004","role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"playing next","depth":2,"bounds":{"left":0.73204786,"top":1.0,"width":0.014295213,"height":-0.024740577},"automation_id":"ITID:4002","role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXStaticText","text":"ChatLLM Teams TTS","depth":5,"bounds":{"left":0.5269282,"top":1.0,"width":0.038896278,"height":-0.027933002},"role_description":"text"},{"role":"AXButton","text":"not favourited","depth":5,"bounds":{"left":0.6085439,"top":1.0,"width":0.00930851,"height":-0.02513969},"role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"More","depth":5,"bounds":{"left":0.5674867,"top":1.0,"width":0.005319149,"height":-0.027533889},"role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXStaticText","text":"0:05","depth":4,"bounds":{"left":0.4742354,"top":1.0,"width":0.00930851,"height":-0.04150045},"role_description":"text"},{"role":"AXButton","text":"-0:49","depth":4,"bounds":{"left":0.60920876,"top":1.0,"width":0.00930851,"height":-0.04150045},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"previous","depth":3,"bounds":{"left":0.38231382,"top":1.0,"width":0.01462766,"height":-0.023144484},"automation_id":"ITID:3000","role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"pause","depth":3,"bounds":{"left":0.39361703,"top":1.0,"width":0.01462766,"height":-0.023144484},"automation_id":"ITID:3001","role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"next","depth":3,"bounds":{"left":0.40492022,"top":1.0,"width":0.01462766,"height":-0.023144484},"automation_id":"ITID:3002","role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"shuffle","depth":3,"bounds":{"left":0.37300533,"top":1.0,"width":0.010638298,"height":-0.027933002},"role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"do not repeat","depth":3,"bounds":{"left":0.41821808,"top":1.0,"width":0.010638298,"height":-0.027933002},"role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"Mute","depth":2,"bounds":{"left":0.64877,"top":1.0,"width":0.00731383,"height":-0.035913825},"automation_id":"ITID:4005","role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"Full Volume","depth":2,"bounds":{"left":0.67769283,"top":1.0,"width":0.007480053,"height":-0.035514712},"automation_id":"ITID:4006","role_description":"button","is_enabled":true,"is_focused":false}]...
|
3576592586790837652
|
3442958919910921403
|
idle
|
accessibility
|
NULL
|
Search
Apple Music
Home
Radio
Library
Recently Add Search
Apple Music
Home
Radio
Library
Recently Added
Artists
Albums
Songs
Store
iTunes Store
Playlists
All Playlists
Internet Songs
start machine
start machine
ChatLLM Teams TTS
ChatLLM Teams TTS
Call to Robinson Crusoe Nov 22 2024
Call to Robinson Crusoe Nov 22 2024
output 2
output 2
ffc1839a-520f-4619-8c06-3fc496622364
ffc1839a-520f-4619-8c06-3fc496622364
6e5cbce9-0b1e-4556-ae01-10b2e491ee17
6e5cbce9-0b1e-4556-ae01-10b2e491ee17
105f8bc8-d065-4fdd-abf6-27d8afad9513
105f8bc8-d065-4fdd-abf6-27d8afad9513
ed9e817e-f202-4d5f-b8b3-92a19fde8535
ed9e817e-f202-4d5f-b8b3-92a19fde8535
ccd1cb82-bd8a-42b4-b14e-4a446013b77b
ccd1cb82-bd8a-42b4-b14e-4a446013b77b
3ddefbad-4f8b-4647-aeaa-f89a2d4d6ff8
3ddefbad-4f8b-4647-aeaa-f89a2d4d6ff8
7cb51831-4023-4bc7-9065-20e16b1551cb
7cb51831-4023-4bc7-9065-20e16b1551cb
91d15fbe-afa7-4017-8d87-8eb13ce954e2
91d15fbe-afa7-4017-8d87-8eb13ce954e2
00aebb8f-d789-4809-b01b-151ffd7a56c6
00aebb8f-d789-4809-b01b-151ffd7a56c6
2025
Recently Added
Search
airplay
Lyrics
playing next
ChatLLM Teams TTS
not favourited
More
0:05
-0:49
previous
pause
next
shuffle
do not repeat
Mute
Full Volume...
|
55825
|
|
55838
|
NULL
|
0
|
2026-04-20T10:20:04.785138+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776680404785_m1.jpg...
|
Music
|
Music
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Search
Apple Music
Home
Radio
Library
Recently Add Search
Apple Music
Home
Radio
Library
Recently Added
Artists
Albums
Songs
Store
iTunes Store
Playlists
All Playlists
Internet Songs
start machine
start machine
ChatLLM Teams TTS
ChatLLM Teams TTS
Call to Robinson Crusoe Nov 22 2024
Call to Robinson Crusoe Nov 22 2024
output 2
output 2
ffc1839a-520f-4619-8c06-3fc496622364
ffc1839a-520f-4619-8c06-3fc496622364
6e5cbce9-0b1e-4556-ae01-10b2e491ee17
6e5cbce9-0b1e-4556-ae01-10b2e491ee17
105f8bc8-d065-4fdd-abf6-27d8afad9513
105f8bc8-d065-4fdd-abf6-27d8afad9513
ed9e817e-f202-4d5f-b8b3-92a19fde8535
ed9e817e-f202-4d5f-b8b3-92a19fde8535
ccd1cb82-bd8a-42b4-b14e-4a446013b77b
ccd1cb82-bd8a-42b4-b14e-4a446013b77b
3ddefbad-4f8b-4647-aeaa-f89a2d4d6ff8
3ddefbad-4f8b-4647-aeaa-f89a2d4d6ff8
7cb51831-4023-4bc7-9065-20e16b1551cb
7cb51831-4023-4bc7-9065-20e16b1551cb
91d15fbe-afa7-4017-8d87-8eb13ce954e2
91d15fbe-afa7-4017-8d87-8eb13ce954e2
00aebb8f-d789-4809-b01b-151ffd7a56c6
00aebb8f-d789-4809-b01b-151ffd7a56c6
2025
Recently Added
Search
airplay
Lyrics
playing next
start machine
not favourited
More
0:10
-0:00
previous
pause
next
shuffle
do not repeat
Mute
Full Volume...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Search","depth":7,"bounds":{"left":0.008333334,"top":0.101111114,"width":0.017361112,"height":0.024444444},"role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXStaticText","text":"Apple Music","depth":6,"bounds":{"left":0.009722223,"top":0.14666666,"width":0.14166667,"height":0.015555556},"role_description":"text"},{"role":"AXStaticText","text":"Home","depth":6,"bounds":{"left":0.03263889,"top":0.17222223,"width":0.10902778,"height":0.017777778},"role_description":"text"},{"role":"AXStaticText","text":"Radio","depth":6,"bounds":{"left":0.03263889,"top":0.20333333,"width":0.10902778,"height":0.017777778},"role_description":"text"},{"role":"AXStaticText","text":"Library","depth":6,"bounds":{"left":0.009722223,"top":0.24444444,"width":0.13263889,"height":0.015555556},"role_description":"text"},{"role":"AXStaticText","text":"Recently Added","depth":6,"bounds":{"left":0.03263889,"top":0.27,"width":0.10902778,"height":0.017777778},"role_description":"text"},{"role":"AXStaticText","text":"Artists","depth":6,"bounds":{"left":0.03263889,"top":0.3011111,"width":0.10902778,"height":0.017777778},"role_description":"text"},{"role":"AXStaticText","text":"Albums","depth":6,"bounds":{"left":0.03263889,"top":0.33222222,"width":0.10902778,"height":0.017777778},"role_description":"text"},{"role":"AXStaticText","text":"Songs","depth":6,"bounds":{"left":0.03263889,"top":0.36333334,"width":0.10902778,"height":0.017777778},"role_description":"text"},{"role":"AXStaticText","text":"Store","depth":6,"bounds":{"left":0.009722223,"top":0.40444446,"width":0.14166667,"height":0.015555556},"role_description":"text"},{"role":"AXStaticText","text":"iTunes Store","depth":6,"bounds":{"left":0.03263889,"top":0.43,"width":0.10902778,"height":0.017777778},"role_description":"text"},{"role":"AXStaticText","text":"Playlists","depth":6,"bounds":{"left":0.009722223,"top":0.47111112,"width":0.14166667,"height":0.015555556},"role_description":"text"},{"role":"AXStaticText","text":"All Playlists","depth":6,"bounds":{"left":0.03263889,"top":0.49666667,"width":0.10902778,"height":0.017777778},"role_description":"text"},{"role":"AXStaticText","text":"Internet Songs","depth":6,"bounds":{"left":0.03263889,"top":0.5277778,"width":0.10902778,"height":0.017777778},"role_description":"text"},{"role":"AXStaticText","text":"start machine","depth":5,"bounds":{"left":0.18125,"top":0.4288889,"width":0.054166667,"height":0.016666668},"role_description":"text"},{"role":"AXStaticText","text":"ChatLLM Teams TTS","depth":5,"bounds":{"left":0.34166667,"top":0.4288889,"width":0.08125,"height":0.016666668},"role_description":"text"},{"role":"AXStaticText","text":"Call to Robinson Crusoe Nov 22 2024","depth":5,"bounds":{"left":0.50208336,"top":0.4288889,"width":0.13680555,"height":0.033333335},"role_description":"text"},{"role":"AXStaticText","text":"output 2","depth":5,"bounds":{"left":0.18125,"top":0.82555556,"width":0.033333335,"height":0.016666668},"role_description":"text"},{"role":"AXStaticText","text":"ffc1839a-520f-4619-8c06-3fc496622364","depth":5,"bounds":{"left":0.34166667,"top":0.82555556,"width":0.13680555,"height":0.033333335},"role_description":"text"},{"role":"AXStaticText","text":"6e5cbce9-0b1e-4556-ae01-10b2e491ee17","depth":5,"bounds":{"left":0.50208336,"top":0.82555556,"width":0.13680555,"height":0.033333335},"role_description":"text"},{"role":"AXStaticText","text":"105f8bc8-d065-4fdd-abf6-27d8afad9513","depth":5,"bounds":{"left":0.6625,"top":0.82555556,"width":0.13680555,"height":0.033333335},"role_description":"text"},{"role":"AXStaticText","text":"ed9e817e-f202-4d5f-b8b3-92a19fde8535","depth":5,"bounds":{"left":0.8229167,"top":0.82555556,"width":0.13680555,"height":0.033333335},"role_description":"text"},{"role":"AXStaticText","text":"ccd1cb82-bd8a-42b4-b14e-4a446013b77b","depth":5,"role_description":"text"},{"role":"AXStaticText","text":"3ddefbad-4f8b-4647-aeaa-f89a2d4d6ff8","depth":5,"role_description":"text"},{"role":"AXStaticText","text":"7cb51831-4023-4bc7-9065-20e16b1551cb","depth":5,"role_description":"text"},{"role":"AXStaticText","text":"91d15fbe-afa7-4017-8d87-8eb13ce954e2","depth":5,"role_description":"text"},{"role":"AXStaticText","text":"00aebb8f-d789-4809-b01b-151ffd7a56c6","depth":5,"role_description":"text"},{"role":"AXStaticText","text":"2025","depth":4,"bounds":{"left":0.18125,"top":0.1388889,"width":0.80694443,"height":0.053333335},"role_description":"text"},{"role":"AXStaticText","text":"Recently Added","depth":2,"bounds":{"left":0.5361111,"top":0.095,"width":0.08125,"height":0.02111111},"automation_id":"pageTitle","role_description":"text"},{"role":"AXButton","text":"Search","depth":2,"bounds":{"left":0.97326386,"top":0.09111111,"width":0.019097222,"height":0.03},"automation_id":"filterBtn","help_text":"Show Filter Field","role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXPopUpButton","text":"airplay","depth":2,"bounds":{"left":0.91805553,"top":0.034444444,"width":0.029166667,"height":0.044444446},"automation_id":"ITID:4001","role_description":"pop-up button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"Lyrics","depth":2,"bounds":{"left":0.94027776,"top":0.034444444,"width":0.03125,"height":0.044444446},"automation_id":"ITID:4004","role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"playing next","depth":2,"bounds":{"left":0.96458334,"top":0.034444444,"width":0.029861111,"height":0.044444446},"automation_id":"ITID:4002","role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXStaticText","text":"start machine","depth":5,"bounds":{"left":0.54965276,"top":0.03888889,"width":0.054166667,"height":0.016666668},"role_description":"text"},{"role":"AXButton","text":"not favourited","depth":5,"bounds":{"left":0.7065972,"top":0.035,"width":0.019444445,"height":0.025555555},"role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"More","depth":5,"bounds":{"left":0.60729164,"top":0.038333334,"width":0.011111111,"height":0.017777778},"role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXStaticText","text":"0:10","depth":4,"bounds":{"left":0.42604166,"top":0.057777777,"width":0.019444445,"height":0.014444444},"role_description":"text"},{"role":"AXButton","text":"-0:00","depth":4,"bounds":{"left":0.7079861,"top":0.057777777,"width":0.019444445,"height":0.014444444},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"previous","depth":3,"bounds":{"left":0.23402777,"top":0.032222223,"width":0.030555556,"height":0.04888889},"automation_id":"ITID:3000","role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"pause","depth":3,"bounds":{"left":0.2576389,"top":0.032222223,"width":0.030555556,"height":0.04888889},"automation_id":"ITID:3001","role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"next","depth":3,"bounds":{"left":0.28125,"top":0.032222223,"width":0.030555556,"height":0.04888889},"automation_id":"ITID:3002","role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"shuffle","depth":3,"bounds":{"left":0.21458334,"top":0.03888889,"width":0.022222223,"height":0.036666665},"role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"do not repeat","depth":3,"bounds":{"left":0.3090278,"top":0.03888889,"width":0.022222223,"height":0.036666665},"role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"Mute","depth":2,"bounds":{"left":0.790625,"top":0.05,"width":0.015277778,"height":0.013333334},"automation_id":"ITID:4005","role_description":"button","is_enabled":true,"is_focused":false},{"role":"AXButton","text":"Full Volume","depth":2,"bounds":{"left":0.8510417,"top":0.049444444,"width":0.015625,"height":0.014444444},"automation_id":"ITID:4006","role_description":"button","is_enabled":true,"is_focused":false}]...
|
-7487100742487365325
|
3441766498881602975
|
idle
|
accessibility
|
NULL
|
Search
Apple Music
Home
Radio
Library
Recently Add Search
Apple Music
Home
Radio
Library
Recently Added
Artists
Albums
Songs
Store
iTunes Store
Playlists
All Playlists
Internet Songs
start machine
start machine
ChatLLM Teams TTS
ChatLLM Teams TTS
Call to Robinson Crusoe Nov 22 2024
Call to Robinson Crusoe Nov 22 2024
output 2
output 2
ffc1839a-520f-4619-8c06-3fc496622364
ffc1839a-520f-4619-8c06-3fc496622364
6e5cbce9-0b1e-4556-ae01-10b2e491ee17
6e5cbce9-0b1e-4556-ae01-10b2e491ee17
105f8bc8-d065-4fdd-abf6-27d8afad9513
105f8bc8-d065-4fdd-abf6-27d8afad9513
ed9e817e-f202-4d5f-b8b3-92a19fde8535
ed9e817e-f202-4d5f-b8b3-92a19fde8535
ccd1cb82-bd8a-42b4-b14e-4a446013b77b
ccd1cb82-bd8a-42b4-b14e-4a446013b77b
3ddefbad-4f8b-4647-aeaa-f89a2d4d6ff8
3ddefbad-4f8b-4647-aeaa-f89a2d4d6ff8
7cb51831-4023-4bc7-9065-20e16b1551cb
7cb51831-4023-4bc7-9065-20e16b1551cb
91d15fbe-afa7-4017-8d87-8eb13ce954e2
91d15fbe-afa7-4017-8d87-8eb13ce954e2
00aebb8f-d789-4809-b01b-151ffd7a56c6
00aebb8f-d789-4809-b01b-151ffd7a56c6
2025
Recently Added
Search
airplay
Lyrics
playing next
start machine
not favourited
More
0:10
-0:00
previous
pause
next
shuffle
do not repeat
Mute
Full Volume...
|
55824
|
|
55793
|
NULL
|
0
|
2026-04-20T10:09:03.216221+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776679743216_m2.jpg...
|
Firefox
|
JY-20692 change confirmation parameter by LakyLak JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app — Work...
|
True
|
github.com/jiminny/app/pull/11986
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
Jy 19798 evaluation for ai activity types by nikolaybiaivanov · Pull Request #468 · jiminny/prophet
Jy 19798 evaluation for ai activity types by nikolaybiaivanov · Pull Request #468 · jiminny/prophet
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
Close tab
[JY-20543] AJ Reports > Tracking - Jira
[JY-20543] AJ Reports > Tracking - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira
Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app
Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app
New Tab
New Tab
Product Growth Platform | Userpilot
Product Growth Platform | Userpilot
Userpilot | Logged-activity
Userpilot | Logged-activity
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
test (873154) - jiminny/app
test (873154) - jiminny/app
Feed — jiminny — Sentry
Feed — jiminny — Sentry
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Copy prompt
You said checkout to remote branch
You said
checkout to remote branch
Listen
Show more options
Show thinking
Gemini said
Gemini said
Here is the standard way to check out a remote branch in Git.
Step 1: Fetch the latest remote branches
Step 1: Fetch the latest remote branches
Before checking out, it is best practice to ensure your local repository knows about the latest branches on the remote. Run:
Bash
Copy code
git fetch
Step 2: Check out the branch
Step 2: Check out the branch
You have a few options depending on your version of Git and whether you want to use the exact same name as the remote branch.
Option A: The simplest way (Recommended)
Option A: The simplest way (Recommended)
If the remote branch exists and you don't have a local branch with the same name, Git will automatically create the local branch and set it up to track the remote one.
Using the newer
switch
command:
Bash
Copy code
git switch <branch-name>
Or using the traditional
checkout
command:
Bash
Copy code
git checkout <branch-name>
(Note: Do not include
origin/
in this command. Just use the branch name, e.g.,
git checkout feature-branch
)
Option B: The explicit way
Option B: The explicit way
If Option A doesn't work (for example, if you have multiple remotes), or if you want to give your local branch a
different name
than the remote branch, you can explicitly map them:
Bash
Copy code
git checkout -b <your-local-branch-name> origin/<remote-branch-name>
How to verify it worked
How to verify it worked
To confirm you are on the right branch and tracking the remote properly, run:
Bash
Copy code
git branch -vv
This will list your local branches, highlight your current branch, and show which remote branch it is tracking (e.g.,
[origin/<branch-name>]
).
Copy prompt
Edit
You said lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git fetch lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git checkout -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $
You said
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git fetch
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays
fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git checkout -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays
fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $
Expand
Listen
Show more options
Show thinking
Gemini said
Gemini said
Ah, it looks like just a tiny typo! You spelled
origin
as
orign
in your commands.
Git is throwing that error because it can't find a remote named "orign".
Here is the corrected command:
Bash
Copy code
git checkout -b JY-20553-debug-crm-sync-delays origin/JY-20553-debug-crm-sync-delays
An Easier Shortcut
An Easier Shortcut
Since your local branch name matches the remote branch exactly, you can actually skip the
-b
and
origin/
entirely. Git is smart enough to figure it out automatically:
Bash
Copy code
git checkout JY-20553-debug-crm-sync-delays
(Or if
co
is your alias for checkout, just
co JY-20553-debug-crm-sync-delays
will work!)
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Microphone
Your Jiminny chats aren’t used to improve our models. Gemini is AI and can make mistakes, including about people.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
Issues(g then i)
Pull requests
Repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (22)
Security and quality
(
22
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20692 change confirmation parameter #11986 Edit title
JY-20692 change confirmation parameter
#
11986
Edit title
Awaiting approval
Awaiting approval
Code
Code
Open
LakyLak
LakyLak
wants to merge 1 commit into
master
master
from
JY-20692-fix-integration-app-[API_KEY]
JY-20692-fix-integration-app-[API_KEY]
Copy head branch name to clipboard
Lines changed: 2 additions & 2 deletions
Conversation (6)
Conversation
(
6
)
Commits (1)
Commits
(
1
)
Checks (6)
Checks
(
6
)
Files changed (2)
Files changed
(
2
)
Open
JY-20692 change confirmation parameter #11986 LakyLak wants to merge 1 commit into master from JY-20692-fix-integration-app-[API_KEY] Copy head branch name to clipboard
JY-20692 change confirmation parameter
JY-20692 change confirmation parameter
#
11986
LakyLak
LakyLak
wants to merge 1 commit into
master
master
from
JY-20692-fix-integration-app-[API_KEY]
JY-20692-fix-integration-app-[API_KEY]
Copy head branch name to clipboard
Conversation
Conversation
@LakyLak
Show options
LakyLak commented 3 days ago •
LakyLak
LakyLak
commented
3 days ago
3 days ago
•
edited
edited
JIRA: JY-20692
JIRA:
JY-20692
JY-20692
Changes:
Changes:
Addresses breaking change, disconnected is replaced by connected.
Keeping disconnected for scenarios it is still used in some cases (support claims both are used)
Add or remove reactions
@LakyLak
JY-20692
JY-20692
change confirmation parameter
change confirmation parameter
12 / 13 checks OK
ad47aa8
ad47aa8
@LakyLak
LakyLak
LakyLak
requested review from
Vasil-Jiminny
Vasil-Jiminny
,
nikolay-yankov
nikolay-yankov
,
nikolaybiaivanov
nikolaybiaivanov
and
yalokin-jiminny
yalokin-jiminny
and removed request for
nikolay-yankov
nikolay-yankov
3 days ago
3 days ago
@sonarqubecloud
Show options
sonarqubecloud bot commented 3 days ago
sonarqubecloud
sonarqubecloud
bot
commented
3 days ago
3 days ago
Quality Gate Passed Quality Gate passed
Quality Gate Passed
Quality Gate passed
Issues
0 New issues
0 New issues
0 Accepted issues
0 Accepted issues
Measures
0 Security Hotspots
0 Security Hotspots
0.0% Coverage on New Code
0.0% Coverage on New Code
0.0% Duplication on New Code
0.0% Duplication on New Code
See analysis details on SonarQube Cloud
See analysis details on SonarQube Cloud
Add or remove reactions
nikolay-yankov
nikolay-yankov
nikolay-yankov
reviewed
3 days ago
3 days ago
View reviewed changes
View reviewed changes
Comment thread
front-end/src/components/connect/connect.vue
front-end/src/components/connect/connect.vue
148
148
});
149
149
150
-
if (connection && connection.disconnected
=
== false) {
150
+
if (connection && connection.disconnected
!== true && connection.connected !
== false) {
148
149
150
148
149
150
});
-
if (connection && connection.disconnected
=
== false) {
+
if (connection && connection.disconnected
!== true && connection.connected !
== false) {
Show options
@nikolay-yankov nikolay-yankov 3 days ago
nikolay-yankov
nikolay-yankov
3 days ago
3 days ago
can we simplify this by? Will it work like that?
Suggested change
150
-...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0018284575,"top":0.0518755,"width":0.07596409,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"Jy 19798 evaluation for ai activity types by nikolaybiaivanov · Pull Request #468 · jiminny/prophet","depth":4,"bounds":{"left":0.0,"top":0.09497207,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jy 19798 evaluation for ai activity types by nikolaybiaivanov · Pull Request #468 · jiminny/prophet","depth":5,"bounds":{"left":0.013297873,"top":0.10614525,"width":0.16888298,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.12769353,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.13886672,"width":0.15774602,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6793] Les Mills activity types not pulling in - Jira","depth":4,"bounds":{"left":0.0,"top":0.16041501,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6793] Les Mills activity types not pulling in - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.17158818,"width":0.09524601,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.19313647,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.20430966,"width":0.19963431,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.22585794,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.23703113,"width":0.15525267,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.2330407,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[JY-20543] AJ Reports > Tracking - Jira","depth":4,"bounds":{"left":0.0,"top":0.2585794,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20543] AJ Reports > Tracking - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.2697526,"width":0.06981383,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira","depth":4,"bounds":{"left":0.0,"top":0.29130086,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.30247405,"width":0.10688165,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.32402235,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.33519554,"width":0.12915559,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.0,"top":0.3567438,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.013297873,"top":0.367917,"width":0.014960106,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Product Growth Platform | Userpilot","depth":4,"bounds":{"left":0.0,"top":0.38946527,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Product Growth Platform | Userpilot","depth":5,"bounds":{"left":0.013297873,"top":0.40063846,"width":0.06200133,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Logged-activity","depth":4,"bounds":{"left":0.0,"top":0.42218676,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Logged-activity","depth":5,"bounds":{"left":0.013297873,"top":0.43335995,"width":0.04637633,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.45490822,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.4660814,"width":0.2052859,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"test (873154) - jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.48762968,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"test (873154) - jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.49880287,"width":0.047041222,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Feed — jiminny — Sentry","depth":4,"bounds":{"left":0.0,"top":0.5203512,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Feed — jiminny — Sentry","depth":5,"bounds":{"left":0.013297873,"top":0.53152436,"width":0.042719416,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.55307263,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.5642458,"width":0.013131649,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.5857941,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.5969673,"width":0.013131649,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.61851555,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.62968874,"width":0.013131649,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.6528332,"width":0.07413564,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.18733378,"top":0.055067837,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.19930187,"top":0.055067837,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.29039228,"top":0.103751,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08361037,"top":0.103751,"width":0.013297873,"height":0.031923383},"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09690824,"top":0.10454908,"width":0.028590426,"height":0.030327214},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.099567816,"top":0.10973663,"width":0.021941489,"height":0.020351157},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.26246676,"top":0.103751,"width":0.013297873,"height":0.031923383},"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.2757646,"top":0.103751,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":21,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said checkout to remote branch","depth":21,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"checkout to remote branch","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":26,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is the standard way to check out a remote branch in Git.","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Step 1: Fetch the latest remote branches","depth":23,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Step 1: Fetch the latest remote branches","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Before checking out, it is best practice to ensure your local repository knows about the latest branches on the remote. Run:","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bash","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy code","depth":25,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"git fetch","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Step 2: Check out the branch","depth":23,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Step 2: Check out the branch","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You have a few options depending on your version of Git and whether you want to use the exact same name as the remote branch.","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Option A: The simplest way (Recommended)","depth":23,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Option A: The simplest way (Recommended)","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the remote branch exists and you don't have a local branch with the same name, Git will automatically create the local branch and set it up to track the remote one.","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Using the newer","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"switch","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"command:","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bash","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy code","depth":25,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"git switch <branch-name>","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Or using the traditional","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"checkout","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"command:","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bash","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy code","depth":25,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"git checkout <branch-name>","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(Note: Do not include","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"origin/","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"in this command. Just use the branch name, e.g.,","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"git checkout feature-branch","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Option B: The explicit way","depth":23,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Option B: The explicit way","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If Option A doesn't work (for example, if you have multiple remotes), or if you want to give your local branch a","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"different name","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"than the remote branch, you can explicitly map them:","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bash","depth":25,"bounds":{"left":0.09358378,"top":0.0,"width":0.010804521,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy code","depth":25,"bounds":{"left":0.28507313,"top":0.0,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"git checkout -b <your-local-branch-name> origin/<remote-branch-name>","depth":25,"bounds":{"left":0.09358378,"top":0.0,"width":0.18982713,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How to verify it worked","depth":23,"bounds":{"left":0.08826463,"top":0.009177973,"width":0.21276596,"height":0.01915403},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How to verify it worked","depth":24,"bounds":{"left":0.08826463,"top":0.010774142,"width":0.060339097,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To confirm you are on the right branch and tracking the remote properly, run:","depth":24,"bounds":{"left":0.08826463,"top":0.037110932,"width":0.18550532,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bash","depth":25,"bounds":{"left":0.09358378,"top":0.122505985,"width":0.010804521,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy code","depth":25,"bounds":{"left":0.28507313,"top":0.11332801,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"git branch -vv","depth":25,"bounds":{"left":0.09358378,"top":0.12210695,"width":0.0390625,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"This will list your local branches, highlight your current branch, and show which remote branch it is tracking (e.g.,","depth":24,"bounds":{"left":0.08826463,"top":0.16560255,"width":0.21027261,"height":0.037110932},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[origin/<branch-name>]","depth":25,"bounds":{"left":0.15275931,"top":0.18754987,"width":0.061502658,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":24,"bounds":{"left":0.21625665,"top":0.18635276,"width":0.0031582448,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":21,"bounds":{"left":0.11353058,"top":0.25897846,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"bounds":{"left":0.12815824,"top":0.25897846,"width":0.013297873,"height":0.031923383},"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git fetch lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git checkout -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $","depth":21,"bounds":{"left":0.14810506,"top":0.26855546,"width":0.13696809,"height":0.11173184},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"bounds":{"left":0.079288565,"top":0.27094972,"width":0.019946808,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git fetch","depth":23,"bounds":{"left":0.14810506,"top":0.2717478,"width":0.13331117,"height":0.061053474},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays","depth":23,"bounds":{"left":0.14810506,"top":0.3387869,"width":0.13447474,"height":0.08339984},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it","depth":23,"bounds":{"left":0.14810506,"top":0.38347965,"width":0.13314494,"height":0.061053474},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git checkout -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays","depth":23,"bounds":{"left":0.14810506,"top":0.45051876,"width":0.13331117,"height":0.08339984},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it","depth":23,"bounds":{"left":0.14810506,"top":0.53990424,"width":0.13314494,"height":0.061053474},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $","depth":23,"bounds":{"left":0.14810506,"top":0.6069433,"width":0.13331117,"height":0.038707104},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"bounds":{"left":0.28507313,"top":0.26855546,"width":0.013297873,"height":0.031923383},"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Listen","depth":22,"bounds":{"left":0.29039228,"top":0.4122107,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"bounds":{"left":0.29039228,"top":0.4066241,"width":0.013297873,"height":0.031923383},"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":26,"bounds":{"left":0.1015625,"top":0.41460496,"width":0.030917553,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"bounds":{"left":0.09923537,"top":0.45610535,"width":0.0003324468,"height":0.0007980846},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"bounds":{"left":0.09923537,"top":0.45810056,"width":0.04105718,"height":0.01915403},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ah, it looks like just a tiny typo! You spelled","depth":24,"bounds":{"left":0.08826463,"top":0.46568236,"width":0.10388963,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"origin","depth":25,"bounds":{"left":0.19414894,"top":0.4668795,"width":0.016788565,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"as","depth":24,"bounds":{"left":0.21293218,"top":0.46568236,"width":0.008144947,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"orign","depth":25,"bounds":{"left":0.22307181,"top":0.4668795,"width":0.013962766,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"in your commands.","depth":24,"bounds":{"left":0.23902926,"top":0.46568236,"width":0.047041222,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Git is throwing that error because it can't find a remote named \"orign\".","depth":24,"bounds":{"left":0.08826463,"top":0.49920192,"width":0.17004654,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is the corrected command:","depth":24,"bounds":{"left":0.08826463,"top":0.53272146,"width":0.077792555,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bash","depth":25,"bounds":{"left":0.09358378,"top":0.57581806,"width":0.010804521,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy code","depth":25,"bounds":{"left":0.28507313,"top":0.5666401,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"git checkout -b JY-20553-debug-crm-sync-delays origin/JY-20553-debug-crm-sync-delays","depth":25,"bounds":{"left":0.09358378,"top":0.6177175,"width":0.23454122,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"An Easier Shortcut","depth":23,"bounds":{"left":0.08826463,"top":0.6683959,"width":0.21276596,"height":0.01915403},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"An Easier Shortcut","depth":24,"bounds":{"left":0.08826463,"top":0.669992,"width":0.04837101,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Since your local branch name matches the remote branch exactly, you can actually skip the","depth":24,"bounds":{"left":0.08826463,"top":0.6963288,"width":0.21210106,"height":0.037110932},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-b","depth":25,"bounds":{"left":0.099567816,"top":0.71827614,"width":0.0056515955,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":24,"bounds":{"left":0.10721409,"top":0.717079,"width":0.011801862,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"origin/","depth":25,"bounds":{"left":0.12101064,"top":0.71827614,"width":0.019614361,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entirely. Git is smart enough to figure it out automatically:","depth":24,"bounds":{"left":0.14261968,"top":0.717079,"width":0.13912898,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bash","depth":25,"bounds":{"left":0.09358378,"top":0.7601756,"width":0.010804521,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy code","depth":25,"bounds":{"left":0.28507313,"top":0.7509976,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"git checkout JY-20553-debug-crm-sync-delays","depth":25,"bounds":{"left":0.09358378,"top":0.802075,"width":0.1200133,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(Or if","depth":24,"bounds":{"left":0.08826463,"top":0.8455706,"width":0.013962766,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"co","depth":25,"bounds":{"left":0.104222074,"top":0.8467678,"width":0.005485372,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is your alias for checkout, just","depth":24,"bounds":{"left":0.11170213,"top":0.8455706,"width":0.07446808,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"co JY-20553-debug-crm-sync-delays","depth":25,"bounds":{"left":0.18816489,"top":0.8467678,"width":0.09208777,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"will work!)","depth":24,"bounds":{"left":0.08826463,"top":0.8455706,"width":0.20428856,"height":0.037110932},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextArea","text":"Enter a prompt for Gemini\nencrypted","depth":20,"bounds":{"left":0.09291888,"top":0.82322425,"width":0.20279256,"height":0.01915403},"value":"Enter a prompt for Gemini\nencrypted","help_text":"","role_description":"text entry area","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enter a prompt for Gemini","depth":21,"bounds":{"left":0.099567816,"top":0.46089387,"width":0.069980055,"height":0.018355945},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"encrypted","depth":21,"bounds":{"left":0.091921546,"top":0.46049482,"width":0.0066489363,"height":0.01915403},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open upload file menu","depth":20,"bounds":{"left":0.08892952,"top":0.8575419,"width":0.013297873,"height":0.031923383},"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tools","depth":18,"bounds":{"left":0.10488697,"top":0.8575419,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open mode picker","depth":20,"bounds":{"left":0.25831118,"top":0.8567438,"width":0.026097074,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pro","depth":23,"bounds":{"left":0.26363033,"top":0.86552274,"width":0.007480053,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Microphone","depth":19,"bounds":{"left":0.2864029,"top":0.8567438,"width":0.013297873,"height":0.031923383},"role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your Jiminny chats aren’t used to improve our models. Gemini is AI and can make mistakes, including about people.","depth":17,"bounds":{"left":0.0887633,"top":0.90901834,"width":0.21110372,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Your privacy & Gemini Opens in a new window","depth":17,"bounds":{"left":0.17420213,"top":0.92178774,"width":0.040226065,"height":0.012370312},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your privacy & Gemini","depth":18,"bounds":{"left":0.17420213,"top":0.92178774,"width":0.040226065,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Opens in a new window","depth":19,"bounds":{"left":0.079288565,"top":0.92098963,"width":0.043218084,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Summarize page","depth":7,"bounds":{"left":0.08494016,"top":0.95730245,"width":0.053523935,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summarize page","depth":9,"bounds":{"left":0.09059176,"top":0.96249,"width":0.042220745,"height":0.015163607},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Skip to content","depth":6,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open menu","depth":10,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Homepage (g then d)","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"jiminny","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"app","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Type","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to search","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chat with Copilot","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Open Copilot…","depth":9,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Create new...","depth":9,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Issues(g then i)","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Pull requests","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Repositories","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"You have unread notifications(g then n)","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open user navigation menu","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Repository navigation","depth":9,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repository navigation","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests (31)","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"31","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Agents","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Agents","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Wiki","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wiki","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality (22)","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":10,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review this update","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub account settings","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"JY-20692 change confirmation parameter #11986 Edit title","depth":13,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20692 change confirmation parameter","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11986","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit title","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Awaiting approval","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Awaiting approval","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Code","depth":13,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Code","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"LakyLak","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"LakyLak","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 1 commit into","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20692-fix-integration-app-token-auth-response-change","depth":16,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20692-fix-integration-app-token-auth-response-change","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 2 additions & 2 deletions","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Conversation (6)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Conversation","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"6","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Commits (1)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Commits","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Checks (6)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"6","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Files changed (2)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Files changed","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":14,"bounds":{"left":0.4644282,"top":0.0726257,"width":0.011968086,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"JY-20692 change confirmation parameter #11986 LakyLak wants to merge 1 commit into master from JY-20692-fix-integration-app-token-auth-response-change Copy head branch name to clipboard","depth":14,"bounds":{"left":0.48304522,"top":0.058260176,"width":0.2534907,"height":0.042298485},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20692 change confirmation parameter","depth":16,"bounds":{"left":0.48304522,"top":0.05865922,"width":0.09458112,"height":0.01915403},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20692 change confirmation parameter","depth":17,"bounds":{"left":0.48304522,"top":0.06304868,"width":0.09458112,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":16,"bounds":{"left":0.5802859,"top":0.06304868,"width":0.0029920214,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11986","depth":16,"bounds":{"left":0.58327794,"top":0.06304868,"width":0.012965426,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"LakyLak","depth":18,"bounds":{"left":0.48304522,"top":0.08339984,"width":0.016123671,"height":0.011971269},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"LakyLak","depth":19,"bounds":{"left":0.48304522,"top":0.08339984,"width":0.016123671,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 1 commit into","depth":18,"bounds":{"left":0.50049865,"top":0.08339984,"width":0.055352394,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":18,"bounds":{"left":0.5571808,"top":0.08180367,"width":0.018284574,"height":0.015163607},"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":19,"bounds":{"left":0.55917555,"top":0.083798885,"width":0.014295213,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":19,"bounds":{"left":0.5767952,"top":0.08339984,"width":0.00880984,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20692-fix-integration-app-token-auth-response-change","depth":19,"bounds":{"left":0.58693486,"top":0.08180367,"width":0.13597074,"height":0.015163607},"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20692-fix-integration-app-token-auth-response-change","depth":20,"bounds":{"left":0.58892953,"top":0.083798885,"width":0.13198139,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":19,"bounds":{"left":0.72423536,"top":0.07821229,"width":0.00930851,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Conversation","depth":12,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@LakyLak","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show options","depth":15,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"LakyLak commented 3 days ago •","depth":14,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"LakyLak","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"LakyLak","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"commented","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"3 days ago","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3 days ago","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"•","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"edited","depth":17,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"edited","depth":19,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"JIRA: JY-20692","depth":16,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JIRA:","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20692","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20692","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Changes:","depth":16,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Changes:","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Addresses breaking change, disconnected is replaced by connected.","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Keeping disconnected for scenarios it is still used in some cases (support claims both are used)","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add or remove reactions","depth":16,"help_text":"","role_description":"summary","subrole":"AXSummary","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"@LakyLak","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"JY-20692","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20692","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"change confirmation parameter","depth":14,"help_text":"JY-20692 change confirmation parameter","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"change confirmation parameter","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"12 / 13 checks OK","depth":14,"help_text":"","role_description":"summary","subrole":"AXSummary","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"ad47aa8","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ad47aa8","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@LakyLak","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"LakyLak","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"LakyLak","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"requested review from","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Vasil-Jiminny","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Vasil-Jiminny","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"nikolay-yankov","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"nikolay-yankov","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":",","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"nikolaybiaivanov","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"nikolaybiaivanov","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"yalokin-jiminny","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"yalokin-jiminny","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and removed request for","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"nikolay-yankov","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"nikolay-yankov","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"3 days ago","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3 days ago","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"@sonarqubecloud","depth":13,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show options","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"sonarqubecloud bot commented 3 days ago","depth":13,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"sonarqubecloud","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"sonarqubecloud","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"bot","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"commented","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"3 days ago","depth":14,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3 days ago","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Quality Gate Passed Quality Gate passed","depth":16,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"Quality Gate Passed","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Quality Gate passed","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Issues","depth":17,"bounds":{"left":0.47805852,"top":0.0,"width":0.013464096,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0 New issues","depth":17,"bounds":{"left":0.48454124,"top":0.0,"width":0.028590426,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0 New issues","depth":18,"bounds":{"left":0.48454124,"top":0.0,"width":0.028590426,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0 Accepted issues","depth":17,"bounds":{"left":0.48454124,"top":0.0,"width":0.03956117,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0 Accepted issues","depth":18,"bounds":{"left":0.48454124,"top":0.0,"width":0.03956117,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Measures","depth":17,"bounds":{"left":0.47805852,"top":0.0,"width":0.020777926,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0 Security Hotspots","depth":17,"bounds":{"left":0.48454124,"top":0.0007980846,"width":0.04288564,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0 Security Hotspots","depth":18,"bounds":{"left":0.48454124,"top":0.0007980846,"width":0.04288564,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0.0% Coverage on New Code","depth":17,"bounds":{"left":0.48454124,"top":0.017557861,"width":0.0631649,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0.0% Coverage on New Code","depth":18,"bounds":{"left":0.48454124,"top":0.017557861,"width":0.0631649,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"0.0% Duplication on New Code","depth":17,"bounds":{"left":0.48454124,"top":0.03431764,"width":0.066821806,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0.0% Duplication on New Code","depth":18,"bounds":{"left":0.48454124,"top":0.03431764,"width":0.066821806,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"See analysis details on SonarQube Cloud","depth":17,"bounds":{"left":0.47805852,"top":0.06384677,"width":0.087932184,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"See analysis details on SonarQube Cloud","depth":18,"bounds":{"left":0.47805852,"top":0.06384677,"width":0.087932184,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Add or remove reactions","depth":15,"bounds":{"left":0.47805852,"top":0.09177973,"width":0.008643617,"height":0.0207502},"help_text":"","role_description":"summary","subrole":"AXSummary","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"nikolay-yankov","depth":13,"bounds":{"left":0.4537899,"top":0.15163608,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"nikolay-yankov","depth":15,"bounds":{"left":0.48603722,"top":0.16001596,"width":0.03357713,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"nikolay-yankov","depth":16,"bounds":{"left":0.48603722,"top":0.16001596,"width":0.03357713,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"reviewed","depth":14,"bounds":{"left":0.52077794,"top":0.16001596,"width":0.020611702,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"3 days ago","depth":14,"bounds":{"left":0.54138964,"top":0.16001596,"width":0.023603724,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3 days ago","depth":16,"bounds":{"left":0.54138964,"top":0.16001596,"width":0.023603724,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"View reviewed changes","depth":14,"bounds":{"left":0.6899933,"top":0.15562649,"width":0.051030584,"height":0.022346368},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"View reviewed changes","depth":16,"bounds":{"left":0.69298536,"top":0.16081405,"width":0.04504654,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Comment thread","depth":15,"bounds":{"left":0.4886968,"top":0.19792499,"width":0.00930851,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXLink","text":"front-end/src/components/connect/connect.vue","depth":15,"bounds":{"left":0.5006649,"top":0.2019154,"width":0.10555186,"height":0.014365523},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"front-end/src/components/connect/connect.vue","depth":16,"bounds":{"left":0.5006649,"top":0.20351157,"width":0.10555186,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"148","depth":20,"bounds":{"left":0.49202126,"top":0.22905028,"width":0.00731383,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"148","depth":20,"bounds":{"left":0.5086436,"top":0.22905028,"width":0.00731383,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"});","depth":21,"bounds":{"left":0.5265958,"top":0.22905028,"width":0.026263298,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"149","depth":20,"bounds":{"left":0.49202126,"top":0.24501197,"width":0.00731383,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"149","depth":20,"bounds":{"left":0.5086436,"top":0.24501197,"width":0.00731383,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"150","depth":20,"bounds":{"left":0.49202126,"top":0.26097366,"width":0.00731383,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":21,"bounds":{"left":0.5219415,"top":0.26177174,"width":0.004654255,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if (connection && connection.disconnected","depth":21,"bounds":{"left":0.5265958,"top":0.26097366,"width":0.11502659,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":21,"bounds":{"left":0.64162236,"top":0.26097366,"width":0.002493351,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"== false) {","depth":21,"bounds":{"left":0.6441157,"top":0.26097366,"width":0.02642952,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"150","depth":20,"bounds":{"left":0.5086436,"top":0.27693537,"width":0.00731383,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+","depth":21,"bounds":{"left":0.5219415,"top":0.27773345,"width":0.004654255,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if (connection && connection.disconnected","depth":21,"bounds":{"left":0.5265958,"top":0.27693537,"width":0.11502659,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"!== true && connection.connected !","depth":21,"bounds":{"left":0.64162236,"top":0.27693537,"width":0.081615694,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"== false) {","depth":21,"bounds":{"left":0.72323805,"top":0.27693537,"width":0.02642952,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"148","depth":20,"bounds":{"left":0.49202126,"top":0.22905028,"width":0.00731383,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"149","depth":20,"bounds":{"left":0.49202126,"top":0.24501197,"width":0.00731383,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"150","depth":20,"bounds":{"left":0.49202126,"top":0.26097366,"width":0.00731383,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"148","depth":20,"bounds":{"left":0.5086436,"top":0.22905028,"width":0.00731383,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"149","depth":20,"bounds":{"left":0.5086436,"top":0.24501197,"width":0.00731383,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"150","depth":20,"bounds":{"left":0.5086436,"top":0.27693537,"width":0.00731383,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"});","depth":21,"bounds":{"left":0.5265958,"top":0.22905028,"width":0.026263298,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":21,"bounds":{"left":0.5219415,"top":0.26177174,"width":0.004654255,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if (connection && connection.disconnected","depth":21,"bounds":{"left":0.5265958,"top":0.26097366,"width":0.11502659,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":21,"bounds":{"left":0.64162236,"top":0.26097366,"width":0.002493351,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"== false) {","depth":21,"bounds":{"left":0.6441157,"top":0.26097366,"width":0.02642952,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"+","depth":21,"bounds":{"left":0.5219415,"top":0.27773345,"width":0.004654255,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"if (connection && connection.disconnected","depth":21,"bounds":{"left":0.5265958,"top":0.27693537,"width":0.11502659,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"!== true && connection.connected !","depth":21,"bounds":{"left":0.64162236,"top":0.27693537,"width":0.081615694,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"== false) {","depth":21,"bounds":{"left":0.72323805,"top":0.27693537,"width":0.02642952,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show options","depth":17,"bounds":{"left":0.7273936,"top":0.31165203,"width":0.007978723,"height":0.016759777},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"@nikolay-yankov nikolay-yankov 3 days ago","depth":16,"bounds":{"left":0.4900266,"top":0.30407023,"width":0.2293883,"height":0.031923383},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"nikolay-yankov","depth":18,"bounds":{"left":0.50199467,"top":0.31324822,"width":0.03357713,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"nikolay-yankov","depth":19,"bounds":{"left":0.50199467,"top":0.31324822,"width":0.03357713,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"3 days ago","depth":17,"bounds":{"left":0.5369016,"top":0.31165203,"width":0.023603724,"height":0.016759777},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"3 days ago","depth":19,"bounds":{"left":0.5369016,"top":0.31324822,"width":0.023603724,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"can we simplify this by? Will it work like that?","depth":18,"bounds":{"left":0.50199467,"top":0.34078214,"width":0.096409574,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Suggested change","depth":19,"bounds":{"left":0.5049867,"top":0.37589785,"width":0.03507314,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"150","depth":22,"bounds":{"left":0.50897604,"top":0.39984038,"width":0.00731383,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-","depth":22,"bounds":{"left":0.52160907,"top":0.39984038,"width":0.004654255,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
6656496235295067842
|
-2315143210708878404
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
Jy 19798 evaluation for ai activity types by nikolaybiaivanov · Pull Request #468 · jiminny/prophet
Jy 19798 evaluation for ai activity types by nikolaybiaivanov · Pull Request #468 · jiminny/prophet
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
Close tab
[JY-20543] AJ Reports > Tracking - Jira
[JY-20543] AJ Reports > Tracking - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira
Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app
Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app
New Tab
New Tab
Product Growth Platform | Userpilot
Product Growth Platform | Userpilot
Userpilot | Logged-activity
Userpilot | Logged-activity
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
test (873154) - jiminny/app
test (873154) - jiminny/app
Feed — jiminny — Sentry
Feed — jiminny — Sentry
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Copy prompt
You said checkout to remote branch
You said
checkout to remote branch
Listen
Show more options
Show thinking
Gemini said
Gemini said
Here is the standard way to check out a remote branch in Git.
Step 1: Fetch the latest remote branches
Step 1: Fetch the latest remote branches
Before checking out, it is best practice to ensure your local repository knows about the latest branches on the remote. Run:
Bash
Copy code
git fetch
Step 2: Check out the branch
Step 2: Check out the branch
You have a few options depending on your version of Git and whether you want to use the exact same name as the remote branch.
Option A: The simplest way (Recommended)
Option A: The simplest way (Recommended)
If the remote branch exists and you don't have a local branch with the same name, Git will automatically create the local branch and set it up to track the remote one.
Using the newer
switch
command:
Bash
Copy code
git switch <branch-name>
Or using the traditional
checkout
command:
Bash
Copy code
git checkout <branch-name>
(Note: Do not include
origin/
in this command. Just use the branch name, e.g.,
git checkout feature-branch
)
Option B: The explicit way
Option B: The explicit way
If Option A doesn't work (for example, if you have multiple remotes), or if you want to give your local branch a
different name
than the remote branch, you can explicitly map them:
Bash
Copy code
git checkout -b <your-local-branch-name> origin/<remote-branch-name>
How to verify it worked
How to verify it worked
To confirm you are on the right branch and tracking the remote properly, run:
Bash
Copy code
git branch -vv
This will list your local branches, highlight your current branch, and show which remote branch it is tracking (e.g.,
[origin/<branch-name>]
).
Copy prompt
Edit
You said lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git fetch lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git checkout -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $
You said
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git fetch
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays
fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git checkout -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays
fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $
Expand
Listen
Show more options
Show thinking
Gemini said
Gemini said
Ah, it looks like just a tiny typo! You spelled
origin
as
orign
in your commands.
Git is throwing that error because it can't find a remote named "orign".
Here is the corrected command:
Bash
Copy code
git checkout -b JY-20553-debug-crm-sync-delays origin/JY-20553-debug-crm-sync-delays
An Easier Shortcut
An Easier Shortcut
Since your local branch name matches the remote branch exactly, you can actually skip the
-b
and
origin/
entirely. Git is smart enough to figure it out automatically:
Bash
Copy code
git checkout JY-20553-debug-crm-sync-delays
(Or if
co
is your alias for checkout, just
co JY-20553-debug-crm-sync-delays
will work!)
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Microphone
Your Jiminny chats aren’t used to improve our models. Gemini is AI and can make mistakes, including about people.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
Issues(g then i)
Pull requests
Repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (22)
Security and quality
(
22
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20692 change confirmation parameter #11986 Edit title
JY-20692 change confirmation parameter
#
11986
Edit title
Awaiting approval
Awaiting approval
Code
Code
Open
LakyLak
LakyLak
wants to merge 1 commit into
master
master
from
JY-20692-fix-integration-app-[API_KEY]
JY-20692-fix-integration-app-[API_KEY]
Copy head branch name to clipboard
Lines changed: 2 additions & 2 deletions
Conversation (6)
Conversation
(
6
)
Commits (1)
Commits
(
1
)
Checks (6)
Checks
(
6
)
Files changed (2)
Files changed
(
2
)
Open
JY-20692 change confirmation parameter #11986 LakyLak wants to merge 1 commit into master from JY-20692-fix-integration-app-[API_KEY] Copy head branch name to clipboard
JY-20692 change confirmation parameter
JY-20692 change confirmation parameter
#
11986
LakyLak
LakyLak
wants to merge 1 commit into
master
master
from
JY-20692-fix-integration-app-[API_KEY]
JY-20692-fix-integration-app-[API_KEY]
Copy head branch name to clipboard
Conversation
Conversation
@LakyLak
Show options
LakyLak commented 3 days ago •
LakyLak
LakyLak
commented
3 days ago
3 days ago
•
edited
edited
JIRA: JY-20692
JIRA:
JY-20692
JY-20692
Changes:
Changes:
Addresses breaking change, disconnected is replaced by connected.
Keeping disconnected for scenarios it is still used in some cases (support claims both are used)
Add or remove reactions
@LakyLak
JY-20692
JY-20692
change confirmation parameter
change confirmation parameter
12 / 13 checks OK
ad47aa8
ad47aa8
@LakyLak
LakyLak
LakyLak
requested review from
Vasil-Jiminny
Vasil-Jiminny
,
nikolay-yankov
nikolay-yankov
,
nikolaybiaivanov
nikolaybiaivanov
and
yalokin-jiminny
yalokin-jiminny
and removed request for
nikolay-yankov
nikolay-yankov
3 days ago
3 days ago
@sonarqubecloud
Show options
sonarqubecloud bot commented 3 days ago
sonarqubecloud
sonarqubecloud
bot
commented
3 days ago
3 days ago
Quality Gate Passed Quality Gate passed
Quality Gate Passed
Quality Gate passed
Issues
0 New issues
0 New issues
0 Accepted issues
0 Accepted issues
Measures
0 Security Hotspots
0 Security Hotspots
0.0% Coverage on New Code
0.0% Coverage on New Code
0.0% Duplication on New Code
0.0% Duplication on New Code
See analysis details on SonarQube Cloud
See analysis details on SonarQube Cloud
Add or remove reactions
nikolay-yankov
nikolay-yankov
nikolay-yankov
reviewed
3 days ago
3 days ago
View reviewed changes
View reviewed changes
Comment thread
front-end/src/components/connect/connect.vue
front-end/src/components/connect/connect.vue
148
148
});
149
149
150
-
if (connection && connection.disconnected
=
== false) {
150
+
if (connection && connection.disconnected
!== true && connection.connected !
== false) {
148
149
150
148
149
150
});
-
if (connection && connection.disconnected
=
== false) {
+
if (connection && connection.disconnected
!== true && connection.connected !
== false) {
Show options
@nikolay-yankov nikolay-yankov 3 days ago
nikolay-yankov
nikolay-yankov
3 days ago
3 days ago
can we simplify this by? Will it work like that?
Suggested change
150
-...
|
55791
|
|
55792
|
NULL
|
0
|
2026-04-20T10:08:57.927997+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776679737927_m1.jpg...
|
PhpStorm
|
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Undo
Redo
Cut
Copy
Paste
Paste and Match Style
Sel Undo
Redo
Cut
Copy
Paste
Paste and Match Style
Select All
Open DevTools...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Undo","depth":5,"bounds":{"left":0.0,"top":0.0,"width":0.065972224,"height":0.024444444},"role_description":"text"},{"role":"AXStaticText","text":"Redo","depth":5,"bounds":{"left":0.0,"top":0.0,"width":0.065972224,"height":0.024444444},"role_description":"text"},{"role":"AXStaticText","text":"Cut","depth":5,"bounds":{"left":0.0,"top":0.0,"width":0.065972224,"height":0.024444444},"role_description":"text"},{"role":"AXStaticText","text":"Copy","depth":5,"bounds":{"left":0.0,"top":0.0,"width":0.065972224,"height":0.024444444},"role_description":"text"},{"role":"AXStaticText","text":"Paste","depth":5,"bounds":{"left":0.0,"top":0.0,"width":0.065972224,"height":0.024444444},"role_description":"text"},{"role":"AXStaticText","text":"Paste and Match Style","depth":5,"bounds":{"left":0.0,"top":0.0,"width":0.065972224,"height":0.024444444},"role_description":"text"},{"role":"AXStaticText","text":"Select All","depth":5,"bounds":{"left":0.0,"top":0.0,"width":0.065972224,"height":0.024444444},"role_description":"text"},{"role":"AXStaticText","text":"Open DevTools","depth":5,"bounds":{"left":0.0,"top":0.0,"width":0.065972224,"height":0.024444444},"role_description":"text"}]...
|
4445374797877545977
|
7802338930891525294
|
click
|
hybrid
|
NULL
|
Undo
Redo
Cut
Copy
Paste
Paste and Match Style
Sel Undo
Redo
Cut
Copy
Paste
Paste and Match Style
Select All
Open DevTools
iTerm2ShellEditViewSessionScriptsProfilesWindowHelpAPP (-zsh)‹$0ffmpeg100% [8 Mon 20 Apr 13:08:57DOCKERO 81DEV (docker)Loadedconfig default from ".php-cs-fixer.dist.php".5603/5603100%882APP (-zsh)1) app/Http/Controllers/API/V2/AskJiminnyReportsController.php (single_quote)begin diff/home/jiminny/app/Http/Controllers/API/V2/AskJiminnyReportsController.php+++/home/jiminny/app/Http/Controllers/API/V2/AskJiminnyReportsController.php-89,7 +89,7 0*/public function update(Request Srequest, string Suuid): JsonResponse\Illuminate|Support\Facades\Log::channel('custom_channel')->info("UPDATE");\Illuminate\Support\Facades\Log::channel('custom_channel')->info('UPDATE');/** @var User Suser */Suser = Srequest->user();-zsh• 84-zsh₴6APPend diffFixed 1 of 5603 files in 42.363 seconds, 60.00 MB memory usedWhat's next:Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1Learn moreat [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git fetchlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delaysfatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays'cannot be created from itlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git checkout -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delaysfatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays'cannot be created from itlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git checkout -b JY-20553-debug-crm-sync-delays origin/JY-20553-debug-crm-sync-delaysM.env.localapp/Console/Commands/JiminnyDebugCommand.phpapp/Http/Controllers/API/ActivityController.phpapp/Jobs/Team/SyncToIntercom.phpMapp/Services/PlaybackService.phpconfig/logging.phproutes/web.phpbranch 'JY-20553-debug-crm-sync-delays' set up to track'origin/JY-20553-debug-crm-sync-delays'.Switched to a new branch 'JY-20553-debug-crm-sync-delays'lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-20553-debug-crm-sync-delays) $ |...
|
NULL
|
|
55724
|
NULL
|
0
|
2026-04-20T10:03:39.939415+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776679419939_m1.jpg...
|
PhpStorm
|
faVsco.js – AskJiminnyReportActivityServiceTest.ph faVsco.js – AskJiminnyReportActivityServiceTest.php...
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Services\Kiosk\AutomatedReports;
use Carbon\CarbonImmutable;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityActualDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityUpdatedDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\DealInsights\ClosingPeriodFilter;
use Jiminny\Component\ActivitySearch\FilterDefinitionCollection;
use Jiminny\Component\ActivitySearch\Service\ActivitySearch;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\Activity\SearchFilter;
use Jiminny\Models\User;
use Jiminny\Repositories\ElasticActivityRepository;
use Jiminny\Services\Kiosk\AutomatedReports\AskJiminnyReportActivityService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\VO\Repository\OnDemandActivitySearch\Criteria;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
class AskJiminnyReportActivityServiceTest extends TestCase
{
private ActivitySearch&MockObject $activitySearch;
private ElasticActivityRepository&MockObject $elasticRepository;
private LoggerInterface&MockObject $logger;
private AskJiminnyReportActivityService $service;
protected function setUp(): void
{
$this->activitySearch = $this->createMock(ActivitySearch::class);
$this->elasticRepository = $this->createMock(ElasticActivityRepository::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->service = new AskJiminnyReportActivityService(
$this->activitySearch,
$this->elasticRepository,
$this->logger,
);
}
private function makeFilter(string $key, ?string $value): SearchFilter&MockObject
{
$filter = $this->createMock(SearchFilter::class);
$filter->method('getFilterProperty')->willReturn($key);
$filter->method('getFilterValue')->willReturn($value);
return $filter;
}
private function makeUser(): User&MockObject
{
$tz = new \DateTimeZone('UTC');
$user = $this->createMock(User::class);
$user->method('getTimezone')->willReturn($tz);
$user->method('getId')->willReturn(1);
$user->method('getUuid')->willReturn('user-uuid');
return $user;
}
private function makeSavedSearch(array $filters): Search&MockObject
{
$savedSearch = $this->createMock(Search::class);
$savedSearch->method('getId')->willReturn(42);
$savedSearch->method('getFilters')->willReturn(new \Illuminate\Support\LazyCollection($filters));
return $savedSearch;
}
public function testGetActivityIdsForSavedSearchReturnsIds(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->expects($this->once())
->method('getArrayFilterKeys')
->with($user)
->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->expects($this->once())
->method('onDemandSearchIdsOnly')
->willReturn(['id-1', 'id-2', 'id-3']);
$this->logger->expects($this->once())
->method('info')
->with('[AskJiminnyReport] Fetched activity IDs for saved search');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1', 'id-2', 'id-3'], $result);
}
public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->expects($this->once())->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEmpty($result);
}
public function testGetActivityIdsFiltersOutDateFilters(): void
{
$user = $this->makeUser();
$nonDateFilter = $this->makeFilter('owner_id', '123');
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');
$updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');
$updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');
$savedSearch = $this->makeSavedSearch([
$nonDateFilter,
$startDateFilter,
$endDateFilter,
$updatedFromFilter,
$updatedToFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
}
public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void
{
$user = $this->makeUser();
$closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');
$closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');
$regularFilter = $this->makeFilter('rep_id', '99');
$savedSearch = $this->makeSavedSearch([
$closingStartFilter,
$closingEndFilter,
$regularFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesArrayFilters(): void
{
$user = $this->makeUser();
$filter1 = $this->makeFilter('outcome', 'positive');
$filter2 = $this->makeFilter('outcome', 'negative');
$savedSearch = $this->makeSavedSearch([$filter1, $filter2]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesScalarFilters(): void
{
$user = $this->makeUser();
$filter = $this->makeFilter('direction', 'inbound');
$savedSearch = $this->makeSavedSearch([$filter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-5'], $result);
}
public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
$this->assertFalse($capturedCriteria->isFirstRequest());
}
public function testGetActivityIdsLogsWithCorrectContext(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);
$this->logger->expects($this->once())
->method('info')
->with(
'[AskJiminnyReport] Fetched activity IDs for saved search',
$this->callback(fn ($context) => $context['saved_search_id'] === 42
&& $context['user_id'] === 1
&& $context['activity_count'] === 2)
);
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
}
public static function frequencyDateRangeProvider(): array
{
$now = CarbonImmutable::parse('2025-06-16 12:00:00');
return [
'daily' => [
AutomatedReportsService::FREQUENCY_DAILY,
$now->subDay()->startOfDay()->format('Y-m-d H:i:s'),
$now->subDay()->endOfDay()->format('Y-m-d H:i:s'),
],
'weekly' => [
AutomatedReportsService::FREQUENCY_WEEKLY,
$now->subWeek()->startOfWeek()->format('Y-m-d H:i:s'),
$now->subWeek()->endOfWeek()->format('Y-m-d H:i:s'),
],
'monthly' => [
AutomatedReportsService::FREQUENCY_MONTHLY,
$now->subMonthNoOverflow()->startOfMonth()->format('Y-m-d H:i:s'),
$now->subMonthNoOverflow()->endOfMonth()->format('Y-m-d H:i:s'),
],
'quarterly' => [
AutomatedReportsService::FREQUENCY_QUARTERLY,
$now->subQuarterNoOverflow()->startOfQuarter()->format('Y-m-d H:i:s'),
$now->subQuarterNoOverflow()->endOfQuarter()->format('Y-m-d H:i:s'),
],
];
}
/**
* @dataProvider frequencyDateRangeProvider
*/
public function testGetActivityIdsInjectsDateRangeForFrequency(
string $frequency,
string $expectedStartDate,
string $expectedEndDate,
): void {
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);
$this->assertNotNull($capturedCriteria);
$this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void
{
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');
$savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);
$this->assertNotNull($capturedCriteria);
$this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
27
9
23
3
105
Previous Highlighted Error
Next Highlighted Error
SELECT * FROM team_features where team_id = 1;
SELECT * FROM teams WHERE name LIKE '%Vixio%'; # 340,270,11922
SELECT * FROM users WHERE team_id = 340; # 12015
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 340
and sa.provider = 'salesforce';
# and sa.provider = 'salesloft';
select * from crm_fields where crm_configuration_id = 270 and object_type = 'event';
# 125558 - Event Type - Event_Type__c
# 125552 - Event Status - Event_Status__c
SELECT * FROM sidekick_settings WHERE team_id = 340;
SELECT * FROM crm_field_values WHERE crm_field_id in (125552);
select * from activities where crm_configuration_id = 270
and type = 'conference' and crm_provider_id IS NOT NULL
and actual_start_time > '2024-09-16 09:00:00' order by scheduled_start_time;
SELECT * FROM activities WHERE id = 20871677;
SELECT * FROM crm_field_data WHERE activity_id = 20871677;
select * from crm_layouts where crm_configuration_id = 270;
select * from crm_layout_entities where crm_layout_id in (886,887);
SELECT * FROM crm_configurations WHERE id = 270;
select * from playbooks where team_id = 340; # 1514
select * from groups where team_id = 340;
SELECT * FROM crm_fields WHERE id IN (125393, 125401);
select g.name as 'team name', p.name as 'playbook name', f.label as 'activity type field' from groups g
join playbooks p on g.playbook_id = p.id
join crm_fields f on p.activity_field_id = f.id
where g.team_id = 340;
SELECT * FROM activities WHERE uuid_to_bin('0c180357-67d2-419e-a8c3-b832a3490770') = uuid; # 20448716
select * from crm_field_data where object_id = 20448716;
select * from activities where crm_configuration_id = 270 and provider = 'salesloft' order by id desc;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%CybSafe%'; # 343,273,12008
select * from opportunities where team_id = 343;
select * from opportunities where team_id = 343 and crm_provider_id = '18099102526';
select * from opportunities where team_id = 343 and account_id = 945217482;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 343
and sa.provider = 'hubspot';
select * from accounts where team_id = 343 order by name asc;
select * from stages where crm_configuration_id = 273 and type = 'opportunity';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Voyado%'; # 353,283,12143
SELECT * FROM activities WHERE crm_configuration_id = 283 and account_id = 3777844 order by id desc;
SELECT * FROM accounts WHERE team_id = 353 AND name LIKE '%Salesloft%';
SELECT * FROM activities WHERE id = 20717903;
select * from participants where activity_id IN (20929172,20928605,20928468,20926272,20926271,20926270,20926269,20916499,20916454,20916436,20916435,20900015,20900014,20900013,20897312,20897243,20897241,20897237,20897232,20897229,20893648,20893231,20893230,20893229,20893228,20889784,20885039,20885038,20885037,20885036,20885035,20882728,20882708,20882703,20882702,20869828,20869811,20869806,20869801,20869799,20869798,20869796,20869795,20869794,20869761,20869760,20869759,20868688,20868687,20850340,20847195,20841710,20833967,20827021,20825307,20825305,20825297,20824615,20824400,20823927,20821760,20795588,20794233,20794057,20793710,20785811,20781789,20781394,20781307,20762651,20758453,20758282,20757323,20756643,20756636,20756629,20756627,20756606,20756605,20756604,20756603,20756602,20756600,20756599,20756598,20756595,20756594,20756589,20756587,20756577,20756573,20748918,20748386,20748385,20748384,20748383,20748382,20748381,20748380,20748379,20748377,20748375,20748373,20743301,20717905,20717904,20717903,20717901,20717899);
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 353
and sa.provider = 'salesforce';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%modern world business solutions%'; # 345,275,12016, [EMAIL]
SELECT * FROM activities WHERE uuid_to_bin('3921d399-3fef-4609-a291-b0097a166d43') = uuid;
# id: 20940638, user: 12022, contact: 5305871
SELECT * FROM activity_summary_logs WHERE activity_id = 20940638;
select * from contacts where team_id = 345 and crm_provider_id = '30891432415' order by name asc; # 5305871
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 345
and sa.provider = 'hubspot';
select * from users where team_id = 345 and id = 12022;
SELECT * FROM crm_profiles WHERE user_id = 12022;
SELECT * FROM participants WHERE activity_id = 20940638;
SELECT * FROM users u
JOIN crm_profiles cp ON u.id = cp.user_id
WHERE u.team_id = 345;
select * from contacts where team_id = 345 and crm_provider_id = '30880813535' order by name desc; # 5305871
select * from team_features where team_id = 345;
SELECT * FROM activities WHERE uuid_to_bin('11701e2d-2f82-4dab-a616-1db4fad238df') = uuid; # 21115197
SELECT * FROM participants WHERE activity_id = 20897406;
SELECT * FROM activities WHERE uuid_to_bin('63ba55cd-1abc-447d-83da-0137000005b7') = uuid; # 20953912
SELECT * FROM activities WHERE crm_configuration_id = 275 and provider = 'ringcentral' and title like '%1252629100%';
SELECT * FROM activities WHERE id = 20946641;
SELECT * FROM crm_profiles WHERE user_id = 10211;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Lunio%'; # 120,97,10984, [EMAIL]
SELECT * FROM opportunities WHERE crm_configuration_id = 97 and crm_provider_id = '006N1000006c5PpIAI';
select * from stages where crm_configuration_id = 97 and type = 'opportunity';
select * from opportunities where team_id = 120;
select * from crm_configurations crm join teams t on crm.id = t.crm_id
where 1=1
AND t.current_billing_plan IS NOT NULL
AND crm.auto_sync_activity = 0
and crm.provider = 'hubspot';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Exclaimer%'; # 270,205,10053,[EMAIL]
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 270
and sa.provider = 'salesforce';
SELECT * FROM activities WHERE uuid_to_bin('b54df794-2a9a-4957-8d80-09a600ead5f8') = uuid; # 21637956
SELECT * FROM crm_profiles WHERE user_id = 11446;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Cygnetise%'; # 372,300,12554, [EMAIL]
select * from playbooks where team_id = 372;
select * from crm_fields where crm_configuration_id = 300 and object_type = 'event'; # 141340
SELECT * FROM crm_field_values WHERE crm_field_id = 141340;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 372
and sa.provider = 'salesforce';
select * from crm_profiles where crm_configuration_id = 300;
SELECT * FROM crm_configurations WHERE team_id = 372;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Planday%'; # 291,242,11501,[EMAIL]
SELECT * FROM opportunities WHERE team_id = 291 and crm_provider_id = '006bG000005DO86QAG'; # 3207756
select * from crm_field_data where object_id = 3207756;
SELECT * FROM crm_fields WHERE id = 111834;
select f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value
FROM crm_fields f
JOIN crm_field_data fd ON f.id = fd.crm_field_id
WHERE f.crm_configuration_id = 242
AND f.object_type = 'opportunity'
AND fd.object_id IN (3207756)
ORDER BY fd.object_id, fd.updated_at;
SELECT * FROM crm_configurations WHERE auto_connect = 1;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Tour%'; # 187,209,8150,[EMAIL]
select * from group_deal_risk_types drgt join groups g on drgt.group_id = g.id
where g.team_id = 187;
select * from `groups` where team_id = 187;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 187
and sa.provider = 'salesforce';
# Destination - 98870 - Destination__c
# Stage - 79014 - StageName
# Land Arrangement - 98856 - Land_Arrangement__c
# Flight - 98848 - Flight__c
# Last activity date - 98812 - LastActivityDate
# Last modified date - 98809 - LastModifiedDate
# Last inbound mail timestamp - 99151 - Last_Inbound_Mail_Timestamp__c
# next call - 98864 - Next_Call__c
select * from crm_fields where crm_configuration_id = 209 and object_type = 'opportunity';
SELECT * FROM crm_layouts WHERE crm_configuration_id = 209;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 682;
select * from opportunities where team_id = 187 and name LIKE'%Muriel Sal%';
select * from opportunities where team_id = 187 and user_id = 9951 and is_closed = 0;
select * from activities where opportunity_id = 3538248;
SELECT * FROM crm_profiles WHERE user_id = 8150;
select * from deal_risks where opportunity_id = 3538248;
select * from teams where crm_id IS NULL;
SELECT opp.id AS opportunity_id,
u.group_id AS group_id,
MAX(
CASE
WHEN a.type IN ("sms-inbound", "sms-outbound") THEN a.created_at
ELSE a.actual_end_time
END) as last_date
FROM opportunities opp
left join activities a on a.opportunity_id = opp.id
inner join users u on opp.user_id = u.id
where opp.user_id IN (9951)
AND opp.is_closed = 0
and a.status IN ('completed', 'received', 'delivered') OR a.status IS NULL
group by opp.id;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Cybsafe%'; # 343,301,12008,[EMAIL]
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 343
and sa.provider = 'hubspot';
SELECT * FROM crm_profiles WHERE crm_configuration_id = 301;
SELECT * FROM contacts WHERE id = 6612363;
SELECT * FROM accounts WHERE id = 4235676;
SELECT * FROM opportunities WHERE crm_configuration_id = 301 and crm_provider_id = 32983784868;
select * from opportunity_stages where opportunity_id = 4503759;
# SELECT * FROM opportunities WHERE id = 4569937;
select * from activities where crm_configuration_id = 301;
SELECT * FROM activities WHERE uuid_to_bin('d3b2b28b-c3d0-4c2d-8ed0-eef42855278a') = uuid; # 26330370
SELECT * FROM participants WHERE activity_id = 26330370;
SELECT * FROM teams WHERE id = 375;
select * from playbooks where team_id = 375;
select * from stages where crm_configuration_id = 301 and type = 'opportunity';
select * from teams;
select * from contact_roles;
SELECT * FROM opportunities WHERE team_id = 343 and user_id = 12871 and close_date >= '2024-11-01';
select * from users u join crm_profiles cp on cp.user_id = u.id where u.team_id = 343;
SELECT * FROM crm_field_data WHERE object_id = 3771706;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 343
and sa.provider = 'hubspot';
SELECT * FROM crm_fields WHERE crm_configuration_id = 301 and object_type = 'opportunity'
and crm_provider_id LIKE "%traffic_light%";
SELECT * FROM crm_field_values WHERE crm_field_id IN (144020,144048,144111,144113,144126,144481,144508,144531);
SELECT fd.* FROM opportunities o
JOIN crm_field_data fd ON o.id = fd.object_id
WHERE o.team_id = 343
# and o.user_id IS NOT NULL
and fd.crm_field_id IN (144020,144048,144111,144113,144126,144481,144508,144531)
and fd.value != ''
order by value desc
# group by o.id
;
SELECT * FROM opportunities WHERE id = 3769843;
SELECT * FROM teams WHERE name LIKE '%Tour%'; # 187,209,8150, [EMAIL]
SELECT * FROM crm_layouts WHERE crm_configuration_id = 209;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 682;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Funding Circle%'; # 220,177,8603,[EMAIL]
SELECT * FROM activities WHERE uuid_to_bin('7a40e99b-3b37-4bb1-b983-325b81801c01') = uuid; # 23139839
SELECT * FROM opportunities WHERE id = 3855992;
SELECT * FROM users WHERE name LIKE '%Angus Pollard%'; # 8988
SELECT * FROM teams WHERE name LIKE '%Story Terrace%'; # 379, 307, 12894
SELECT * FROM crm_fields WHERE crm_configuration_id = 307 and object_type != 'opportunity';
select * from contacts where team_id = 379 and name like '%bebro%'; # 5874411, crm: 77229348507
SELECT * FROM crm_field_data WHERE object_id = 5874411;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 379
and sa.provider = 'hubspot';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%mentio%'; # 117, 94, 6371, [EMAIL]
SELECT * FROM activities WHERE uuid_to_bin('82939311-1af0-4506-8546-21e8d1fdf2c1') = uuid;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Tourlane%'; # 187, 209, 8150, [EMAIL]
SELECT * FROM opportunities WHERE team_id = 187 and crm_provider_id = '006Se000008xfvNIAQ'; # 3537793
select * from generic_ai_prompts where subject_id = 3537793;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Lunio%'; # 120, 97, 10984, [EMAIL]
SELECT * FROM crm_configurations WHERE id = 97;
SELECT * FROM crm_layouts WHERE crm_configuration_id = 97;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 355;
SELECT * FROM crm_fields WHERE id = 32682;
select cfd.value, o.* from opportunities o
join crm_field_data cfd on o.id = cfd.object_id and cfd.crm_field_id = 32682
where team_id = 120
and cfd.value != ''
;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 120
and sa.provider = 'salesforce';
select * from opportunities where team_id = 120 and crm_provider_id = '006N1000007X8MAIA0';
SELECT * FROM crm_field_data WHERE object_id = 2313439;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE id = 410;
SELECT * FROM teams WHERE name LIKE '%Local Business Oxford%';
select * from scorecards where team_id = 410;
select * from scorecard_rules;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Funding%'; # 220, 177, 8603, [EMAIL]
select * from activities a
join opportunities o on a.opportunity_id = o.id
join users u on o.user_id = u.id
where a.crm_configuration_id = 177 and a.type LIKE '%email-out%'
# and a.actual_end_time > '2024-12-16 00:00:00'
# and o.remotely_created_at > '2024-12-01 00:00:00'
# and u.group_id = 1014
and u.id = 9021
order by a.id desc;
SELECT * FROM opportunities WHERE id in (3981384,4017346);
SELECT * FROM users WHERE team_id = 220 and id IN (8775, 11435);
select * from users where id = 9021;
select * from inboxes where user_id = 9021;
select * from inbox_emails where inbox_id = 1349 and email_date > '2024-12-18 00:00:00';
select * from email_messages where team_id = 220
and orig_date > '2024-12-16 00:00:00' and orig_date < '2024-12-19 00:00:00'
and subject LIKE '%Personal%'
# and 'from' = '[EMAIL]'
;
select * from activities a
join opportunities o on a.opportunity_id = o.id
where a.user_id = 9021 and a.type LIKE '%email-out%'
and a.actual_end_time > '2024-12-18 00:00:00'
and o.user_id IS NOT NULL
and o.remotely_created_at > '2024-12-01 00:00:00'
order by a.id desc;
SELECT * FROM opportunities WHERE team_id = 220 and name LIKE '%Right Car move Limited%' and id = 3966852;
select * from activities where crm_configuration_id = 177 and type LIKE '%email%' and opportunity_id = 3966852 order by id desc;
select * from team_settings where name IN ('useCloseDate');
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Hurree%'; # 104, 81, 6175, [EMAIL]
SELECT * FROM opportunities WHERE team_id = 104 and name = 'PropOp';
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 104
and sa.provider = 'hubspot';
select * from crm_configurations where last_synced_at > '2025-01-19 01:00:00'
select * from teams where crm_id IS NULL;
select t.name as 'team', u.name as 'owner', u.email, u.phone
from teams t
join activity_providers ap on t.id = ap.team_id
join users u on t.owner_id = u.id
where 1=1
and t.status = 'active'
and ap.is_enabled = 1
# and u.status = 1
and ap.provider = 'ms-teams';
select * from crm_configurations where provider = 'bullhorn'; # 344
SELECT * FROM teams WHERE id = 442; # 14293
select * from users where team_id = 442;
select * from social_accounts sa where sa.sociable_id = 14293;
select * from invitations where team_id = 442;
# [PASSWORD_DOTS]
SELECT * FROM users WHERE email LIKE '%[EMAIL]%'; # 14022
SELECT * FROM teams WHERE id = 429;
select * from opportunities where team_id = 429 and crm_provider_id IN (16157415775, 22246219645);
select * from activities where opportunity_id in (4340436,4353519);
select * from transcription where activity_id IN (25630961,25381771);
select * from generic_ai_prompts where subject_id IN (4353519);
SELECT
a.id as activity_id,
a.opportunity_id,
a.type as activity_type,
a.language,
CONCAT(a.title, a.description) AS mail_content,
e.from AS mail_from,
e.to AS mail_to,
e.subject AS mail_subject,
e.body AS mail_body,
p.type as prompt_type,
p.status as prompt_status,
p.content AS prompt_content,
a.actual_start_time as created_at
FROM activities a
LEFT JOIN ai_prompts p ON a.transcription_id = p.transcription_id AND p.deleted_at IS NULL
LEFT JOIN email_messages e ON a.id = e.activity_id
WHERE a.actual_start_time > '2024-01-01 00:00:00'
AND a.opportunity_id IN (4353519)
AND a.status IN ('completed', 'received', 'delivered')
AND a.deleted_at IS NULL
AND a.type NOT IN ('sms-inbound', 'sms-outbound')
ORDER BY a.opportunity_id ASC, a.id ASC;
SELECT * FROM users WHERE name LIKE '%George Fierstone%'; # 14293
SELECT * FROM teams WHERE id = 442;
SELECT * FROM crm_configurations WHERE id = 344;
select * from team_features where team_id = 442;
select * from groups where team_id = 442;
select * from playbooks where team_id = 442;
select * from playbook_categories where playbook_id = 1729;
select * from crm_fields where crm_configuration_id = 344 and id = 172024;
SELECT * FROM crm_field_values WHERE crm_field_id = 172024;
select * from crm_layouts where crm_configuration_id = 344;
select * from playbook_layouts where playbook_id = 1729;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Learning%'; # 260, 221, 9444
select s.*
# , s.sent_at, u.name, a.*
from activity_summary_logs s
inner join activities a on a.id = s.activity_id
inner join users u on u.id = a.user_id
where a.crm_configuration_id = 356
and s.sent_at > date_sub(now(), interval 60 day)
order by a.actual_end_time desc;
select * from activities a
# inner join activity_summary_logs s on s.activity_id = a.id
where a.crm_configuration_id = 356 and a.actual_end_time > date_sub(now(), interval 60 day)
# and a.crm_provider_id is not null
# and provider <> 'ringcentral'
and status = 'completed'
order by a.actual_end_time desc;
select * from teams order by id desc; # 17328, 32, 17830, [EMAIL]
SELECT * FROM users;
SELECT * FROM users where team_id = 260 and status = 1; # 201 - 150 active
SELECT * FROM teams WHERE id = 260;
select * from team_settings where team_id = 260;
select * from crm_configurations where team_id = 260;
SELECT * FROM crm_layouts WHERE crm_configuration_id = 356;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 1184;
select * from accounts where crm_configuration_id = 221 order by id desc; # 7000
select * from leads where crm_configuration_id = 221 order by id desc; # 0
select * from contacts where crm_configuration_id = 221 order by id desc; # 200 000
select * from opportunities where crm_configuration_id = 221 order by id desc; # 0
select * from crm_profiles where crm_configuration_id = 221 order by id desc; # 23
select * from crm_fields where crm_configuration_id = 221;
select * from crm_field_values where crm_field_id = 5302 order by id desc;
select * from crm_layouts where crm_configuration_id = 221 order by id desc;
select * from stages where crm_configuration_id = 221 order by id desc;
select * from accounts where crm_configuration_id = 356 order by id desc; # 7000
select * from leads where crm_configuration_id = 356 order by id desc; # 0
select * from contacts where crm_configuration_id = 356 order by id desc; # 200 000
select * from opportunities where crm_configuration_id = 356 order by id desc; # 0
select * from crm_profiles where crm_configuration_id = 356 order by id desc; # 23
select * from crm_fields where crm_configuration_id = 356;
select * from crm_field_values where crm_field_id = 5302 order by id desc;
select * from crm_layouts where crm_configuration_id = 356 order by id desc;
select * from stages where crm_configuration_id = 356 order by id desc;
select * from playbooks where team_id = 260 order by id desc; # 4 (2 deleted)
select * from groups where team_id = 260 order by id desc; # 27 groups, (2 deleted)
select * from playbook_layouts where playbook_id IN (1410,1409,1276,1254); # 4
select ce.* from calendars c
join users u on c.user_id = u.id
join calendar_events ce on c.id = ce.calendar_id
where u.team_id = 260
and (ce.start_time > '2025-02-21 00:00:00')
;
# calendar events 1207
#
select * from opportunities where team_id = 260;
SELECT * FROM crm_field_data WHERE object_id = 4696496;
select * from activities where crm_configuration_id = 356 and crm_provider_id IS NOT NULL;
select * from activities where crm_configuration_id IN (221) and provider NOT IN ('ms-teams', 'uploader', 'zoom-bot')
# and type = 'conference' and status = 'scheduled' and activities.is_internal = 0
and created_at > '2024-03-01 00:00:00'
order by id desc; # 880 000, ringcentral, avaya
SELECT * FROM participants WHERE activity_id = 26371744;
# all activities 942 000 +
# conference 7385 - scheduled 984 - external 343
select * from activities where id = 26321812;
select * from participants where activity_id = 26321812;
select * from participants where activity_id in (26414510,26414514,26414516,26414604,26414653,26414655);
select * from leads where id in (720428,689175,731546,645866,621037);
select * from users where id = 13841;
select * from opportunities where user_id = 9541;
select * from stages where id = 15900;
select * from accounts where
# id IN (4160055,5053725,4965303,4896434)
id in (4584518,3249934,3218025,3891133,3399450,4172999,4485161,3101785,4587203,3070816,2870343,2870341,3563940,4550846,3424464,3249963,2870342)
;
select * from activities where id = 26654935;
SELECT * FROM opportunities WHERE id = 4803458;
SELECT * FROM opportunities where team_id = 260 and user_id = 13841 AND stage_id = 15900;
SELECT id, uuid, provider, type, lead_id, account_id, contact_id, opportunity_id, stage_id, status, recording_state, title, actual_start_time, actual_end_time
FROM activities WHERE user_id = 13841 AND opportunity_id IN (4729783, 4731717, 4731726, 4732064, 4732849, 4803458, 4813213);
SELECT DISTINCT
o.id, o.stage_id, s.name, a.title,
a.*
FROM activities a
# INNER JOIN tracks t ON a.id = t.activity_id
INNER JOIN users u ON a.user_id = u.id
INNER JOIN teams team ON u.team_id = team.id
INNER JOIN groups g ON u.group_id = g.id
INNER JOIN opportunities o ON a.opportunity_id = o.id
INNER JOIN stages s ON o.stage_id = s.id
WHERE
a.crm_configuration_id = 356
AND a.status IN ('completed', 'failed')
AND a.recording_state != 'stopped'
# and a.user_id = 13841
AND u.uuid = uuid_to_bin('6f40e4b8-c340-4059-b4ac-1728e87ea99e')
AND team.uuid = uuid_to_bin('a607fba7-452e-4683-b2af-00d6cb52c93c')
AND g.uuid = uuid_to_bin('b5d69e40-24a0-4c16-810b-5fa462299f94')
AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')
# AND t.type IN ('audio', 'video')
AND (
(a.actual_start_time BETWEEN '2025-03-13 00:00:00' AND '2025-03-18 07:59:59')
OR
(
a.actual_start_time IS NULL
AND a.type IN ('sms-outbound', 'sms-inbound')
AND a.created_at BETWEEN '2025-03-13 00:00:00' AND '2025-03-18 07:59:59'
)
)
AND (
a.is_private = 0
OR (
a.is_private = 1
AND u.uuid = uuid_to_bin('6f40e4b8-c340-4059-b4ac-1728e87ea99e')
)
)
AND (
# s.id = 15900
s.uuid = uuid_to_bin('04ca1c26-c666-4268-a129-419c0acffd73')
OR s.uuid IS NULL -- Include records without opportunity stage
)
ORDER BY a.actual_end_time DESC;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Lead Forensics%'; # 190, 162, 8474, [EMAIL]
SELECT * FROM users WHERE team_id = 190;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 190
and sa.provider = 'hubspot';
select * from role_user where user_id = 8474;
select * from crm_configurations where provider = 'bullhorn';
SELECT * FROM opportunities WHERE uuid_to_bin('94578249-65ec-4205-90f2-7d1a7d5ab64a') = uuid;
SELECT * FROM users WHERE uuid_to_bin('26dbadeb-926f-4150-b11b-771b9d4c2f9a') = uuid;
SELECT * FROM opportunities WHERE id = 4732493;
select * from activities where opportunity_id = 4732493;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE id = 443; # 358, 14315, [EMAIL]
SELECT * FROM opportunities WHERE team_id = 443;
SELECT a.id, a.type, a.user_id, a.status, a.deleted_at, u.name, u.email, u.team_id as activity_team_id, u.status, u.deleted_at, t.name, t.status, s.team_id as stage_team_id
FROM activities AS a
JOIN stages AS s ON a.stage_id = s.id
JOIN users AS u ON u.id = a.user_id
JOIN teams AS t ON t.id = s.team_id
WHERE u.team_id <> s.team_id and t.id > 135;
SELECT
crm_configuration_id,
crm_provider_id,
COUNT(*) as duplicate_count,
GROUP_CONCAT(id) as stage_ids,
GROUP_CONCAT(name) as stage_names
FROM stages
GROUP BY crm_configuration_id, crm_provider_id
HAVING COUNT(*) > 1
ORDER BY duplicate_count DESC;
select * from stages where id IN (14898,14907);
select * from business_processes;
SELECT *
FROM crm_configurations
WHERE team_id IN (
SELECT team_id
FROM crm_configurations
GROUP BY team_id
HAVING COUNT(*) > 1
)
ORDER BY team_id;
SELECT *
FROM teams
WHERE crm_id IN (
SELECT crm_id
FROM teams
GROUP BY crm_id
HAVING COUNT(*) > 1
)
ORDER BY crm_id;
# [PASSWORD_DOTS]
select * from crm_configurations where provider = 'integration-app';
SELECT * FROM teams WHERE id = 443; # Correre Naturale 358 14315 [EMAIL]
select * from activities where crm_configuration_id = 358 order by actual_end_time desc;
select id, uuid, actual_end_time, crm_provider_id, is_internal, playbook_category_id, type, user_id, lead_id, contact_id, account_id, opportunity_id, status, title from activities where crm_configuration_id = 358 order by actual_end_time desc;
select * from team_features where team_id = 358;
select * from activity_summary_logs;
select * from teams where id = 406;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Sportfive%'; # 267, 202, 14637, [EMAIL]
select * from activities where crm_configuration_id = 202 order by actual_end_time desc;
SELECT * FROM users where id = 14637;
SELECT * FROM teams where id = 267;
SELECT * FROM groups where id = 1118;
select g.name, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled_start_time, a.scheduled_end_time, a.actual_start_time, a.actual_end_time from activities a
inner join users u on u.id = a.user_id
inner join groups g on g.id = u.group_id
where a.crm_configuration_id = 202
and a.is_internal = 0
and (a.scheduled_start_time between '2025-03-19 00:00:00' and '2025-03-21 00:00:00')
and a.type = 'conference'
and a.status != 'completed'
and a.external_id is not null
order by a.scheduled_start_time desc;
SELECT * FROM activities
WHERE crm_configuration_id = 202
AND status IN ('completed', 'failed')
AND recording_state != 'stopped'
AND type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')
AND (is_private = 0 OR user_id = 14637)
AND (
(
actual_start_time BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'
) OR (
actual_start_time IS NULL
AND type IN ('sms-outbound', 'sms-inbound')
AND created_at BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'
)
)
AND NOT EXISTS (
SELECT 1
FROM tracks
WHERE
tracks.activity_id = activities.id
AND tracks.type IN ('audio', 'video')
)
ORDER BY actual_end_time DESC;
SELECT DISTINCT
a.*
FROM activities a
INNER JOIN tracks t ON a.id = t.activity_id
INNER JOIN users u ON a.user_id = u.id
INNER JOIN teams team ON u.team_id = team.id
WHERE
a.crm_configuration_id = 202
AND a.status IN ('completed', 'failed')
AND a.recording_state != 'stopped'
# and a.user_id = 14637
AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')
# AND t.type IN ('audio', 'video')
AND (
(a.actual_start_time BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59')
OR
(
a.actual_start_time IS NULL
AND a.type IN ('sms-outbound', 'sms-inbound')
AND a.created_at BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'
)
)
AND (
a.is_private = 0
OR (
a.is_private = 1
AND a.user_id = 14637
)
)
ORDER BY a.actual_end_time DESC
;
SELECT DISTINCT a.*
FROM activities a
INNER JOIN users u ON a.user_id = u.id
INNER JOIN teams t ON u.team_id = t.id
# INNER JOIN tracks tr ON a.id = tr.activity_id
# INNER JOIN groups g ON u.group_id = g.id
WHERE 1=1
AND t.id = 267
# AND t.uuid = uuid_to_bin('aed4927b-f1ea-499e-94c3-83762fd233e8')
AND a.status IN ('completed', 'failed')
AND a.recording_state != 'stopped'
AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')
# AND tr.type NOT IN ('audio', 'video')
AND (
a.is_private = 0
OR a.user_id = 14637
)
AND (
(a.actual_start_time BETWEEN '2025-03-19 00:00:00' AND '2025-03-21 23:59:59')
OR (
a.actual_start_time IS NULL
AND a.type IN ('sms-outbound', 'sms-inbound')
AND a.created_at BETWEEN '2025-03-19 00:00:00' AND '2025-03-21 23:59:59'
)
)
# and NOT EXISTS (
# SELECT 1
# FROM tracks t
# WHERE t.activity_id = a.id
# AND t.type IN ('audio', 'video')
# )
ORDER BY a.actual_end_time DESC;
SELECT * FROM tracks WHERE activity_id = 26485995;
select a.is_private, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11894 on JY-18909-automated-reports-ask-jiminny, menu","depth":5,"help_text":"Pull request #11894 exists for current branch JY-18909-automated-reports-ask-jiminny","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.016666668,"height":0.02111111},"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.016666668,"height":0.02111111},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.025555555},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.014583333,"height":0.025555555},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Services\\Kiosk\\AutomatedReports;\n\nuse Carbon\\CarbonImmutable;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityActualDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityUpdatedDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\DealInsights\\ClosingPeriodFilter;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionCollection;\nuse Jiminny\\Component\\ActivitySearch\\Service\\ActivitySearch;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\Activity\\SearchFilter;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\ElasticActivityRepository;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AskJiminnyReportActivityService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\VO\\Repository\\OnDemandActivitySearch\\Criteria;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\n\nclass AskJiminnyReportActivityServiceTest extends TestCase\n{\n private ActivitySearch&MockObject $activitySearch;\n private ElasticActivityRepository&MockObject $elasticRepository;\n private LoggerInterface&MockObject $logger;\n private AskJiminnyReportActivityService $service;\n\n protected function setUp(): void\n {\n $this->activitySearch = $this->createMock(ActivitySearch::class);\n $this->elasticRepository = $this->createMock(ElasticActivityRepository::class);\n $this->logger = $this->createMock(LoggerInterface::class);\n\n $this->service = new AskJiminnyReportActivityService(\n $this->activitySearch,\n $this->elasticRepository,\n $this->logger,\n );\n }\n\n private function makeFilter(string $key, ?string $value): SearchFilter&MockObject\n {\n $filter = $this->createMock(SearchFilter::class);\n $filter->method('getFilterProperty')->willReturn($key);\n $filter->method('getFilterValue')->willReturn($value);\n\n return $filter;\n }\n\n private function makeUser(): User&MockObject\n {\n $tz = new \\DateTimeZone('UTC');\n $user = $this->createMock(User::class);\n $user->method('getTimezone')->willReturn($tz);\n $user->method('getId')->willReturn(1);\n $user->method('getUuid')->willReturn('user-uuid');\n\n return $user;\n }\n\n private function makeSavedSearch(array $filters): Search&MockObject\n {\n $savedSearch = $this->createMock(Search::class);\n $savedSearch->method('getId')->willReturn(42);\n $savedSearch->method('getFilters')->willReturn(new \\Illuminate\\Support\\LazyCollection($filters));\n\n return $savedSearch;\n }\n\n public function testGetActivityIdsForSavedSearchReturnsIds(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->expects($this->once())\n ->method('getArrayFilterKeys')\n ->with($user)\n ->willReturn([]);\n\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n\n $this->elasticRepository->expects($this->once())\n ->method('onDemandSearchIdsOnly')\n ->willReturn(['id-1', 'id-2', 'id-3']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[AskJiminnyReport] Fetched activity IDs for saved search');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1', 'id-2', 'id-3'], $result);\n }\n\n public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $this->logger->expects($this->once())->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEmpty($result);\n }\n\n public function testGetActivityIdsFiltersOutDateFilters(): void\n {\n $user = $this->makeUser();\n\n $nonDateFilter = $this->makeFilter('owner_id', '123');\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');\n $updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');\n $updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');\n\n $savedSearch = $this->makeSavedSearch([\n $nonDateFilter,\n $startDateFilter,\n $endDateFilter,\n $updatedFromFilter,\n $updatedToFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n }\n\n public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void\n {\n $user = $this->makeUser();\n\n $closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');\n $closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');\n $regularFilter = $this->makeFilter('rep_id', '99');\n\n $savedSearch = $this->makeSavedSearch([\n $closingStartFilter,\n $closingEndFilter,\n $regularFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesArrayFilters(): void\n {\n $user = $this->makeUser();\n\n $filter1 = $this->makeFilter('outcome', 'positive');\n $filter2 = $this->makeFilter('outcome', 'negative');\n\n $savedSearch = $this->makeSavedSearch([$filter1, $filter2]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesScalarFilters(): void\n {\n $user = $this->makeUser();\n\n $filter = $this->makeFilter('direction', 'inbound');\n $savedSearch = $this->makeSavedSearch([$filter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-5'], $result);\n }\n\n public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertFalse($capturedCriteria->isFirstRequest());\n }\n\n public function testGetActivityIdsLogsWithCorrectContext(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with(\n '[AskJiminnyReport] Fetched activity IDs for saved search',\n $this->callback(fn ($context) => $context['saved_search_id'] === 42\n && $context['user_id'] === 1\n && $context['activity_count'] === 2)\n );\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n }\n\n public static function frequencyDateRangeProvider(): array\n {\n $now = CarbonImmutable::parse('2025-06-16 12:00:00');\n\n return [\n 'daily' => [\n AutomatedReportsService::FREQUENCY_DAILY,\n $now->subDay()->startOfDay()->format('Y-m-d H:i:s'),\n $now->subDay()->endOfDay()->format('Y-m-d H:i:s'),\n ],\n 'weekly' => [\n AutomatedReportsService::FREQUENCY_WEEKLY,\n $now->subWeek()->startOfWeek()->format('Y-m-d H:i:s'),\n $now->subWeek()->endOfWeek()->format('Y-m-d H:i:s'),\n ],\n 'monthly' => [\n AutomatedReportsService::FREQUENCY_MONTHLY,\n $now->subMonthNoOverflow()->startOfMonth()->format('Y-m-d H:i:s'),\n $now->subMonthNoOverflow()->endOfMonth()->format('Y-m-d H:i:s'),\n ],\n 'quarterly' => [\n AutomatedReportsService::FREQUENCY_QUARTERLY,\n $now->subQuarterNoOverflow()->startOfQuarter()->format('Y-m-d H:i:s'),\n $now->subQuarterNoOverflow()->endOfQuarter()->format('Y-m-d H:i:s'),\n ],\n ];\n }\n\n /**\n * @dataProvider frequencyDateRangeProvider\n */\n public function testGetActivityIdsInjectsDateRangeForFrequency(\n string $frequency,\n string $expectedStartDate,\n string $expectedEndDate,\n ): void {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n\n public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void\n {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');\n $savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Services\\Kiosk\\AutomatedReports;\n\nuse Carbon\\CarbonImmutable;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityActualDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityUpdatedDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\DealInsights\\ClosingPeriodFilter;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionCollection;\nuse Jiminny\\Component\\ActivitySearch\\Service\\ActivitySearch;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\Activity\\SearchFilter;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\ElasticActivityRepository;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AskJiminnyReportActivityService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\VO\\Repository\\OnDemandActivitySearch\\Criteria;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\n\nclass AskJiminnyReportActivityServiceTest extends TestCase\n{\n private ActivitySearch&MockObject $activitySearch;\n private ElasticActivityRepository&MockObject $elasticRepository;\n private LoggerInterface&MockObject $logger;\n private AskJiminnyReportActivityService $service;\n\n protected function setUp(): void\n {\n $this->activitySearch = $this->createMock(ActivitySearch::class);\n $this->elasticRepository = $this->createMock(ElasticActivityRepository::class);\n $this->logger = $this->createMock(LoggerInterface::class);\n\n $this->service = new AskJiminnyReportActivityService(\n $this->activitySearch,\n $this->elasticRepository,\n $this->logger,\n );\n }\n\n private function makeFilter(string $key, ?string $value): SearchFilter&MockObject\n {\n $filter = $this->createMock(SearchFilter::class);\n $filter->method('getFilterProperty')->willReturn($key);\n $filter->method('getFilterValue')->willReturn($value);\n\n return $filter;\n }\n\n private function makeUser(): User&MockObject\n {\n $tz = new \\DateTimeZone('UTC');\n $user = $this->createMock(User::class);\n $user->method('getTimezone')->willReturn($tz);\n $user->method('getId')->willReturn(1);\n $user->method('getUuid')->willReturn('user-uuid');\n\n return $user;\n }\n\n private function makeSavedSearch(array $filters): Search&MockObject\n {\n $savedSearch = $this->createMock(Search::class);\n $savedSearch->method('getId')->willReturn(42);\n $savedSearch->method('getFilters')->willReturn(new \\Illuminate\\Support\\LazyCollection($filters));\n\n return $savedSearch;\n }\n\n public function testGetActivityIdsForSavedSearchReturnsIds(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->expects($this->once())\n ->method('getArrayFilterKeys')\n ->with($user)\n ->willReturn([]);\n\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n\n $this->elasticRepository->expects($this->once())\n ->method('onDemandSearchIdsOnly')\n ->willReturn(['id-1', 'id-2', 'id-3']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[AskJiminnyReport] Fetched activity IDs for saved search');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1', 'id-2', 'id-3'], $result);\n }\n\n public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $this->logger->expects($this->once())->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEmpty($result);\n }\n\n public function testGetActivityIdsFiltersOutDateFilters(): void\n {\n $user = $this->makeUser();\n\n $nonDateFilter = $this->makeFilter('owner_id', '123');\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');\n $updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');\n $updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');\n\n $savedSearch = $this->makeSavedSearch([\n $nonDateFilter,\n $startDateFilter,\n $endDateFilter,\n $updatedFromFilter,\n $updatedToFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n }\n\n public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void\n {\n $user = $this->makeUser();\n\n $closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');\n $closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');\n $regularFilter = $this->makeFilter('rep_id', '99');\n\n $savedSearch = $this->makeSavedSearch([\n $closingStartFilter,\n $closingEndFilter,\n $regularFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesArrayFilters(): void\n {\n $user = $this->makeUser();\n\n $filter1 = $this->makeFilter('outcome', 'positive');\n $filter2 = $this->makeFilter('outcome', 'negative');\n\n $savedSearch = $this->makeSavedSearch([$filter1, $filter2]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesScalarFilters(): void\n {\n $user = $this->makeUser();\n\n $filter = $this->makeFilter('direction', 'inbound');\n $savedSearch = $this->makeSavedSearch([$filter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-5'], $result);\n }\n\n public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertFalse($capturedCriteria->isFirstRequest());\n }\n\n public function testGetActivityIdsLogsWithCorrectContext(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with(\n '[AskJiminnyReport] Fetched activity IDs for saved search',\n $this->callback(fn ($context) => $context['saved_search_id'] === 42\n && $context['user_id'] === 1\n && $context['activity_count'] === 2)\n );\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n }\n\n public static function frequencyDateRangeProvider(): array\n {\n $now = CarbonImmutable::parse('2025-06-16 12:00:00');\n\n return [\n 'daily' => [\n AutomatedReportsService::FREQUENCY_DAILY,\n $now->subDay()->startOfDay()->format('Y-m-d H:i:s'),\n $now->subDay()->endOfDay()->format('Y-m-d H:i:s'),\n ],\n 'weekly' => [\n AutomatedReportsService::FREQUENCY_WEEKLY,\n $now->subWeek()->startOfWeek()->format('Y-m-d H:i:s'),\n $now->subWeek()->endOfWeek()->format('Y-m-d H:i:s'),\n ],\n 'monthly' => [\n AutomatedReportsService::FREQUENCY_MONTHLY,\n $now->subMonthNoOverflow()->startOfMonth()->format('Y-m-d H:i:s'),\n $now->subMonthNoOverflow()->endOfMonth()->format('Y-m-d H:i:s'),\n ],\n 'quarterly' => [\n AutomatedReportsService::FREQUENCY_QUARTERLY,\n $now->subQuarterNoOverflow()->startOfQuarter()->format('Y-m-d H:i:s'),\n $now->subQuarterNoOverflow()->endOfQuarter()->format('Y-m-d H:i:s'),\n ],\n ];\n }\n\n /**\n * @dataProvider frequencyDateRangeProvider\n */\n public function testGetActivityIdsInjectsDateRangeForFrequency(\n string $frequency,\n string $expectedStartDate,\n string $expectedEndDate,\n ): void {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n\n public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void\n {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');\n $savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"27","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"23","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"105","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"SELECT * FROM team_features where team_id = 1;\n\nSELECT * FROM teams WHERE name LIKE '%Vixio%'; # 340,270,11922\nSELECT * FROM users WHERE team_id = 340; # 12015\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 340\nand sa.provider = 'salesforce';\n# and sa.provider = 'salesloft';\n\nselect * from crm_fields where crm_configuration_id = 270 and object_type = 'event';\n# 125558 - Event Type - Event_Type__c\n# 125552 - Event Status - Event_Status__c\n\nSELECT * FROM sidekick_settings WHERE team_id = 340;\n\nSELECT * FROM crm_field_values WHERE crm_field_id in (125552);\n\nselect * from activities where crm_configuration_id = 270\nand type = 'conference' and crm_provider_id IS NOT NULL\nand actual_start_time > '2024-09-16 09:00:00' order by scheduled_start_time;\n\nSELECT * FROM activities WHERE id = 20871677;\nSELECT * FROM crm_field_data WHERE activity_id = 20871677;\n\nselect * from crm_layouts where crm_configuration_id = 270;\nselect * from crm_layout_entities where crm_layout_id in (886,887);\n\nSELECT * FROM crm_configurations WHERE id = 270;\n\nselect * from playbooks where team_id = 340; # 1514\nselect * from groups where team_id = 340;\nSELECT * FROM crm_fields WHERE id IN (125393, 125401);\n\nselect g.name as 'team name', p.name as 'playbook name', f.label as 'activity type field' from groups g\njoin playbooks p on g.playbook_id = p.id\njoin crm_fields f on p.activity_field_id = f.id\nwhere g.team_id = 340;\n\nSELECT * FROM activities WHERE uuid_to_bin('0c180357-67d2-419e-a8c3-b832a3490770') = uuid; # 20448716\nselect * from crm_field_data where object_id = 20448716;\n\nselect * from activities where crm_configuration_id = 270 and provider = 'salesloft' order by id desc;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%CybSafe%'; # 343,273,12008\nselect * from opportunities where team_id = 343;\nselect * from opportunities where team_id = 343 and crm_provider_id = '18099102526';\nselect * from opportunities where team_id = 343 and account_id = 945217482;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 343\nand sa.provider = 'hubspot';\n\nselect * from accounts where team_id = 343 order by name asc;\n\nselect * from stages where crm_configuration_id = 273 and type = 'opportunity';\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Voyado%'; # 353,283,12143\nSELECT * FROM activities WHERE crm_configuration_id = 283 and account_id = 3777844 order by id desc;\nSELECT * FROM accounts WHERE team_id = 353 AND name LIKE '%Salesloft%';\nSELECT * FROM activities WHERE id = 20717903;\n\nselect * from participants where activity_id IN (20929172,20928605,20928468,20926272,20926271,20926270,20926269,20916499,20916454,20916436,20916435,20900015,20900014,20900013,20897312,20897243,20897241,20897237,20897232,20897229,20893648,20893231,20893230,20893229,20893228,20889784,20885039,20885038,20885037,20885036,20885035,20882728,20882708,20882703,20882702,20869828,20869811,20869806,20869801,20869799,20869798,20869796,20869795,20869794,20869761,20869760,20869759,20868688,20868687,20850340,20847195,20841710,20833967,20827021,20825307,20825305,20825297,20824615,20824400,20823927,20821760,20795588,20794233,20794057,20793710,20785811,20781789,20781394,20781307,20762651,20758453,20758282,20757323,20756643,20756636,20756629,20756627,20756606,20756605,20756604,20756603,20756602,20756600,20756599,20756598,20756595,20756594,20756589,20756587,20756577,20756573,20748918,20748386,20748385,20748384,20748383,20748382,20748381,20748380,20748379,20748377,20748375,20748373,20743301,20717905,20717904,20717903,20717901,20717899);\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 353\nand sa.provider = 'salesforce';\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%modern world business solutions%'; # 345,275,12016, l.atkinson@mwbsolutions.co.uk\nSELECT * FROM activities WHERE uuid_to_bin('3921d399-3fef-4609-a291-b0097a166d43') = uuid;\n# id: 20940638, user: 12022, contact: 5305871\nSELECT * FROM activity_summary_logs WHERE activity_id = 20940638;\nselect * from contacts where team_id = 345 and crm_provider_id = '30891432415' order by name asc; # 5305871\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 345\nand sa.provider = 'hubspot';\n\nselect * from users where team_id = 345 and id = 12022;\nSELECT * FROM crm_profiles WHERE user_id = 12022;\nSELECT * FROM participants WHERE activity_id = 20940638;\nSELECT * FROM users u\nJOIN crm_profiles cp ON u.id = cp.user_id\nWHERE u.team_id = 345;\n\nselect * from contacts where team_id = 345 and crm_provider_id = '30880813535' order by name desc; # 5305871\n\nselect * from team_features where team_id = 345;\nSELECT * FROM activities WHERE uuid_to_bin('11701e2d-2f82-4dab-a616-1db4fad238df') = uuid; # 21115197\nSELECT * FROM participants WHERE activity_id = 20897406;\n\n\n\nSELECT * FROM activities WHERE uuid_to_bin('63ba55cd-1abc-447d-83da-0137000005b7') = uuid; # 20953912\nSELECT * FROM activities WHERE crm_configuration_id = 275 and provider = 'ringcentral' and title like '%1252629100%';\n\n\nSELECT * FROM activities WHERE id = 20946641;\nSELECT * FROM crm_profiles WHERE user_id = 10211;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Lunio%'; # 120,97,10984, triger@lunio.ai\nSELECT * FROM opportunities WHERE crm_configuration_id = 97 and crm_provider_id = '006N1000006c5PpIAI';\nselect * from stages where crm_configuration_id = 97 and type = 'opportunity';\nselect * from opportunities where team_id = 120;\n\n\nselect * from crm_configurations crm join teams t on crm.id = t.crm_id\nwhere 1=1\nAND t.current_billing_plan IS NOT NULL\nAND crm.auto_sync_activity = 0\nand crm.provider = 'hubspot';\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Exclaimer%'; # 270,205,10053,james.lewendon@exclaimer.com\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 270\nand sa.provider = 'salesforce';\nSELECT * FROM activities WHERE uuid_to_bin('b54df794-2a9a-4957-8d80-09a600ead5f8') = uuid; # 21637956\nSELECT * FROM crm_profiles WHERE user_id = 11446;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Cygnetise%'; # 372,300,12554, alex.chikly@cygnetise.com\nselect * from playbooks where team_id = 372;\nselect * from crm_fields where crm_configuration_id = 300 and object_type = 'event'; # 141340\nSELECT * FROM crm_field_values WHERE crm_field_id = 141340;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 372\nand sa.provider = 'salesforce';\n\nselect * from crm_profiles where crm_configuration_id = 300;\nSELECT * FROM crm_configurations WHERE team_id = 372;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Planday%'; # 291,242,11501,mfa@planday.com\nSELECT * FROM opportunities WHERE team_id = 291 and crm_provider_id = '006bG000005DO86QAG'; # 3207756\nselect * from crm_field_data where object_id = 3207756;\nSELECT * FROM crm_fields WHERE id = 111834;\n\nselect f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value\nFROM crm_fields f\nJOIN crm_field_data fd ON f.id = fd.crm_field_id\nWHERE f.crm_configuration_id = 242\nAND f.object_type = 'opportunity'\nAND fd.object_id IN (3207756)\nORDER BY fd.object_id, fd.updated_at;\n\nSELECT * FROM crm_configurations WHERE auto_connect = 1;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Tour%'; # 187,209,8150,salesforce-admin@tourlane.com\nselect * from group_deal_risk_types drgt join groups g on drgt.group_id = g.id\nwhere g.team_id = 187;\n\nselect * from `groups` where team_id = 187;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 187\nand sa.provider = 'salesforce';\n\n# Destination - 98870 - Destination__c\n# Stage - 79014 - StageName\n# Land Arrangement - 98856 - Land_Arrangement__c\n# Flight - 98848 - Flight__c\n# Last activity date - 98812 - LastActivityDate\n# Last modified date - 98809 - LastModifiedDate\n# Last inbound mail timestamp - 99151 - Last_Inbound_Mail_Timestamp__c\n# next call - 98864 - Next_Call__c\n\nselect * from crm_fields where crm_configuration_id = 209 and object_type = 'opportunity';\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 209;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 682;\n\nselect * from opportunities where team_id = 187 and name LIKE'%Muriel Sal%';\nselect * from opportunities where team_id = 187 and user_id = 9951 and is_closed = 0;\nselect * from activities where opportunity_id = 3538248;\n\nSELECT * FROM crm_profiles WHERE user_id = 8150;\n\nselect * from deal_risks where opportunity_id = 3538248;\n\nselect * from teams where crm_id IS NULL;\n\nSELECT opp.id AS opportunity_id,\n u.group_id AS group_id,\n MAX(\n CASE\n WHEN a.type IN (\"sms-inbound\", \"sms-outbound\") THEN a.created_at\n ELSE a.actual_end_time\n END) as last_date\nFROM opportunities opp\nleft join activities a on a.opportunity_id = opp.id\ninner join users u on opp.user_id = u.id\nwhere opp.user_id IN (9951)\n\nAND opp.is_closed = 0\nand a.status IN ('completed', 'received', 'delivered') OR a.status IS NULL\ngroup by opp.id;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Cybsafe%'; # 343,301,12008,polly.morphew@cybsafe.com\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 343\nand sa.provider = 'hubspot';\n\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 301;\nSELECT * FROM contacts WHERE id = 6612363;\nSELECT * FROM accounts WHERE id = 4235676;\nSELECT * FROM opportunities WHERE crm_configuration_id = 301 and crm_provider_id = 32983784868;\nselect * from opportunity_stages where opportunity_id = 4503759;\n# SELECT * FROM opportunities WHERE id = 4569937;\n\nselect * from activities where crm_configuration_id = 301;\nSELECT * FROM activities WHERE uuid_to_bin('d3b2b28b-c3d0-4c2d-8ed0-eef42855278a') = uuid; # 26330370\nSELECT * FROM participants WHERE activity_id = 26330370;\n\nSELECT * FROM teams WHERE id = 375;\nselect * from playbooks where team_id = 375;\n\nselect * from stages where crm_configuration_id = 301 and type = 'opportunity';\n\nselect * from teams;\nselect * from contact_roles;\n\nSELECT * FROM opportunities WHERE team_id = 343 and user_id = 12871 and close_date >= '2024-11-01';\n\nselect * from users u join crm_profiles cp on cp.user_id = u.id where u.team_id = 343;\n\nSELECT * FROM crm_field_data WHERE object_id = 3771706;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 343\nand sa.provider = 'hubspot';\n\nSELECT * FROM crm_fields WHERE crm_configuration_id = 301 and object_type = 'opportunity'\nand crm_provider_id LIKE \"%traffic_light%\";\nSELECT * FROM crm_field_values WHERE crm_field_id IN (144020,144048,144111,144113,144126,144481,144508,144531);\n\nSELECT fd.* FROM opportunities o\nJOIN crm_field_data fd ON o.id = fd.object_id\nWHERE o.team_id = 343\n# and o.user_id IS NOT NULL\nand fd.crm_field_id IN (144020,144048,144111,144113,144126,144481,144508,144531)\nand fd.value != ''\norder by value desc\n# group by o.id\n;\n\nSELECT * FROM opportunities WHERE id = 3769843;\n\nSELECT * FROM teams WHERE name LIKE '%Tour%'; # 187,209,8150, salesforce-admin@tourlane.com\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 209;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 682;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Funding Circle%'; # 220,177,8603,aswini.mishra@fundingcircle.com\nSELECT * FROM activities WHERE uuid_to_bin('7a40e99b-3b37-4bb1-b983-325b81801c01') = uuid; # 23139839\n\n\nSELECT * FROM opportunities WHERE id = 3855992;\n\nSELECT * FROM users WHERE name LIKE '%Angus Pollard%'; # 8988\n\nSELECT * FROM teams WHERE name LIKE '%Story Terrace%'; # 379, 307, 12894\nSELECT * FROM crm_fields WHERE crm_configuration_id = 307 and object_type != 'opportunity';\n\nselect * from contacts where team_id = 379 and name like '%bebro%'; # 5874411, crm: 77229348507\nSELECT * FROM crm_field_data WHERE object_id = 5874411;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 379\nand sa.provider = 'hubspot';\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%mentio%'; # 117, 94, 6371, nikhil.kumar@mention-me.com\nSELECT * FROM activities WHERE uuid_to_bin('82939311-1af0-4506-8546-21e8d1fdf2c1') = uuid;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Tourlane%'; # 187, 209, 8150, salesforce-admin@tourlane.com\nSELECT * FROM opportunities WHERE team_id = 187 and crm_provider_id = '006Se000008xfvNIAQ'; # 3537793\nselect * from generic_ai_prompts where subject_id = 3537793;\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Lunio%'; # 120, 97, 10984, triger@lunio.ai\nSELECT * FROM crm_configurations WHERE id = 97;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 97;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 355;\nSELECT * FROM crm_fields WHERE id = 32682;\n\nselect cfd.value, o.* from opportunities o\njoin crm_field_data cfd on o.id = cfd.object_id and cfd.crm_field_id = 32682\nwhere team_id = 120\nand cfd.value != ''\n;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 120\nand sa.provider = 'salesforce';\n\nselect * from opportunities where team_id = 120 and crm_provider_id = '006N1000007X8MAIA0';\nSELECT * FROM crm_field_data WHERE object_id = 2313439;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE id = 410;\nSELECT * FROM teams WHERE name LIKE '%Local Business Oxford%';\nselect * from scorecards where team_id = 410;\nselect * from scorecard_rules;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Funding%'; # 220, 177, 8603, aswini.mishra@fundingcircle.com\nselect * from activities a\njoin opportunities o on a.opportunity_id = o.id\njoin users u on o.user_id = u.id\nwhere a.crm_configuration_id = 177 and a.type LIKE '%email-out%'\n# and a.actual_end_time > '2024-12-16 00:00:00'\n# and o.remotely_created_at > '2024-12-01 00:00:00'\n# and u.group_id = 1014\nand u.id = 9021\norder by a.id desc;\nSELECT * FROM opportunities WHERE id in (3981384,4017346);\nSELECT * FROM users WHERE team_id = 220 and id IN (8775, 11435);\n\nselect * from users where id = 9021;\nselect * from inboxes where user_id = 9021;\n\nselect * from inbox_emails where inbox_id = 1349 and email_date > '2024-12-18 00:00:00';\n\nselect * from email_messages where team_id = 220\nand orig_date > '2024-12-16 00:00:00' and orig_date < '2024-12-19 00:00:00'\nand subject LIKE '%Personal%'\n# and 'from' = 'credit@fundingcircle.com'\n;\n\nselect * from activities a\njoin opportunities o on a.opportunity_id = o.id\nwhere a.user_id = 9021 and a.type LIKE '%email-out%'\nand a.actual_end_time > '2024-12-18 00:00:00'\nand o.user_id IS NOT NULL\nand o.remotely_created_at > '2024-12-01 00:00:00'\norder by a.id desc;\n\nSELECT * FROM opportunities WHERE team_id = 220 and name LIKE '%Right Car move Limited%' and id = 3966852;\nselect * from activities where crm_configuration_id = 177 and type LIKE '%email%' and opportunity_id = 3966852 order by id desc;\n\nselect * from team_settings where name IN ('useCloseDate');\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Hurree%'; # 104, 81, 6175, jfarrell@hurree.co\nSELECT * FROM opportunities WHERE team_id = 104 and name = 'PropOp';\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 104\nand sa.provider = 'hubspot';\n\nselect * from crm_configurations where last_synced_at > '2025-01-19 01:00:00'\nselect * from teams where crm_id IS NULL;\n\nselect t.name as 'team', u.name as 'owner', u.email, u.phone\nfrom teams t\njoin activity_providers ap on t.id = ap.team_id\njoin users u on t.owner_id = u.id\nwhere 1=1\n and t.status = 'active'\n and ap.is_enabled = 1\n# and u.status = 1\n and ap.provider = 'ms-teams';\n\nselect * from crm_configurations where provider = 'bullhorn'; # 344\nSELECT * FROM teams WHERE id = 442; # 14293\nselect * from users where team_id = 442;\nselect * from social_accounts sa where sa.sociable_id = 14293;\nselect * from invitations where team_id = 442;\n\n# ********************************************************************************************************\nSELECT * FROM users WHERE email LIKE '%nea.liikamaa@eletive.com%'; # 14022\nSELECT * FROM teams WHERE id = 429;\nselect * from opportunities where team_id = 429 and crm_provider_id IN (16157415775, 22246219645);\nselect * from activities where opportunity_id in (4340436,4353519);\n\nselect * from transcription where activity_id IN (25630961,25381771);\nselect * from generic_ai_prompts where subject_id IN (4353519);\n\nSELECT\n a.id as activity_id,\n a.opportunity_id,\n a.type as activity_type,\n a.language,\n CONCAT(a.title, a.description) AS mail_content,\n e.from AS mail_from,\n e.to AS mail_to,\n e.subject AS mail_subject,\n e.body AS mail_body,\n p.type as prompt_type,\n p.status as prompt_status,\n p.content AS prompt_content,\n a.actual_start_time as created_at\nFROM activities a\n LEFT JOIN ai_prompts p ON a.transcription_id = p.transcription_id AND p.deleted_at IS NULL\n LEFT JOIN email_messages e ON a.id = e.activity_id\nWHERE a.actual_start_time > '2024-01-01 00:00:00'\n AND a.opportunity_id IN (4353519)\n AND a.status IN ('completed', 'received', 'delivered')\n AND a.deleted_at IS NULL\n AND a.type NOT IN ('sms-inbound', 'sms-outbound')\nORDER BY a.opportunity_id ASC, a.id ASC;\n\nSELECT * FROM users WHERE name LIKE '%George Fierstone%'; # 14293\nSELECT * FROM teams WHERE id = 442;\nSELECT * FROM crm_configurations WHERE id = 344;\nselect * from team_features where team_id = 442;\nselect * from groups where team_id = 442;\nselect * from playbooks where team_id = 442;\nselect * from playbook_categories where playbook_id = 1729;\nselect * from crm_fields where crm_configuration_id = 344 and id = 172024;\nSELECT * FROM crm_field_values WHERE crm_field_id = 172024;\nselect * from crm_layouts where crm_configuration_id = 344;\nselect * from playbook_layouts where playbook_id = 1729;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Learning%'; # 260, 221, 9444\n\nselect s.*\n# , s.sent_at, u.name, a.*\nfrom activity_summary_logs s\ninner join activities a on a.id = s.activity_id\ninner join users u on u.id = a.user_id\nwhere a.crm_configuration_id = 356\nand s.sent_at > date_sub(now(), interval 60 day)\norder by a.actual_end_time desc;\n\nselect * from activities a\n# inner join activity_summary_logs s on s.activity_id = a.id\nwhere a.crm_configuration_id = 356 and a.actual_end_time > date_sub(now(), interval 60 day)\n# and a.crm_provider_id is not null\n# and provider <> 'ringcentral'\nand status = 'completed'\norder by a.actual_end_time desc;\n\nselect * from teams order by id desc; # 17328, 32, 17830, integration-account@jiminny.com\nSELECT * FROM users;\nSELECT * FROM users where team_id = 260 and status = 1; # 201 - 150 active\nSELECT * FROM teams WHERE id = 260;\nselect * from team_settings where team_id = 260;\nselect * from crm_configurations where team_id = 260;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 356;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1184;\n\nselect * from accounts where crm_configuration_id = 221 order by id desc; # 7000\nselect * from leads where crm_configuration_id = 221 order by id desc; # 0\nselect * from contacts where crm_configuration_id = 221 order by id desc; # 200 000\nselect * from opportunities where crm_configuration_id = 221 order by id desc; # 0\nselect * from crm_profiles where crm_configuration_id = 221 order by id desc; # 23\nselect * from crm_fields where crm_configuration_id = 221;\nselect * from crm_field_values where crm_field_id = 5302 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 221 order by id desc;\nselect * from stages where crm_configuration_id = 221 order by id desc;\n\nselect * from accounts where crm_configuration_id = 356 order by id desc; # 7000\nselect * from leads where crm_configuration_id = 356 order by id desc; # 0\nselect * from contacts where crm_configuration_id = 356 order by id desc; # 200 000\nselect * from opportunities where crm_configuration_id = 356 order by id desc; # 0\nselect * from crm_profiles where crm_configuration_id = 356 order by id desc; # 23\nselect * from crm_fields where crm_configuration_id = 356;\nselect * from crm_field_values where crm_field_id = 5302 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 356 order by id desc;\nselect * from stages where crm_configuration_id = 356 order by id desc;\n\nselect * from playbooks where team_id = 260 order by id desc; # 4 (2 deleted)\nselect * from groups where team_id = 260 order by id desc; # 27 groups, (2 deleted)\nselect * from playbook_layouts where playbook_id IN (1410,1409,1276,1254); # 4\nselect ce.* from calendars c\njoin users u on c.user_id = u.id\njoin calendar_events ce on c.id = ce.calendar_id\nwhere u.team_id = 260\nand (ce.start_time > '2025-02-21 00:00:00')\n;\n# calendar events 1207\n#\n\nselect * from opportunities where team_id = 260;\nSELECT * FROM crm_field_data WHERE object_id = 4696496;\n\nselect * from activities where crm_configuration_id = 356 and crm_provider_id IS NOT NULL;\nselect * from activities where crm_configuration_id IN (221) and provider NOT IN ('ms-teams', 'uploader', 'zoom-bot')\n# and type = 'conference' and status = 'scheduled' and activities.is_internal = 0\nand created_at > '2024-03-01 00:00:00'\norder by id desc; # 880 000, ringcentral, avaya\nSELECT * FROM participants WHERE activity_id = 26371744;\n\n# all activities 942 000 +\n# conference 7385 - scheduled 984 - external 343\n\nselect * from activities where id = 26321812;\nselect * from participants where activity_id = 26321812;\nselect * from participants where activity_id in (26414510,26414514,26414516,26414604,26414653,26414655);\nselect * from leads where id in (720428,689175,731546,645866,621037);\n\nselect * from users where id = 13841;\nselect * from opportunities where user_id = 9541;\nselect * from stages where id = 15900;\n\nselect * from accounts where\n# id IN (4160055,5053725,4965303,4896434)\nid in (4584518,3249934,3218025,3891133,3399450,4172999,4485161,3101785,4587203,3070816,2870343,2870341,3563940,4550846,3424464,3249963,2870342)\n;\n\nselect * from activities where id = 26654935;\nSELECT * FROM opportunities WHERE id = 4803458;\n\nSELECT * FROM opportunities where team_id = 260 and user_id = 13841 AND stage_id = 15900;\nSELECT id, uuid, provider, type, lead_id, account_id, contact_id, opportunity_id, stage_id, status, recording_state, title, actual_start_time, actual_end_time\nFROM activities WHERE user_id = 13841 AND opportunity_id IN (4729783, 4731717, 4731726, 4732064, 4732849, 4803458, 4813213);\n\nSELECT DISTINCT\n o.id, o.stage_id, s.name, a.title,\n a.*\nFROM activities a\n# INNER JOIN tracks t ON a.id = t.activity_id\nINNER JOIN users u ON a.user_id = u.id\nINNER JOIN teams team ON u.team_id = team.id\nINNER JOIN groups g ON u.group_id = g.id\nINNER JOIN opportunities o ON a.opportunity_id = o.id\nINNER JOIN stages s ON o.stage_id = s.id\nWHERE\n a.crm_configuration_id = 356\n AND a.status IN ('completed', 'failed')\n AND a.recording_state != 'stopped'\n# and a.user_id = 13841\n AND u.uuid = uuid_to_bin('6f40e4b8-c340-4059-b4ac-1728e87ea99e')\n AND team.uuid = uuid_to_bin('a607fba7-452e-4683-b2af-00d6cb52c93c')\n AND g.uuid = uuid_to_bin('b5d69e40-24a0-4c16-810b-5fa462299f94')\n\n AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')\n# AND t.type IN ('audio', 'video')\n AND (\n (a.actual_start_time BETWEEN '2025-03-13 00:00:00' AND '2025-03-18 07:59:59')\n OR\n (\n a.actual_start_time IS NULL\n AND a.type IN ('sms-outbound', 'sms-inbound')\n AND a.created_at BETWEEN '2025-03-13 00:00:00' AND '2025-03-18 07:59:59'\n )\n )\n AND (\n a.is_private = 0\n OR (\n a.is_private = 1\n AND u.uuid = uuid_to_bin('6f40e4b8-c340-4059-b4ac-1728e87ea99e')\n )\n )\n AND (\n# s.id = 15900\n s.uuid = uuid_to_bin('04ca1c26-c666-4268-a129-419c0acffd73')\n OR s.uuid IS NULL -- Include records without opportunity stage\n )\n\nORDER BY a.actual_end_time DESC;\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Lead Forensics%'; # 190, 162, 8474, willsc@leadforensics.com\nSELECT * FROM users WHERE team_id = 190;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 190\nand sa.provider = 'hubspot';\n\nselect * from role_user where user_id = 8474;\n\nselect * from crm_configurations where provider = 'bullhorn';\n\nSELECT * FROM opportunities WHERE uuid_to_bin('94578249-65ec-4205-90f2-7d1a7d5ab64a') = uuid;\nSELECT * FROM users WHERE uuid_to_bin('26dbadeb-926f-4150-b11b-771b9d4c2f9a') = uuid;\n\nSELECT * FROM opportunities WHERE id = 4732493;\nselect * from activities where opportunity_id = 4732493;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE id = 443; # 358, 14315, andrea.romano@correrenaturale.com\nSELECT * FROM opportunities WHERE team_id = 443;\n\nSELECT a.id, a.type, a.user_id, a.status, a.deleted_at, u.name, u.email, u.team_id as activity_team_id, u.status, u.deleted_at, t.name, t.status, s.team_id as stage_team_id\nFROM activities AS a\nJOIN stages AS s ON a.stage_id = s.id\nJOIN users AS u ON u.id = a.user_id\nJOIN teams AS t ON t.id = s.team_id\nWHERE u.team_id <> s.team_id and t.id > 135;\n\n\nSELECT\n crm_configuration_id,\n crm_provider_id,\n COUNT(*) as duplicate_count,\n GROUP_CONCAT(id) as stage_ids,\n GROUP_CONCAT(name) as stage_names\nFROM stages\nGROUP BY crm_configuration_id, crm_provider_id\nHAVING COUNT(*) > 1\nORDER BY duplicate_count DESC;\n\nselect * from stages where id IN (14898,14907);\n\nselect * from business_processes;\n\nSELECT *\nFROM crm_configurations\nWHERE team_id IN (\n SELECT team_id\n FROM crm_configurations\n GROUP BY team_id\n HAVING COUNT(*) > 1\n)\nORDER BY team_id;\n\nSELECT *\nFROM teams\nWHERE crm_id IN (\n SELECT crm_id\n FROM teams\n GROUP BY crm_id\n HAVING COUNT(*) > 1\n)\nORDER BY crm_id;\n\n# ***************************************************************************\nselect * from crm_configurations where provider = 'integration-app';\nSELECT * FROM teams WHERE id = 443; # Correre Naturale 358 14315 andrea.romano@correrenaturale.com\nselect * from activities where crm_configuration_id = 358 order by actual_end_time desc;\nselect id, uuid, actual_end_time, crm_provider_id, is_internal, playbook_category_id, type, user_id, lead_id, contact_id, account_id, opportunity_id, status, title from activities where crm_configuration_id = 358 order by actual_end_time desc;\nselect * from team_features where team_id = 358;\nselect * from activity_summary_logs;\n\nselect * from teams where id = 406;\n\n# ************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Sportfive%'; # 267, 202, 14637, srv.salesforce@sportfive.com\nselect * from activities where crm_configuration_id = 202 order by actual_end_time desc;\n\nSELECT * FROM users where id = 14637;\nSELECT * FROM teams where id = 267;\nSELECT * FROM groups where id = 1118;\n\nselect g.name, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled_start_time, a.scheduled_end_time, a.actual_start_time, a.actual_end_time from activities a\ninner join users u on u.id = a.user_id\ninner join groups g on g.id = u.group_id\nwhere a.crm_configuration_id = 202\nand a.is_internal = 0\nand (a.scheduled_start_time between '2025-03-19 00:00:00' and '2025-03-21 00:00:00')\nand a.type = 'conference'\nand a.status != 'completed'\nand a.external_id is not null\norder by a.scheduled_start_time desc;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 202\n AND status IN ('completed', 'failed')\n AND recording_state != 'stopped'\n AND type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')\n AND (is_private = 0 OR user_id = 14637)\n AND (\n (\n actual_start_time BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'\n ) OR (\n actual_start_time IS NULL\n AND type IN ('sms-outbound', 'sms-inbound')\n AND created_at BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'\n )\n )\n AND NOT EXISTS (\n SELECT 1\n FROM tracks\n WHERE\n tracks.activity_id = activities.id\n AND tracks.type IN ('audio', 'video')\n )\nORDER BY actual_end_time DESC;\n\nSELECT DISTINCT\n a.*\nFROM activities a\nINNER JOIN tracks t ON a.id = t.activity_id\nINNER JOIN users u ON a.user_id = u.id\nINNER JOIN teams team ON u.team_id = team.id\nWHERE\n a.crm_configuration_id = 202\n AND a.status IN ('completed', 'failed')\n AND a.recording_state != 'stopped'\n# and a.user_id = 14637\n AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')\n# AND t.type IN ('audio', 'video')\n AND (\n (a.actual_start_time BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59')\n OR\n (\n a.actual_start_time IS NULL\n AND a.type IN ('sms-outbound', 'sms-inbound')\n AND a.created_at BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'\n )\n )\n AND (\n a.is_private = 0\n OR (\n a.is_private = 1\n AND a.user_id = 14637\n )\n )\n\nORDER BY a.actual_end_time DESC\n;\n\nSELECT DISTINCT a.*\nFROM activities a\nINNER JOIN users u ON a.user_id = u.id\nINNER JOIN teams t ON u.team_id = t.id\n# INNER JOIN tracks tr ON a.id = tr.activity_id\n# INNER JOIN groups g ON u.group_id = g.id\nWHERE 1=1\n AND t.id = 267\n# AND t.uuid = uuid_to_bin('aed4927b-f1ea-499e-94c3-83762fd233e8')\n AND a.status IN ('completed', 'failed')\n AND a.recording_state != 'stopped'\n AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')\n# AND tr.type NOT IN ('audio', 'video')\n AND (\n a.is_private = 0\n OR a.user_id = 14637\n )\n AND (\n (a.actual_start_time BETWEEN '2025-03-19 00:00:00' AND '2025-03-21 23:59:59')\n OR (\n a.actual_start_time IS NULL\n AND a.type IN ('sms-outbound', 'sms-inbound')\n AND a.created_at BETWEEN '2025-03-19 00:00:00' AND '2025-03-21 23:59:59'\n )\n )\n# and NOT EXISTS (\n# SELECT 1\n# FROM tracks t\n# WHERE t.activity_id = a.id\n# AND t.type IN ('audio', 'video')\n# )\n\nORDER BY a.actual_end_time DESC;\n\nSELECT * FROM tracks WHERE activity_id = 26485995;\n\nselect a.is_private, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled_start_time, a.scheduled_end_time, a.actual_start_time, a.actual_end_time from activities a\ninner join users u on u.id = a.user_id\nwhere a.crm_configuration_id = 202\n# and a.is_internal = 0\nand (a.actual_start_time between '2025-03-19 00:00:00' and '2025-03-21 00:00:00')\nand a.type IN (\"softphone\",\"softphone-inbound\",\"conference\",\"sms-inbound\")\nand a.status IN ('completed', 'failed')\n# and a.external_id is not null\norder by a.actual_end_time desc;\n\nselect * from activities a where a.crm_configuration_id = 202\nand a.actual_start_time between '2025-03-20 00:00:00' and '2025-03-21 00:00:00'\n# AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')\n\nselect g.name, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled_start_time, a.scheduled_end_time, a.actual_start_time, a.actual_end_time from activities a\ninner join users u on u.id = a.user_id\ninner join groups g on g.id = u.group_id\nwhere a.crm_configuration_id = 202\nand a.is_internal = 0\nand (a.scheduled_start_time between '2025-03-19 00:00:00' and '2025-03-21 00:00:00')\nand a.type = 'conference'\nand a.status != 'completed'\nand a.external_id is not null\norder by a.scheduled_start_time desc;\n\nSELECT * FROM teams WHERE name LIKE '%Tourlane%';\nSELECT * FROM crm_fields WHERE crm_configuration_id = 209 and object_type = 'opportunity';\nSELECT * FROM crm_field_data WHERE crm_field_id = 98809;\n\nselect * from users where status = 1 AND timezone = 'MDT';\n\nselect * from opportunities where id = 3769814;\nselect * from deal_risks where opportunity_id = 3769814;\n\nselect cp.* from crm_profiles cp\njoin users u on cp.user_id = u.id\njoin crm_configurations crm on cp.crm_configuration_id = crm.id\nwhere crm.provider = 'hubspot' AND u.status = 1 AND log_notes != 'none';\n\nselect * from crm_fields where id = 154575;\n\nselect * from team_features where feature = 'SUPPORTS_SYNC_MISSING_CALL_DISPOSITIONS';\nSELECT * FROM teams WHERE id = 176; # crm 148\nselect * from activities where crm_configuration_id = 148 and provider = 'hubspot' order by id desc;\n\nselect * from activity_providers where provider = 'amazon-connect';\n\nselect * from crm_fields cf\njoin crm_configurations crm on crm.id = cf.crm_configuration_id\nwhere crm.provider = 'hubspot' and cf.object_type IN ('account', 'contact');\n\n# *********************************************************************************************\nSELECT * FROM users WHERE id IN (15415, 15418);\nSELECT * FROM groups WHERE id IN (1805,1806);\nSELECT * FROM playbooks WHERE id = 1860;\nSELECT * FROM playbook_categories WHERE id = 38634;\nSELECT * FROM crm_fields WHERE id = 189962;\n\nSELECT * FROM teams WHERE name = 'Pulsar Group'; # 472, 380, 15138 raza.gilani@vuelio.com\n\nSELECT * FROM crm_profiles WHERE user_id = 15415;\nSELECT * FROM social_accounts WHERE sociable_id = 15415 and provider = 'salesforce';\n\nselect * from sidekick_settings where team_id = 472;\n\nSELECT * FROM activities WHERE uuid_to_bin('452c58c7-b87c-4fdd-953e-d7af185e9588') = uuid; # 28617536, user: 15418\nSELECT * FROM activities WHERE uuid_to_bin('399114ee-d3a8-458c-bff5-5f654658db0a') = uuid; # 28344407, user: 15415\nSELECT * FROM activities WHERE uuid_to_bin('f0aa567f-0ab1-4bbb-96aa-37dcf184676b') = uuid; # 28580288, user: 15415\nSELECT * FROM activities WHERE uuid_to_bin('50c086b1-2770-4bca-b5ae-6bac22ec426b') = uuid; # 28566069, user: 15415\n\n# *********************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%TeamTailor%'; # 109, 218, 13969, salesforce-integrations@teamtailor.com\nselect * from crm_configurations where id = 218;\nSELECT * FROM activities WHERE uuid_to_bin('e39b5857-7fdb-4f5a-951a-8d3ca69bb1b0') = uuid; # 28338765\nSELECT * FROM users WHERE id IN (13232, 13230);\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 109\nand sa.provider = 'salesforce';\n\n0057R00000EPL5HQAX Inez Ekblad\n\n1091cb81-5ea1-4951-a0ed-f00b568f0140 Triman Kaur\n\nSELECT * FROM crm_profiles WHERE user_id IN (13232, 13230);\n\n############################################################################################\nSELECT * FROM activities WHERE uuid_to_bin('675eeaeb-5681-42db-90bc-54c07a604408') = uuid; # 28655939 00UVg00000FLvnSMAT\nSELECT * FROM crm_field_data WHERE activity_id = 28655939;\nSELECT * FROM crm_fields WHERE id IN (94491,94493,94498);\nSELECT * FROM users WHERE id = 13658;\nSELECT * FROM teams WHERE id = 109;\nSELECT * FROM crm_configurations WHERE id = 218;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 109\nand sa.provider = 'salesforce';\n\n# ********************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Strengthscope%'; # 481, 390, 15420, katy.holden@strengthscope.comk\nSELECT * FROM stages WHERE crm_configuration_id = 390;\nselect * from business_processes where team_id = 481 and crm_configuration_id = 390;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 481\nand sa.provider = 'salesforce';\n\n\nSELECT * FROM users WHERE id = 15780; # team 462\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 462\nand sa.provider = 'hubspot';\n\n\nselect * from teams where id = 495;\nSELECT * FROM users WHERE id = 15794;\nselect * from social_accounts where sociable_id = 15794;\n\n# ********************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Flight%'; # 427, 333, 13752\nSELECT * FROM accounts WHERE team_id = 427 and crm_provider_id = '668731000183444517';\n\n# ********************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Group GTI%'; # 495, 407, 15794\nSELECT * FROM activities WHERE crm_configuration_id = 407\nand status = 'completed' and type = 'conference'\norder by id desc;\n\nselect ru.*, pr.*, p.* from users u join role_user ru on ru.user_id = u.id\njoin permission_role pr on pr.role_id = ru.role_id\n join permissions p on p.id = pr.permission_id\nwhere team_id = 495 and p.name IN ('dial');\n\nselect * from permission_role;\n\nselect * from activities where crm_configuration_id = 407 and status = 'completed' order by id desc;\nSELECT * FROM activities WHERE id = 29512773;\nSELECT * FROM activities WHERE id IN (29042721,28991325,29002874);\n\nSELECT al.* from activity_summary_logs al join activities a on a.id = al.activity_id\nwhere a.crm_configuration_id = 407\n# and a.id IN (29042721,28991325,29002874);\n\nSELECT * FROM users WHERE id = 15794;\nSELECT * FROM users WHERE team_id = 495;\nSELECT * FROM social_accounts WHERE sociable_id = 15794;\nSELECT * FROM opportunities WHERE team_id = 495 and name like '%OC:%';\nSELECT * FROM contacts WHERE team_id = 495;\nSELECT * FROM leads WHERE team_id = 495;\nSELECT * FROM accounts WHERE team_id = 495;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 407;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 407;\nSELECT * FROM crm_configurations WHERE id = 407;\nSELECT * FROM opportunities WHERE team_id = 495 and close_date BETWEEN '2025-06-01' AND '2025-07-01'\nand user_id IS NOT NULL and is_closed = 1 and is_won = 1;\n\n# ********************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Hamilton Court FX LLP%'; # 249, 187, 10103\nSELECT * FROM activities WHERE uuid_to_bin('4659c2bb-9a49-484e-9327-a3d66f1e028c') = uuid; # 28951064\nSELECT * FROM crm_fields WHERE crm_configuration_id = 187 and object_type IN ('tasks', 'event');\n\n# *********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Checkstep%'; # 325, 256, 11753\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 325\nand sa.provider = 'hubspot';\n\nSELECT * FROM activities WHERE uuid_to_bin('7be372e2-1916-4d79-a2f3-ca3db1346db3') = uuid; # 28611085\nSELECT * FROM activities WHERE uuid_to_bin('980f0336-840b-4185-a5a9-30cf8b0749a8') = uuid; # 28719733\nSELECT * FROM activity_summary_logs where activity_id = 28719733;\n\n# *************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Learning%'; # 260, 356, 9444\nSELECT * FROM activity_summary_logs where sent_at BETWEEN '2025-06-09 11:38:00' AND '2025-06-09 11:40:00';\nSELECT * FROM leads WHERE crm_configuration_id = 356 and crm_provider_id = '230045001502770504'; # 823630\nselect * from activities where crm_configuration_id = 356 and lead_id = 841732;\n\nSELECT * from activity_summary_logs al join activities a on a.id = al.activity_id\nwhere a.crm_configuration_id = 356;\n\nselect * from activities where crm_configuration_id = 356\nand actual_end_time between '2025-06-09 11:00:00' and '2025-06-09 12:00:00'\norder by id desc;\n\nselect * from accounts where crm_configuration_id = 356 and crm_provider_id = '230045001514403366' order by id desc;\nselect * from leads where crm_configuration_id = 356 and crm_provider_id = '230045001514275654' order by id desc;\nselect * from contacts where crm_configuration_id = 356 and crm_provider_id = '230045001514403366' order by id desc;\nselect * from opportunities where crm_configuration_id = 356 and crm_provider_id = '230045001514403366' order by id desc;\n\nselect * from team_features where team_id = 260;\nselect * from features where id IN (1,2,4,6,18,19,20,9,10,3,23,24,25,26,27);\n\nSELECT * FROM activities WHERE uuid_to_bin('7be372e2-1916-4d79-a2f3-ca3db1346db3') = uuid;\n\nselect * from crm_fields;\nselect * from crm_layout_entities;\n\nSELECT * FROM teams WHERE name LIKE '%Optable%';\n\n# *************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Teamtailor%'; # 109, 218, 13969\nSELECT * FROM crm_configurations WHERE id = 218;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 109\nand sa.provider = 'salesforce';\nSELECT * FROM activities WHERE uuid_to_bin('675eeaeb-5681-42db-90bc-54c07a604408') = uuid; # 28655939\nSELECT * FROM crm_field_data WHERE activity_id = 28655939;\nSELECT * FROM crm_fields WHERE id in (94491,94493,94498);\n\nselect * from teams where crm_id IS NULL;\n\nSELECT * FROM activities WHERE uuid_to_bin('71aa8a0c-9652-4ff6-bee7-d98ae60abef6') = uuid;\n\n# *************************************************************************************************\nselect * from team_domains where team_id = 399;\nSELECT * FROM teams WHERE name LIKE '%Rydoo%'; # 399, 318, 13207\n\nselect * from calendar_events where id = 5163781;\nSELECT * FROM activities WHERE uuid_to_bin('be2cbc52-7fda-46a0-9ae0-25d9553eafc0') = uuid; # 29443896\nSELECT * FROM participants WHERE activity_id = 29443896;\nselect * from contacts where crm_configuration_id = 318 and email = 'marianne.westeng@strawberry.no';\nselect * from leads where crm_configuration_id = 318 and email = 'marianne.westeng@strawberry.no';\n\nselect * from activities where user_id = 14937 order by created_at ;\n\nselect * from users where id = 14937;\n\nselect * from contacts where crm_configuration_id = 318 and email LIKE '%@strawberry.se';\nselect * from opportunities where crm_configuration_id = 318 and crm_provider_id = '006Sf00000D1WOAIA3';\n\nselect * from activities a join participants p on a.id = p.activity_id\nwhere crm_configuration_id = 318 and a.updated_at > '2025-06-23T08:18:43Z';\n\n# *************************************************************************************************\nSELECT * FROM opportunities WHERE team_id = 379 and crm_provider_id = '39334518886';\nSELECT * FROM opportunities WHERE team_id = 379 order by id desc;\nSELECT * FROM teams WHERE id = 379;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 379 and sociable_id = 13852\nand sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations WHERE id = 307;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 307;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1027;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 307\n and id IN (144750,144855,145158,155227);\n\nSELECT * FROM activities;\n\n\nselect * from activities\nwhere created_at > '2025-07-01 00:00:00'\n# and created_at < '2025-08-01 00:00:00'\nand type not in ('email-outbound', 'email-inbound')\nand account_id is null\nand contact_id is null\nand lead_id is null\nand opportunity_id is not null\n;\nSELECT * FROM activities WHERE id IN (25344155, 25344296, 25501909, 28692187);\nSELECT * FROM crm_configurations WHERE id in (335,301,200);\n\nselect * from crm_fields where crm_configuration_id = 230 and crm_provider_id = 'Age2__c';\n\nSELECT * FROM teams WHERE name LIKE '%Resights%';\nselect * from crm_fields where crm_configuration_id = 1 and object_type = 'opportunity';\n\nselect * from crm_configurations where provider = 'bullhorn'; # 344\nselect * from teams where id IN (442);\n\nselect * from activities\nwhere crm_configuration_id = 177\nand provider = 'amazon-connect'\n order by id desc;\n# and source <> 'gong';\n\nselect * from activity_providers where provider = 'amazon-connect';\n\nSELECT * FROM activities WHERE uuid_to_bin('cec1993b-a7e5-4164-b74d-d680ea51d2f2') = uuid;\n\n\nselect * from crm_configurations where store_transcript = 1;\nSELECT * FROM teams WHERE id IN (80);\n\n# *************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Sedna%'; # 277, 213, 12594\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 277\nand sa.provider = 'salesforce';\n\nselect * from activities where crm_configuration_id = 213 and account_id = 2511502;\n\nselect * from crm_configurations where id = 213;\n\nSELECT * FROM activities WHERE uuid_to_bin('35aa790a-8569-4544-8268-66f9a4a26804') = uuid; # 33981604\nSELECT * FROM participants WHERE activity_id = 33981604;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 337 and object_type = 'task';\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 431\nand sa.provider = 'salesforce';\nSELECT * FROM activities WHERE uuid_to_bin('b5476c7d-19a8-491b-869d-676ea1e857b6') = uuid; # 33997223\nselect * from activity_summary_logs where activity_id = 33997223;\nselect * from activity_notes where activity_id = 33997223;\n\n# ***********************************\nSELECT * FROM teams WHERE name LIKE '%Abode%';\n\n\nselect * from features;\nselect * from teams t\nwhere t.status = 'active'\nand id NOT IN (select team_id from team_features where feature_id = 9)\n;\n\n\nselect * from playbook_layouts where playbook_id = 1725;\nSELECT * FROM activities WHERE uuid_to_bin('65cc283c-4849-49e6-927f-4c281c8fea19') = uuid; # 34297473\nselect * from teams where id = 318;\nselect * from crm_configurations where team_id = 318;\nselect * from playbooks where team_id = 318;\nSELECT * FROM crm_layouts where crm_configuration_id = 381;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1259;\nSELECT * FROM crm_fields WHERE id IN (192938,192936,192939);\n\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1266;\nSELECT * FROM crm_fields WHERE id IN (192980,192991,192997,192998,193064,193067);\n\nSELECT * FROM activities WHERE uuid_to_bin('a902289b-285c-48eb-9cc2-6ad6c5d938f5') = uuid; # 34297533\n\n\n\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 927;\nSELECT * FROM crm_fields WHERE id IN (131668,131669,131670,131671,131676,131797);\n\nSELECT * FROM teams WHERE name LIKE '%Peripass%'; # 351, 281, 12124\nselect * from crm_layouts where crm_configuration_id = 281;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 927;\nselect * from crm_fields where crm_configuration_id = 281 and id in (131668,131669,131670,131671,131676,131797);\nselect * from opportunities where crm_configuration_id = 281;\n\nSELECT * FROM activities WHERE id IN (34211315, 34130075);\nSELECT * FROM crm_field_data WHERE object_id IN (34211315, 34130075);\n\nselect cf.crm_configuration_id, cle.crm_layout_id, cle.id, cf.id from crm_field_data cfd\njoin crm_layout_entities cle on cle.id = cfd.crm_layout_entity_id\njoin crm_fields cf on cle.crm_field_id = cf.id\nwhere cf.deleted_at IS NOT NULL\nGROUP BY cle.id, cf.id;\n\nselect * from crm_layouts where id IN (355);\nselect u.email, t.crm_id, t.* from teams t\njoin users u on u.id = t.owner_id\nwhere crm_id IN (97);\n\nSELECT * FROM crm_fields WHERE id = 96492;\n\nselect * from permissions;\nselect * from permission_role where permission_id = 247;\nselect * from roles;\n\nselect * from migrations;\n# *****************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('291e3c21-11cc-4728-aee7-6e4bedf86d72') = uuid; # 34262174\nSELECT * FROM crm_configurations WHERE id = 301;\nSELECT * FROM teams WHERE id = 343;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 343\nand sa.provider = 'hubspot';\n\nselect * from participants where activity_id = 34262174;\n\nselect * from contacts where crm_configuration_id = 301 and id = 6976326;\nselect * from accounts where crm_configuration_id = 301 and id IN (4647626, 4815829); # 30761335403\n\nselect * from activity_summary_logs where activity_id = 34262174;\n\nselect * from users where status = 1 AND timezone = 'EST';\n\n# ****************************************************************************\nSELECT * FROM users WHERE id = 13869;\nSELECT * FROM crm_configurations WHERE id = 320;\nSELECT * FROM teams WHERE id = 401;\n\nSELECT * FROM activities WHERE uuid_to_bin('2228c16f-10be-48d5-90d4-67385219dc01') = uuid; # 29670601\n\nSELECT * FROM accounts WHERE id = 7761483;\nSELECT * FROM opportunities WHERE id = 6051814;\n\nSELECT * FROM teams WHERE name LIKE '%Seedlegals%';\n\n;select * from opportunities where updated_at > '2025-10-11' AND crm_provider_id = '34713761166';\n\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 177;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 577;\nSELECT * FROM crm_fields WHERE id IN (68458,68459,68480,68497,68524,68530,68554,68618,68662,68781,68810,68898,68981,69049,97467);\n\nSELECT t.id, crm.id, t.name, crm.sync_objects, crm.provider, crm.last_synced_at FROM crm_configurations crm join teams t on t.crm_id = crm.id\nwhere t.status = 'active' AND crm.provider = 'hubspot' AND crm.last_synced_at < '2025-10-22 00:00:00';\n\nSELECT * FROM activities WHERE uuid_to_bin('fa09449f-cba9-496a-b8f3-865cd3c72351') = uuid;\nSELECT * FROM crm_configurations where id = 184;\nSELECT * FROM teams WHERE id = 246;\nSELECT * FROM social_accounts WHERE sociable_id = 9259 and provider = 'hubspot';\n\nSELECT * FROM users WHERE email LIKE '%rhian.old@bud.co.uk%'; # 17700\nSELECT * FROM teams WHERE id = 551;\n\nSELECT * FROM crm_configurations WHERE id = 471;\nSELECT * FROM activities WHERE crm_configuration_id = 471 and crm_provider_id IS NOT NULL;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 471;\nSELECT * FROM crm_fields WHERE id = 307260;\nSELECT * FROM crm_field_values WHERE crm_field_id = 307260;\n\nselect * from crm_layouts where crm_configuration_id = 471;\n\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1547;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1548;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 551 and sa.provider = 'hubspot';\n\nSELECT * FROM teams WHERE name LIKE '%$PCS%';\n\n# ********************************************************************************************************\nselect * from crm_configurations crm\njoin teams t on t.crm_id = crm.id\nwhere t.status = 'active'\nand crm.provider = 'hubspot';\n\n# $slug = 'HUBSPOT_WEBHOOK_SYNC';\n# $team = Jiminny\\Models\\Team::find(2);\n# $feature = Feature::query()->where('slug', $slug)->first();\n# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);\n\n# hubspot_webhook_metrics\n\nselect * from crm_configurations where id = 331; # 416\nSELECT * FROM teams WHERE id = 416;\nSELECT * FROM opportunities WHERE team_id = 190;\n\nSELECT * FROM teams WHERE name LIKE '%Lead Forensics%';\nSELECT sa.id,\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 190 and sa.provider = 'hubspot';\n\n\n\nSELECT * FROM teams WHERE name LIKE '%Rapaport%'; # 431, 337\nSELECT * FROM teams where id = 431;\nSELECT * FROM crm_configurations where team_id = 431;\nSELECT * FROM activity_providers where team_id = 431;\nSELECT * FROM activities where crm_configuration_id = 337 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\nSELECT sa.id,\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 431 and sa.provider = 'salesforce';\n\nSELECT * FROM teams WHERE name LIKE '%BiP%'; # 401, 320\nSELECT * FROM teams where id = 401;\nSELECT * FROM crm_configurations where team_id = 401;\nSELECT * FROM activity_providers where team_id = 401;\nSELECT * FROM activities where crm_configuration_id = 320 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\nSELECT sa.id,\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 401 and sa.provider = 'salesforce';\n\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 307; # 379 - Story Terrace Inc , portalId: 3921157\nSELECT * FROM contacts WHERE team_id = 379 and updated_at > '2026-01-31 11:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 379 and updated_at > '2026-02-01 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 379 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 379 and sa.provider = 'hubspot';\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 485; # 563 - LATUS Group (ad94d501-5d09-44fd-878f-ca3a9f8865c3) , portalId: 3904501\nSELECT * FROM opportunities WHERE team_id = 563 and updated_at > '2026-02-02 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 563 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 338; # 432 - Formalize , portalId: 9214205\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 432 and sa.provider = 'hubspot';\nSELECT * FROM opportunities WHERE team_id = 432 and updated_at > '2026-02-02 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 432 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 436; # 519 - Moxso , portalId: 25531989\nSELECT * FROM opportunities WHERE team_id = 519 and updated_at > '2026-02-02 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 519 and updated_at > '2026-02-04 11:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 96; # 119 - Nourish Care , portalId: 26617984\nSELECT * FROM opportunities WHERE team_id = 119 and updated_at > '2026-02-02 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 119 and updated_at > '2026-02-04 11:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 331; # 416 - The National College , portalId: 7213852\nSELECT * FROM opportunities WHERE team_id = 416 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 416 and updated_at > '2026-02-04 11:00:00' order by updated_at desc;\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 308; # 380 - Foodles , portalId: 7723616\nSELECT * FROM opportunities WHERE team_id = 380 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 380 and updated_at > '2026-02-06 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 379; # 471 - imat-uve , portalId: 9177354\nSELECT * FROM opportunities WHERE team_id = 471 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 471 and updated_at > '2026-02-06 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 465; # 545 - Spotler , portalId: 144759271\nSELECT * FROM opportunities WHERE team_id = 545 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 545 and updated_at > '2026-02-06 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 455; # 537 - indevis , portalId: 25666868\nSELECT * FROM opportunities WHERE team_id = 537 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 537 and updated_at > '2026-02-06 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 200; # 265 - Jobadder , portalId: 6426676\nSELECT * FROM opportunities WHERE team_id = 265 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 265 and updated_at > '2026-02-06 10:30:00' order by updated_at desc;\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 335; # 429 - Eletive , portalId: 6110563\nSELECT * FROM opportunities WHERE team_id = 429 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 429 and updated_at > '2026-02-09 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 363; # 456 - Global Group , portalId: 8901981\nSELECT * FROM opportunities WHERE team_id = 456 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 456 and updated_at > '2026-02-09 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 297; # 369 - Unbiased , portalId: 9229005\nSELECT * FROM opportunities WHERE team_id = 369 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 369 and updated_at > '2026-02-09 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 353; # 449 - Fuuse , portalId: 25781745\nSELECT * FROM opportunities WHERE team_id = 449 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 449 and updated_at > '2026-02-09 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 487; # 566 - Nimbus , portalId: 39982590\nSELECT * FROM opportunities WHERE team_id = 566 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 566 and updated_at > '2026-02-09 10:30:00' order by updated_at desc;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 487;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1630;\nselect * from crm_fields where crm_configuration_id = 487 and\n(uuid_to_bin('4c6b2971-64d4-45b8-b377-427be758b5a5') = uuid or uuid_to_bin('59e368d8-65a0-4b77-b611-db37c99fbe68') = uuid);\nSELECT * FROM crm_field_values WHERE crm_field_id = 375177;\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 420; # 506 - voiio , portalId: 145629154\nSELECT * FROM opportunities WHERE team_id = 506 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 506 and updated_at > '2026-02-10 15:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 479; # 558 - Momice , portalId: 535962\nSELECT * FROM opportunities WHERE team_id = 558 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 558 and updated_at > '2026-02-10 15:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 59; # 80 - Storyclash GmbH , portalId: 4268479\nSELECT * FROM opportunities WHERE team_id = 80 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 80 and updated_at > '2026-02-10 15:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 175; # 203 - Team iAM , portalId: 5534732\nSELECT * FROM opportunities WHERE team_id = 203 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 203 and updated_at > '2026-02-10 15:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 368; # 460 - OneTouch Health , portalId: 5534732183355\nSELECT * FROM opportunities WHERE team_id = 460 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 460 and updated_at > '2026-02-10 15:00:00' order by updated_at desc;\n\n\n\nselect * from users where id = 29643;\nSELECT * FROM crm_field_values WHERE crm_field_id = 375177;\n# ********************************************************************\nSELECT * FROM teams WHERE name LIKE '%Buynomics%'; # 462, 482, 14910\nSELECT * FROM activities WHERE crm_configuration_id = 482\nand type NOT IN ('email-inbound', 'email-outbound')\n# and description like '%The call focused on understanding Welch%'\norder by id desc;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 462 and sa.provider = 'salesforce';\n\nselect * from contacts where crm_configuration_id = 482 and name = 'Cyndall Hill'; # 15504749\nselect * from contacts where id = 10891096; # 482\nSELECT * FROM activities WHERE crm_configuration_id = 482\nand type NOT IN ('email-inbound', 'email-outbound')\nand contact_id = 15504749\norder by id desc;\n\nselect * from activities where id = 36793003; # 96cc7bc1-8622-4d27-92f4-baf664fc1a56, 00UOf00000PDdOXMA1\nselect * from transcription where id = 7646782;\nselect * from ai_prompts where transcription_id = 7646782;\n\n# ********************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('7a8471a3-847e-4822-802b-ddf426bbc252') = uuid; # 37370018\nSELECT * FROM activity_summary_logs WHERE activity_id = 37370018;\nSELECT * FROM teams WHERE id = 555;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 555 and sa.provider = 'hubspot';\n\n# ********************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('7c17b8aa-09df-4f85-a0f7-51f47afd712d') = uuid; # 37395250\nSELECT * FROM activities WHERE uuid_to_bin('14d60388-260d-494b-aa0d-63fdb1c78026') = uuid; # 37395250\n\nSELECT a.* FROM activities a JOIN crm_configurations c on c.id = a.crm_configuration_id\nwhere a.type IN ('softphone', 'softphone-outbound') and c.provider = 'hubspot'\nand a.provider NOT IN ('hubspot')\n# and a.provider IN ('salesloft')\n# and c.id NOT IN (70)\n# and a.duration > 30\n# and actual_start_time > '2026-02-05 00:00:00'\norder by a.id desc;\n\nSELECT * FROM activities WHERE id = 37549787;\nSELECT * FROM crm_profiles WHERE user_id = 17613;\n\nSELECT * FROM crm_configurations WHERE id = 70;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 93 and sa.provider = 'hubspot';\n\nSELECT asf.activity_search_id, asf.id, asf.value\nFROM activity_search_filters asf\nWHERE asf.filter = 'group_id'\nAND asf.value IN (\n SELECT CONCAT(\n HEX(SUBSTR(uuid, 5, 4)), '-',\n HEX(SUBSTR(uuid, 3, 2)), '-',\n HEX(SUBSTR(uuid, 1, 2)), '-',\n HEX(SUBSTR(uuid, 9, 2)), '-',\n HEX(SUBSTR(uuid, 11))\n )\n FROM groups\n WHERE deleted_at IS NOT NULL\n);\n\nSELECT * FROM crm_configurations WHERE id = 373; # KPSBremen.de 465 # - no social account\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 465 and sa.provider = 'hubspot';\n\nselect * from crm_configurations where id = 494;\n\nSELECT * FROM teams WHERE name LIKE '%splose%'; # 572, 495, 18708\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 572 and sa.provider = 'pipedrive';\n\nselect * from opportunities where team_id = 572\n# and name like '%Onebright%'\n# and is_closed = 1 and is_won = 0\n order by id desc;\n\n\nselect * from users where deleted_at is null and status = 2;\n\nselect * from contacts where id = 17900517;\nselect * from accounts where id = 10109838;\nselect * from opportunities where id = 6955880;\n\nselect * from opportunity_contacts where opportunity_id = 6955880;\nselect * from opportunity_contacts where contact_id = 17900517;\n\nselect * from contact_roles cr join crm_configurations crm on cr.crm_configuration_id = crm.id\nwhere crm.provider != 'salesforce';\n\nSELECT * FROM activities WHERE uuid_to_bin('adcb8331-5988-4353-834e-383a355abba2') = uuid; # 38056424, crm 104659682404\nselect * from teams where id = 456;\nSELECT * FROM crm_configurations WHERE id = 363;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 456 and sa.provider = 'hubspot';\n\nselect * from crm_layouts where crm_configuration_id = 363;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id IN (1203, 1204, 1635);\nSELECT * FROM crm_fields WHERE id IN (181536, 181538, 213455);\n\nSELECT * FROM teams WHERE name LIKE '%Electric%'; # 342, 272, 12767\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 342 and sa.provider = 'pipedrive';\nSELECT * FROM opportunities WHERE crm_configuration_id = 272 and name like 'NORTHUMBRIA POL%'; # and updated_at > '2025-07-01 00:00:00';\nSELECT * FROM opportunities WHERE crm_configuration_id = 272 order by remotely_created_at asc; # and updated_at > '2025-07-01 00:00:00';\nSELECT * FROM opportunities WHERE crm_configuration_id = 272 and updated_at > '2026-01-01 00:00:00';\nSELECT * FROM crm_fields WHERE crm_configuration_id = 272 and object_type = 'opportunity';\nSELECT * FROM crm_field_values WHERE crm_field_id = 127164;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 342 and sa.provider = 'pipedrive';\n\nSELECT * FROM teams WHERE id = 472;\nSELECT * FROM crm_configurations WHERE id = 380;\nselect * from activities where id = 38285673; # 38285673\nSELECT * FROM users WHERE id = 16942;\nSELECT * FROM groups WHERE id = 1964;\nSELECT * FROM playbooks WHERE id = 2033;\n\nselect * from teams where created_at > '2026-03-09';\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 499; # 1065\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1678;\n\nSELECT * FROM teams WHERE id = 575;\nselect * from opportunities where team_id = 575;\n\nSELECT * FROM activities WHERE uuid_to_bin('96b1261f-2357-49f9-ab38-23ce12008ea0') = uuid;\n\nselect * from contacts c\nwhere c.crm_configuration_id = 370 order by c.updated_at desc;\n\nSELECT * FROM participants where activity_id = 38833541;\nSELECT * FROM participants where activity_id = 39216301;\nSELECT * FROM activity_summary_logs where activity_id = 39216301;\nSELECT * FROM activities WHERE uuid_to_bin('c7d99fbe-1fb1-41f2-8f4d-52e2bf70e1e9') = uuid; # 38833541, crm 478116564181\nSELECT * FROM activities WHERE uuid_to_bin('2e6ff4d3-9faa-447a-a8c1-9acde4d885ae') = uuid; # 39216301, crm 480171536586\nselect * from crm_profiles where crm_configuration_id = 319 and crm_provider_id = 525785080;\nselect * from opportunities where crm_configuration_id = 319 and crm_provider_id = 410150124747;\nselect * from accounts where crm_configuration_id = 319 and crm_provider_id = 47150650569;\nselect * from contacts where crm_configuration_id = 319 and crm_provider_id IN ('665587441856', '742723347700');\n# owner 13236 525785080\n# contact 1 16779180 665587441856 - activity - Alex Howes alex@supportroom.com created 2026-01-26\n# contact 2 19247563 742723347700 - ash@supportroom.com 2026-03-24\n# company 4176133 47150650569\n# deal 7100953 410150124747\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 400 and sa.provider = 'hubspot';\n\nselect * from features;\nselect * from team_features where feature_id = 40;\n\nselect * from teams where id = 556; # owner: 18101, crm: 477\nselect * from crm_configurations where id = 477;\nSELECT * FROM users WHERE id = 18101;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 556 and sa.provider = 'integration-app';\n\nselect * from opportunities where id = 7594349;\nselect * from opportunity_stages where opportunity_id = 7594349 order by created_at desc;\nselect * from business_processes where id = 6024;\nselect * from business_process_stages where stage_id = 16352;\nselect * from business_process_stages where business_process_id = 6024;\nselect * from stages where team_id = 459;\nselect * from teams where id = 459;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 459 and sa.provider = 'hubspot';\n\nSELECT os.stage_id, s.crm_provider_id, s.name, COUNT(*) as cnt\nFROM opportunity_stages os\nJOIN stages s ON s.id = os.stage_id\nWHERE os.opportunity_id = 7594349\nGROUP BY os.stage_id, s.crm_provider_id, s.name\nORDER BY cnt DESC;\n\nSELECT s.id, s.crm_provider_id, s.name, s.team_id, s.crm_configuration_id\nFROM stages s\nJOIN business_process_stages bps ON bps.stage_id = s.id\nWHERE bps.business_process_id = 6024\nAND s.crm_provider_id = 'contractsent';\n\nselect * from stages where id IN (16352,20612,18281,7344,16378,16309,5036,15223,14535,6293,12098,11607)\n\nSELECT * FROM teams WHERE name LIKE '%Pulsar Group%'; # 472, 380, 15138, raza.gilani@vuelio.com\nselect * from playbooks where team_id = 472; # event 226147\nSELECT * FROM playbook_categories WHERE playbook_id = 2288;\nSELECT * FROM crm_fields WHERE id = 226147;\nSELECT * FROM crm_field_values WHERE crm_field_id = 226147;\n\nSELECT * FROM crm_configurations WHERE id = 380;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 472 and sa.provider = 'salesforce';","depth":4,"value":"SELECT * FROM team_features where team_id = 1;\n\nSELECT * FROM teams WHERE name LIKE '%Vixio%'; # 340,270,11922\nSELECT * FROM users WHERE team_id = 340; # 12015\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 340\nand sa.provider = 'salesforce';\n# and sa.provider = 'salesloft';\n\nselect * from crm_fields where crm_configuration_id = 270 and object_type = 'event';\n# 125558 - Event Type - Event_Type__c\n# 125552 - Event Status - Event_Status__c\n\nSELECT * FROM sidekick_settings WHERE team_id = 340;\n\nSELECT * FROM crm_field_values WHERE crm_field_id in (125552);\n\nselect * from activities where crm_configuration_id = 270\nand type = 'conference' and crm_provider_id IS NOT NULL\nand actual_start_time > '2024-09-16 09:00:00' order by scheduled_start_time;\n\nSELECT * FROM activities WHERE id = 20871677;\nSELECT * FROM crm_field_data WHERE activity_id = 20871677;\n\nselect * from crm_layouts where crm_configuration_id = 270;\nselect * from crm_layout_entities where crm_layout_id in (886,887);\n\nSELECT * FROM crm_configurations WHERE id = 270;\n\nselect * from playbooks where team_id = 340; # 1514\nselect * from groups where team_id = 340;\nSELECT * FROM crm_fields WHERE id IN (125393, 125401);\n\nselect g.name as 'team name', p.name as 'playbook name', f.label as 'activity type field' from groups g\njoin playbooks p on g.playbook_id = p.id\njoin crm_fields f on p.activity_field_id = f.id\nwhere g.team_id = 340;\n\nSELECT * FROM activities WHERE uuid_to_bin('0c180357-67d2-419e-a8c3-b832a3490770') = uuid; # 20448716\nselect * from crm_field_data where object_id = 20448716;\n\nselect * from activities where crm_configuration_id = 270 and provider = 'salesloft' order by id desc;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%CybSafe%'; # 343,273,12008\nselect * from opportunities where team_id = 343;\nselect * from opportunities where team_id = 343 and crm_provider_id = '18099102526';\nselect * from opportunities where team_id = 343 and account_id = 945217482;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 343\nand sa.provider = 'hubspot';\n\nselect * from accounts where team_id = 343 order by name asc;\n\nselect * from stages where crm_configuration_id = 273 and type = 'opportunity';\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Voyado%'; # 353,283,12143\nSELECT * FROM activities WHERE crm_configuration_id = 283 and account_id = 3777844 order by id desc;\nSELECT * FROM accounts WHERE team_id = 353 AND name LIKE '%Salesloft%';\nSELECT * FROM activities WHERE id = 20717903;\n\nselect * from participants where activity_id IN (20929172,20928605,20928468,20926272,20926271,20926270,20926269,20916499,20916454,20916436,20916435,20900015,20900014,20900013,20897312,20897243,20897241,20897237,20897232,20897229,20893648,20893231,20893230,20893229,20893228,20889784,20885039,20885038,20885037,20885036,20885035,20882728,20882708,20882703,20882702,20869828,20869811,20869806,20869801,20869799,20869798,20869796,20869795,20869794,20869761,20869760,20869759,20868688,20868687,20850340,20847195,20841710,20833967,20827021,20825307,20825305,20825297,20824615,20824400,20823927,20821760,20795588,20794233,20794057,20793710,20785811,20781789,20781394,20781307,20762651,20758453,20758282,20757323,20756643,20756636,20756629,20756627,20756606,20756605,20756604,20756603,20756602,20756600,20756599,20756598,20756595,20756594,20756589,20756587,20756577,20756573,20748918,20748386,20748385,20748384,20748383,20748382,20748381,20748380,20748379,20748377,20748375,20748373,20743301,20717905,20717904,20717903,20717901,20717899);\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 353\nand sa.provider = 'salesforce';\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%modern world business solutions%'; # 345,275,12016, l.atkinson@mwbsolutions.co.uk\nSELECT * FROM activities WHERE uuid_to_bin('3921d399-3fef-4609-a291-b0097a166d43') = uuid;\n# id: 20940638, user: 12022, contact: 5305871\nSELECT * FROM activity_summary_logs WHERE activity_id = 20940638;\nselect * from contacts where team_id = 345 and crm_provider_id = '30891432415' order by name asc; # 5305871\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 345\nand sa.provider = 'hubspot';\n\nselect * from users where team_id = 345 and id = 12022;\nSELECT * FROM crm_profiles WHERE user_id = 12022;\nSELECT * FROM participants WHERE activity_id = 20940638;\nSELECT * FROM users u\nJOIN crm_profiles cp ON u.id = cp.user_id\nWHERE u.team_id = 345;\n\nselect * from contacts where team_id = 345 and crm_provider_id = '30880813535' order by name desc; # 5305871\n\nselect * from team_features where team_id = 345;\nSELECT * FROM activities WHERE uuid_to_bin('11701e2d-2f82-4dab-a616-1db4fad238df') = uuid; # 21115197\nSELECT * FROM participants WHERE activity_id = 20897406;\n\n\n\nSELECT * FROM activities WHERE uuid_to_bin('63ba55cd-1abc-447d-83da-0137000005b7') = uuid; # 20953912\nSELECT * FROM activities WHERE crm_configuration_id = 275 and provider = 'ringcentral' and title like '%1252629100%';\n\n\nSELECT * FROM activities WHERE id = 20946641;\nSELECT * FROM crm_profiles WHERE user_id = 10211;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Lunio%'; # 120,97,10984, triger@lunio.ai\nSELECT * FROM opportunities WHERE crm_configuration_id = 97 and crm_provider_id = '006N1000006c5PpIAI';\nselect * from stages where crm_configuration_id = 97 and type = 'opportunity';\nselect * from opportunities where team_id = 120;\n\n\nselect * from crm_configurations crm join teams t on crm.id = t.crm_id\nwhere 1=1\nAND t.current_billing_plan IS NOT NULL\nAND crm.auto_sync_activity = 0\nand crm.provider = 'hubspot';\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Exclaimer%'; # 270,205,10053,james.lewendon@exclaimer.com\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 270\nand sa.provider = 'salesforce';\nSELECT * FROM activities WHERE uuid_to_bin('b54df794-2a9a-4957-8d80-09a600ead5f8') = uuid; # 21637956\nSELECT * FROM crm_profiles WHERE user_id = 11446;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Cygnetise%'; # 372,300,12554, alex.chikly@cygnetise.com\nselect * from playbooks where team_id = 372;\nselect * from crm_fields where crm_configuration_id = 300 and object_type = 'event'; # 141340\nSELECT * FROM crm_field_values WHERE crm_field_id = 141340;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 372\nand sa.provider = 'salesforce';\n\nselect * from crm_profiles where crm_configuration_id = 300;\nSELECT * FROM crm_configurations WHERE team_id = 372;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Planday%'; # 291,242,11501,mfa@planday.com\nSELECT * FROM opportunities WHERE team_id = 291 and crm_provider_id = '006bG000005DO86QAG'; # 3207756\nselect * from crm_field_data where object_id = 3207756;\nSELECT * FROM crm_fields WHERE id = 111834;\n\nselect f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value\nFROM crm_fields f\nJOIN crm_field_data fd ON f.id = fd.crm_field_id\nWHERE f.crm_configuration_id = 242\nAND f.object_type = 'opportunity'\nAND fd.object_id IN (3207756)\nORDER BY fd.object_id, fd.updated_at;\n\nSELECT * FROM crm_configurations WHERE auto_connect = 1;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Tour%'; # 187,209,8150,salesforce-admin@tourlane.com\nselect * from group_deal_risk_types drgt join groups g on drgt.group_id = g.id\nwhere g.team_id = 187;\n\nselect * from `groups` where team_id = 187;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 187\nand sa.provider = 'salesforce';\n\n# Destination - 98870 - Destination__c\n# Stage - 79014 - StageName\n# Land Arrangement - 98856 - Land_Arrangement__c\n# Flight - 98848 - Flight__c\n# Last activity date - 98812 - LastActivityDate\n# Last modified date - 98809 - LastModifiedDate\n# Last inbound mail timestamp - 99151 - Last_Inbound_Mail_Timestamp__c\n# next call - 98864 - Next_Call__c\n\nselect * from crm_fields where crm_configuration_id = 209 and object_type = 'opportunity';\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 209;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 682;\n\nselect * from opportunities where team_id = 187 and name LIKE'%Muriel Sal%';\nselect * from opportunities where team_id = 187 and user_id = 9951 and is_closed = 0;\nselect * from activities where opportunity_id = 3538248;\n\nSELECT * FROM crm_profiles WHERE user_id = 8150;\n\nselect * from deal_risks where opportunity_id = 3538248;\n\nselect * from teams where crm_id IS NULL;\n\nSELECT opp.id AS opportunity_id,\n u.group_id AS group_id,\n MAX(\n CASE\n WHEN a.type IN (\"sms-inbound\", \"sms-outbound\") THEN a.created_at\n ELSE a.actual_end_time\n END) as last_date\nFROM opportunities opp\nleft join activities a on a.opportunity_id = opp.id\ninner join users u on opp.user_id = u.id\nwhere opp.user_id IN (9951)\n\nAND opp.is_closed = 0\nand a.status IN ('completed', 'received', 'delivered') OR a.status IS NULL\ngroup by opp.id;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Cybsafe%'; # 343,301,12008,polly.morphew@cybsafe.com\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 343\nand sa.provider = 'hubspot';\n\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 301;\nSELECT * FROM contacts WHERE id = 6612363;\nSELECT * FROM accounts WHERE id = 4235676;\nSELECT * FROM opportunities WHERE crm_configuration_id = 301 and crm_provider_id = 32983784868;\nselect * from opportunity_stages where opportunity_id = 4503759;\n# SELECT * FROM opportunities WHERE id = 4569937;\n\nselect * from activities where crm_configuration_id = 301;\nSELECT * FROM activities WHERE uuid_to_bin('d3b2b28b-c3d0-4c2d-8ed0-eef42855278a') = uuid; # 26330370\nSELECT * FROM participants WHERE activity_id = 26330370;\n\nSELECT * FROM teams WHERE id = 375;\nselect * from playbooks where team_id = 375;\n\nselect * from stages where crm_configuration_id = 301 and type = 'opportunity';\n\nselect * from teams;\nselect * from contact_roles;\n\nSELECT * FROM opportunities WHERE team_id = 343 and user_id = 12871 and close_date >= '2024-11-01';\n\nselect * from users u join crm_profiles cp on cp.user_id = u.id where u.team_id = 343;\n\nSELECT * FROM crm_field_data WHERE object_id = 3771706;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 343\nand sa.provider = 'hubspot';\n\nSELECT * FROM crm_fields WHERE crm_configuration_id = 301 and object_type = 'opportunity'\nand crm_provider_id LIKE \"%traffic_light%\";\nSELECT * FROM crm_field_values WHERE crm_field_id IN (144020,144048,144111,144113,144126,144481,144508,144531);\n\nSELECT fd.* FROM opportunities o\nJOIN crm_field_data fd ON o.id = fd.object_id\nWHERE o.team_id = 343\n# and o.user_id IS NOT NULL\nand fd.crm_field_id IN (144020,144048,144111,144113,144126,144481,144508,144531)\nand fd.value != ''\norder by value desc\n# group by o.id\n;\n\nSELECT * FROM opportunities WHERE id = 3769843;\n\nSELECT * FROM teams WHERE name LIKE '%Tour%'; # 187,209,8150, salesforce-admin@tourlane.com\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 209;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 682;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Funding Circle%'; # 220,177,8603,aswini.mishra@fundingcircle.com\nSELECT * FROM activities WHERE uuid_to_bin('7a40e99b-3b37-4bb1-b983-325b81801c01') = uuid; # 23139839\n\n\nSELECT * FROM opportunities WHERE id = 3855992;\n\nSELECT * FROM users WHERE name LIKE '%Angus Pollard%'; # 8988\n\nSELECT * FROM teams WHERE name LIKE '%Story Terrace%'; # 379, 307, 12894\nSELECT * FROM crm_fields WHERE crm_configuration_id = 307 and object_type != 'opportunity';\n\nselect * from contacts where team_id = 379 and name like '%bebro%'; # 5874411, crm: 77229348507\nSELECT * FROM crm_field_data WHERE object_id = 5874411;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 379\nand sa.provider = 'hubspot';\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%mentio%'; # 117, 94, 6371, nikhil.kumar@mention-me.com\nSELECT * FROM activities WHERE uuid_to_bin('82939311-1af0-4506-8546-21e8d1fdf2c1') = uuid;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Tourlane%'; # 187, 209, 8150, salesforce-admin@tourlane.com\nSELECT * FROM opportunities WHERE team_id = 187 and crm_provider_id = '006Se000008xfvNIAQ'; # 3537793\nselect * from generic_ai_prompts where subject_id = 3537793;\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Lunio%'; # 120, 97, 10984, triger@lunio.ai\nSELECT * FROM crm_configurations WHERE id = 97;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 97;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 355;\nSELECT * FROM crm_fields WHERE id = 32682;\n\nselect cfd.value, o.* from opportunities o\njoin crm_field_data cfd on o.id = cfd.object_id and cfd.crm_field_id = 32682\nwhere team_id = 120\nand cfd.value != ''\n;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 120\nand sa.provider = 'salesforce';\n\nselect * from opportunities where team_id = 120 and crm_provider_id = '006N1000007X8MAIA0';\nSELECT * FROM crm_field_data WHERE object_id = 2313439;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE id = 410;\nSELECT * FROM teams WHERE name LIKE '%Local Business Oxford%';\nselect * from scorecards where team_id = 410;\nselect * from scorecard_rules;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Funding%'; # 220, 177, 8603, aswini.mishra@fundingcircle.com\nselect * from activities a\njoin opportunities o on a.opportunity_id = o.id\njoin users u on o.user_id = u.id\nwhere a.crm_configuration_id = 177 and a.type LIKE '%email-out%'\n# and a.actual_end_time > '2024-12-16 00:00:00'\n# and o.remotely_created_at > '2024-12-01 00:00:00'\n# and u.group_id = 1014\nand u.id = 9021\norder by a.id desc;\nSELECT * FROM opportunities WHERE id in (3981384,4017346);\nSELECT * FROM users WHERE team_id = 220 and id IN (8775, 11435);\n\nselect * from users where id = 9021;\nselect * from inboxes where user_id = 9021;\n\nselect * from inbox_emails where inbox_id = 1349 and email_date > '2024-12-18 00:00:00';\n\nselect * from email_messages where team_id = 220\nand orig_date > '2024-12-16 00:00:00' and orig_date < '2024-12-19 00:00:00'\nand subject LIKE '%Personal%'\n# and 'from' = 'credit@fundingcircle.com'\n;\n\nselect * from activities a\njoin opportunities o on a.opportunity_id = o.id\nwhere a.user_id = 9021 and a.type LIKE '%email-out%'\nand a.actual_end_time > '2024-12-18 00:00:00'\nand o.user_id IS NOT NULL\nand o.remotely_created_at > '2024-12-01 00:00:00'\norder by a.id desc;\n\nSELECT * FROM opportunities WHERE team_id = 220 and name LIKE '%Right Car move Limited%' and id = 3966852;\nselect * from activities where crm_configuration_id = 177 and type LIKE '%email%' and opportunity_id = 3966852 order by id desc;\n\nselect * from team_settings where name IN ('useCloseDate');\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Hurree%'; # 104, 81, 6175, jfarrell@hurree.co\nSELECT * FROM opportunities WHERE team_id = 104 and name = 'PropOp';\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 104\nand sa.provider = 'hubspot';\n\nselect * from crm_configurations where last_synced_at > '2025-01-19 01:00:00'\nselect * from teams where crm_id IS NULL;\n\nselect t.name as 'team', u.name as 'owner', u.email, u.phone\nfrom teams t\njoin activity_providers ap on t.id = ap.team_id\njoin users u on t.owner_id = u.id\nwhere 1=1\n and t.status = 'active'\n and ap.is_enabled = 1\n# and u.status = 1\n and ap.provider = 'ms-teams';\n\nselect * from crm_configurations where provider = 'bullhorn'; # 344\nSELECT * FROM teams WHERE id = 442; # 14293\nselect * from users where team_id = 442;\nselect * from social_accounts sa where sa.sociable_id = 14293;\nselect * from invitations where team_id = 442;\n\n# ********************************************************************************************************\nSELECT * FROM users WHERE email LIKE '%nea.liikamaa@eletive.com%'; # 14022\nSELECT * FROM teams WHERE id = 429;\nselect * from opportunities where team_id = 429 and crm_provider_id IN (16157415775, 22246219645);\nselect * from activities where opportunity_id in (4340436,4353519);\n\nselect * from transcription where activity_id IN (25630961,25381771);\nselect * from generic_ai_prompts where subject_id IN (4353519);\n\nSELECT\n a.id as activity_id,\n a.opportunity_id,\n a.type as activity_type,\n a.language,\n CONCAT(a.title, a.description) AS mail_content,\n e.from AS mail_from,\n e.to AS mail_to,\n e.subject AS mail_subject,\n e.body AS mail_body,\n p.type as prompt_type,\n p.status as prompt_status,\n p.content AS prompt_content,\n a.actual_start_time as created_at\nFROM activities a\n LEFT JOIN ai_prompts p ON a.transcription_id = p.transcription_id AND p.deleted_at IS NULL\n LEFT JOIN email_messages e ON a.id = e.activity_id\nWHERE a.actual_start_time > '2024-01-01 00:00:00'\n AND a.opportunity_id IN (4353519)\n AND a.status IN ('completed', 'received', 'delivered')\n AND a.deleted_at IS NULL\n AND a.type NOT IN ('sms-inbound', 'sms-outbound')\nORDER BY a.opportunity_id ASC, a.id ASC;\n\nSELECT * FROM users WHERE name LIKE '%George Fierstone%'; # 14293\nSELECT * FROM teams WHERE id = 442;\nSELECT * FROM crm_configurations WHERE id = 344;\nselect * from team_features where team_id = 442;\nselect * from groups where team_id = 442;\nselect * from playbooks where team_id = 442;\nselect * from playbook_categories where playbook_id = 1729;\nselect * from crm_fields where crm_configuration_id = 344 and id = 172024;\nSELECT * FROM crm_field_values WHERE crm_field_id = 172024;\nselect * from crm_layouts where crm_configuration_id = 344;\nselect * from playbook_layouts where playbook_id = 1729;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Learning%'; # 260, 221, 9444\n\nselect s.*\n# , s.sent_at, u.name, a.*\nfrom activity_summary_logs s\ninner join activities a on a.id = s.activity_id\ninner join users u on u.id = a.user_id\nwhere a.crm_configuration_id = 356\nand s.sent_at > date_sub(now(), interval 60 day)\norder by a.actual_end_time desc;\n\nselect * from activities a\n# inner join activity_summary_logs s on s.activity_id = a.id\nwhere a.crm_configuration_id = 356 and a.actual_end_time > date_sub(now(), interval 60 day)\n# and a.crm_provider_id is not null\n# and provider <> 'ringcentral'\nand status = 'completed'\norder by a.actual_end_time desc;\n\nselect * from teams order by id desc; # 17328, 32, 17830, integration-account@jiminny.com\nSELECT * FROM users;\nSELECT * FROM users where team_id = 260 and status = 1; # 201 - 150 active\nSELECT * FROM teams WHERE id = 260;\nselect * from team_settings where team_id = 260;\nselect * from crm_configurations where team_id = 260;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 356;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1184;\n\nselect * from accounts where crm_configuration_id = 221 order by id desc; # 7000\nselect * from leads where crm_configuration_id = 221 order by id desc; # 0\nselect * from contacts where crm_configuration_id = 221 order by id desc; # 200 000\nselect * from opportunities where crm_configuration_id = 221 order by id desc; # 0\nselect * from crm_profiles where crm_configuration_id = 221 order by id desc; # 23\nselect * from crm_fields where crm_configuration_id = 221;\nselect * from crm_field_values where crm_field_id = 5302 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 221 order by id desc;\nselect * from stages where crm_configuration_id = 221 order by id desc;\n\nselect * from accounts where crm_configuration_id = 356 order by id desc; # 7000\nselect * from leads where crm_configuration_id = 356 order by id desc; # 0\nselect * from contacts where crm_configuration_id = 356 order by id desc; # 200 000\nselect * from opportunities where crm_configuration_id = 356 order by id desc; # 0\nselect * from crm_profiles where crm_configuration_id = 356 order by id desc; # 23\nselect * from crm_fields where crm_configuration_id = 356;\nselect * from crm_field_values where crm_field_id = 5302 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 356 order by id desc;\nselect * from stages where crm_configuration_id = 356 order by id desc;\n\nselect * from playbooks where team_id = 260 order by id desc; # 4 (2 deleted)\nselect * from groups where team_id = 260 order by id desc; # 27 groups, (2 deleted)\nselect * from playbook_layouts where playbook_id IN (1410,1409,1276,1254); # 4\nselect ce.* from calendars c\njoin users u on c.user_id = u.id\njoin calendar_events ce on c.id = ce.calendar_id\nwhere u.team_id = 260\nand (ce.start_time > '2025-02-21 00:00:00')\n;\n# calendar events 1207\n#\n\nselect * from opportunities where team_id = 260;\nSELECT * FROM crm_field_data WHERE object_id = 4696496;\n\nselect * from activities where crm_configuration_id = 356 and crm_provider_id IS NOT NULL;\nselect * from activities where crm_configuration_id IN (221) and provider NOT IN ('ms-teams', 'uploader', 'zoom-bot')\n# and type = 'conference' and status = 'scheduled' and activities.is_internal = 0\nand created_at > '2024-03-01 00:00:00'\norder by id desc; # 880 000, ringcentral, avaya\nSELECT * FROM participants WHERE activity_id = 26371744;\n\n# all activities 942 000 +\n# conference 7385 - scheduled 984 - external 343\n\nselect * from activities where id = 26321812;\nselect * from participants where activity_id = 26321812;\nselect * from participants where activity_id in (26414510,26414514,26414516,26414604,26414653,26414655);\nselect * from leads where id in (720428,689175,731546,645866,621037);\n\nselect * from users where id = 13841;\nselect * from opportunities where user_id = 9541;\nselect * from stages where id = 15900;\n\nselect * from accounts where\n# id IN (4160055,5053725,4965303,4896434)\nid in (4584518,3249934,3218025,3891133,3399450,4172999,4485161,3101785,4587203,3070816,2870343,2870341,3563940,4550846,3424464,3249963,2870342)\n;\n\nselect * from activities where id = 26654935;\nSELECT * FROM opportunities WHERE id = 4803458;\n\nSELECT * FROM opportunities where team_id = 260 and user_id = 13841 AND stage_id = 15900;\nSELECT id, uuid, provider, type, lead_id, account_id, contact_id, opportunity_id, stage_id, status, recording_state, title, actual_start_time, actual_end_time\nFROM activities WHERE user_id = 13841 AND opportunity_id IN (4729783, 4731717, 4731726, 4732064, 4732849, 4803458, 4813213);\n\nSELECT DISTINCT\n o.id, o.stage_id, s.name, a.title,\n a.*\nFROM activities a\n# INNER JOIN tracks t ON a.id = t.activity_id\nINNER JOIN users u ON a.user_id = u.id\nINNER JOIN teams team ON u.team_id = team.id\nINNER JOIN groups g ON u.group_id = g.id\nINNER JOIN opportunities o ON a.opportunity_id = o.id\nINNER JOIN stages s ON o.stage_id = s.id\nWHERE\n a.crm_configuration_id = 356\n AND a.status IN ('completed', 'failed')\n AND a.recording_state != 'stopped'\n# and a.user_id = 13841\n AND u.uuid = uuid_to_bin('6f40e4b8-c340-4059-b4ac-1728e87ea99e')\n AND team.uuid = uuid_to_bin('a607fba7-452e-4683-b2af-00d6cb52c93c')\n AND g.uuid = uuid_to_bin('b5d69e40-24a0-4c16-810b-5fa462299f94')\n\n AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')\n# AND t.type IN ('audio', 'video')\n AND (\n (a.actual_start_time BETWEEN '2025-03-13 00:00:00' AND '2025-03-18 07:59:59')\n OR\n (\n a.actual_start_time IS NULL\n AND a.type IN ('sms-outbound', 'sms-inbound')\n AND a.created_at BETWEEN '2025-03-13 00:00:00' AND '2025-03-18 07:59:59'\n )\n )\n AND (\n a.is_private = 0\n OR (\n a.is_private = 1\n AND u.uuid = uuid_to_bin('6f40e4b8-c340-4059-b4ac-1728e87ea99e')\n )\n )\n AND (\n# s.id = 15900\n s.uuid = uuid_to_bin('04ca1c26-c666-4268-a129-419c0acffd73')\n OR s.uuid IS NULL -- Include records without opportunity stage\n )\n\nORDER BY a.actual_end_time DESC;\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Lead Forensics%'; # 190, 162, 8474, willsc@leadforensics.com\nSELECT * FROM users WHERE team_id = 190;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 190\nand sa.provider = 'hubspot';\n\nselect * from role_user where user_id = 8474;\n\nselect * from crm_configurations where provider = 'bullhorn';\n\nSELECT * FROM opportunities WHERE uuid_to_bin('94578249-65ec-4205-90f2-7d1a7d5ab64a') = uuid;\nSELECT * FROM users WHERE uuid_to_bin('26dbadeb-926f-4150-b11b-771b9d4c2f9a') = uuid;\n\nSELECT * FROM opportunities WHERE id = 4732493;\nselect * from activities where opportunity_id = 4732493;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE id = 443; # 358, 14315, andrea.romano@correrenaturale.com\nSELECT * FROM opportunities WHERE team_id = 443;\n\nSELECT a.id, a.type, a.user_id, a.status, a.deleted_at, u.name, u.email, u.team_id as activity_team_id, u.status, u.deleted_at, t.name, t.status, s.team_id as stage_team_id\nFROM activities AS a\nJOIN stages AS s ON a.stage_id = s.id\nJOIN users AS u ON u.id = a.user_id\nJOIN teams AS t ON t.id = s.team_id\nWHERE u.team_id <> s.team_id and t.id > 135;\n\n\nSELECT\n crm_configuration_id,\n crm_provider_id,\n COUNT(*) as duplicate_count,\n GROUP_CONCAT(id) as stage_ids,\n GROUP_CONCAT(name) as stage_names\nFROM stages\nGROUP BY crm_configuration_id, crm_provider_id\nHAVING COUNT(*) > 1\nORDER BY duplicate_count DESC;\n\nselect * from stages where id IN (14898,14907);\n\nselect * from business_processes;\n\nSELECT *\nFROM crm_configurations\nWHERE team_id IN (\n SELECT team_id\n FROM crm_configurations\n GROUP BY team_id\n HAVING COUNT(*) > 1\n)\nORDER BY team_id;\n\nSELECT *\nFROM teams\nWHERE crm_id IN (\n SELECT crm_id\n FROM teams\n GROUP BY crm_id\n HAVING COUNT(*) > 1\n)\nORDER BY crm_id;\n\n# ***************************************************************************\nselect * from crm_configurations where provider = 'integration-app';\nSELECT * FROM teams WHERE id = 443; # Correre Naturale 358 14315 andrea.romano@correrenaturale.com\nselect * from activities where crm_configuration_id = 358 order by actual_end_time desc;\nselect id, uuid, actual_end_time, crm_provider_id, is_internal, playbook_category_id, type, user_id, lead_id, contact_id, account_id, opportunity_id, status, title from activities where crm_configuration_id = 358 order by actual_end_time desc;\nselect * from team_features where team_id = 358;\nselect * from activity_summary_logs;\n\nselect * from teams where id = 406;\n\n# ************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Sportfive%'; # 267, 202, 14637, srv.salesforce@sportfive.com\nselect * from activities where crm_configuration_id = 202 order by actual_end_time desc;\n\nSELECT * FROM users where id = 14637;\nSELECT * FROM teams where id = 267;\nSELECT * FROM groups where id = 1118;\n\nselect g.name, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled_start_time, a.scheduled_end_time, a.actual_start_time, a.actual_end_time from activities a\ninner join users u on u.id = a.user_id\ninner join groups g on g.id = u.group_id\nwhere a.crm_configuration_id = 202\nand a.is_internal = 0\nand (a.scheduled_start_time between '2025-03-19 00:00:00' and '2025-03-21 00:00:00')\nand a.type = 'conference'\nand a.status != 'completed'\nand a.external_id is not null\norder by a.scheduled_start_time desc;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 202\n AND status IN ('completed', 'failed')\n AND recording_state != 'stopped'\n AND type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')\n AND (is_private = 0 OR user_id = 14637)\n AND (\n (\n actual_start_time BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'\n ) OR (\n actual_start_time IS NULL\n AND type IN ('sms-outbound', 'sms-inbound')\n AND created_at BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'\n )\n )\n AND NOT EXISTS (\n SELECT 1\n FROM tracks\n WHERE\n tracks.activity_id = activities.id\n AND tracks.type IN ('audio', 'video')\n )\nORDER BY actual_end_time DESC;\n\nSELECT DISTINCT\n a.*\nFROM activities a\nINNER JOIN tracks t ON a.id = t.activity_id\nINNER JOIN users u ON a.user_id = u.id\nINNER JOIN teams team ON u.team_id = team.id\nWHERE\n a.crm_configuration_id = 202\n AND a.status IN ('completed', 'failed')\n AND a.recording_state != 'stopped'\n# and a.user_id = 14637\n AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')\n# AND t.type IN ('audio', 'video')\n AND (\n (a.actual_start_time BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59')\n OR\n (\n a.actual_start_time IS NULL\n AND a.type IN ('sms-outbound', 'sms-inbound')\n AND a.created_at BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'\n )\n )\n AND (\n a.is_private = 0\n OR (\n a.is_private = 1\n AND a.user_id = 14637\n )\n )\n\nORDER BY a.actual_end_time DESC\n;\n\nSELECT DISTINCT a.*\nFROM activities a\nINNER JOIN users u ON a.user_id = u.id\nINNER JOIN teams t ON u.team_id = t.id\n# INNER JOIN tracks tr ON a.id = tr.activity_id\n# INNER JOIN groups g ON u.group_id = g.id\nWHERE 1=1\n AND t.id = 267\n# AND t.uuid = uuid_to_bin('aed4927b-f1ea-499e-94c3-83762fd233e8')\n AND a.status IN ('completed', 'failed')\n AND a.recording_state != 'stopped'\n AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')\n# AND tr.type NOT IN ('audio', 'video')\n AND (\n a.is_private = 0\n OR a.user_id = 14637\n )\n AND (\n (a.actual_start_time BETWEEN '2025-03-19 00:00:00' AND '2025-03-21 23:59:59')\n OR (\n a.actual_start_time IS NULL\n AND a.type IN ('sms-outbound', 'sms-inbound')\n AND a.created_at BETWEEN '2025-03-19 00:00:00' AND '2025-03-21 23:59:59'\n )\n )\n# and NOT EXISTS (\n# SELECT 1\n# FROM tracks t\n# WHERE t.activity_id = a.id\n# AND t.type IN ('audio', 'video')\n# )\n\nORDER BY a.actual_end_time DESC;\n\nSELECT * FROM tracks WHERE activity_id = 26485995;\n\nselect a.is_private, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled_start_time, a.scheduled_end_time, a.actual_start_time, a.actual_end_time from activities a\ninner join users u on u.id = a.user_id\nwhere a.crm_configuration_id = 202\n# and a.is_internal = 0\nand (a.actual_start_time between '2025-03-19 00:00:00' and '2025-03-21 00:00:00')\nand a.type IN (\"softphone\",\"softphone-inbound\",\"conference\",\"sms-inbound\")\nand a.status IN ('completed', 'failed')\n# and a.external_id is not null\norder by a.actual_end_time desc;\n\nselect * from activities a where a.crm_configuration_id = 202\nand a.actual_start_time between '2025-03-20 00:00:00' and '2025-03-21 00:00:00'\n# AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')\n\nselect g.name, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled_start_time, a.scheduled_end_time, a.actual_start_time, a.actual_end_time from activities a\ninner join users u on u.id = a.user_id\ninner join groups g on g.id = u.group_id\nwhere a.crm_configuration_id = 202\nand a.is_internal = 0\nand (a.scheduled_start_time between '2025-03-19 00:00:00' and '2025-03-21 00:00:00')\nand a.type = 'conference'\nand a.status != 'completed'\nand a.external_id is not null\norder by a.scheduled_start_time desc;\n\nSELECT * FROM teams WHERE name LIKE '%Tourlane%';\nSELECT * FROM crm_fields WHERE crm_configuration_id = 209 and object_type = 'opportunity';\nSELECT * FROM crm_field_data WHERE crm_field_id = 98809;\n\nselect * from users where status = 1 AND timezone = 'MDT';\n\nselect * from opportunities where id = 3769814;\nselect * from deal_risks where opportunity_id = 3769814;\n\nselect cp.* from crm_profiles cp\njoin users u on cp.user_id = u.id\njoin crm_configurations crm on cp.crm_configuration_id = crm.id\nwhere crm.provider = 'hubspot' AND u.status = 1 AND log_notes != 'none';\n\nselect * from crm_fields where id = 154575;\n\nselect * from team_features where feature = 'SUPPORTS_SYNC_MISSING_CALL_DISPOSITIONS';\nSELECT * FROM teams WHERE id = 176; # crm 148\nselect * from activities where crm_configuration_id = 148 and provider = 'hubspot' order by id desc;\n\nselect * from activity_providers where provider = 'amazon-connect';\n\nselect * from crm_fields cf\njoin crm_configurations crm on crm.id = cf.crm_configuration_id\nwhere crm.provider = 'hubspot' and cf.object_type IN ('account', 'contact');\n\n# *********************************************************************************************\nSELECT * FROM users WHERE id IN (15415, 15418);\nSELECT * FROM groups WHERE id IN (1805,1806);\nSELECT * FROM playbooks WHERE id = 1860;\nSELECT * FROM playbook_categories WHERE id = 38634;\nSELECT * FROM crm_fields WHERE id = 189962;\n\nSELECT * FROM teams WHERE name = 'Pulsar Group'; # 472, 380, 15138 raza.gilani@vuelio.com\n\nSELECT * FROM crm_profiles WHERE user_id = 15415;\nSELECT * FROM social_accounts WHERE sociable_id = 15415 and provider = 'salesforce';\n\nselect * from sidekick_settings where team_id = 472;\n\nSELECT * FROM activities WHERE uuid_to_bin('452c58c7-b87c-4fdd-953e-d7af185e9588') = uuid; # 28617536, user: 15418\nSELECT * FROM activities WHERE uuid_to_bin('399114ee-d3a8-458c-bff5-5f654658db0a') = uuid; # 28344407, user: 15415\nSELECT * FROM activities WHERE uuid_to_bin('f0aa567f-0ab1-4bbb-96aa-37dcf184676b') = uuid; # 28580288, user: 15415\nSELECT * FROM activities WHERE uuid_to_bin('50c086b1-2770-4bca-b5ae-6bac22ec426b') = uuid; # 28566069, user: 15415\n\n# *********************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%TeamTailor%'; # 109, 218, 13969, salesforce-integrations@teamtailor.com\nselect * from crm_configurations where id = 218;\nSELECT * FROM activities WHERE uuid_to_bin('e39b5857-7fdb-4f5a-951a-8d3ca69bb1b0') = uuid; # 28338765\nSELECT * FROM users WHERE id IN (13232, 13230);\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 109\nand sa.provider = 'salesforce';\n\n0057R00000EPL5HQAX Inez Ekblad\n\n1091cb81-5ea1-4951-a0ed-f00b568f0140 Triman Kaur\n\nSELECT * FROM crm_profiles WHERE user_id IN (13232, 13230);\n\n############################################################################################\nSELECT * FROM activities WHERE uuid_to_bin('675eeaeb-5681-42db-90bc-54c07a604408') = uuid; # 28655939 00UVg00000FLvnSMAT\nSELECT * FROM crm_field_data WHERE activity_id = 28655939;\nSELECT * FROM crm_fields WHERE id IN (94491,94493,94498);\nSELECT * FROM users WHERE id = 13658;\nSELECT * FROM teams WHERE id = 109;\nSELECT * FROM crm_configurations WHERE id = 218;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 109\nand sa.provider = 'salesforce';\n\n# ********************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Strengthscope%'; # 481, 390, 15420, katy.holden@strengthscope.comk\nSELECT * FROM stages WHERE crm_configuration_id = 390;\nselect * from business_processes where team_id = 481 and crm_configuration_id = 390;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 481\nand sa.provider = 'salesforce';\n\n\nSELECT * FROM users WHERE id = 15780; # team 462\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 462\nand sa.provider = 'hubspot';\n\n\nselect * from teams where id = 495;\nSELECT * FROM users WHERE id = 15794;\nselect * from social_accounts where sociable_id = 15794;\n\n# ********************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Flight%'; # 427, 333, 13752\nSELECT * FROM accounts WHERE team_id = 427 and crm_provider_id = '668731000183444517';\n\n# ********************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Group GTI%'; # 495, 407, 15794\nSELECT * FROM activities WHERE crm_configuration_id = 407\nand status = 'completed' and type = 'conference'\norder by id desc;\n\nselect ru.*, pr.*, p.* from users u join role_user ru on ru.user_id = u.id\njoin permission_role pr on pr.role_id = ru.role_id\n join permissions p on p.id = pr.permission_id\nwhere team_id = 495 and p.name IN ('dial');\n\nselect * from permission_role;\n\nselect * from activities where crm_configuration_id = 407 and status = 'completed' order by id desc;\nSELECT * FROM activities WHERE id = 29512773;\nSELECT * FROM activities WHERE id IN (29042721,28991325,29002874);\n\nSELECT al.* from activity_summary_logs al join activities a on a.id = al.activity_id\nwhere a.crm_configuration_id = 407\n# and a.id IN (29042721,28991325,29002874);\n\nSELECT * FROM users WHERE id = 15794;\nSELECT * FROM users WHERE team_id = 495;\nSELECT * FROM social_accounts WHERE sociable_id = 15794;\nSELECT * FROM opportunities WHERE team_id = 495 and name like '%OC:%';\nSELECT * FROM contacts WHERE team_id = 495;\nSELECT * FROM leads WHERE team_id = 495;\nSELECT * FROM accounts WHERE team_id = 495;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 407;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 407;\nSELECT * FROM crm_configurations WHERE id = 407;\nSELECT * FROM opportunities WHERE team_id = 495 and close_date BETWEEN '2025-06-01' AND '2025-07-01'\nand user_id IS NOT NULL and is_closed = 1 and is_won = 1;\n\n# ********************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Hamilton Court FX LLP%'; # 249, 187, 10103\nSELECT * FROM activities WHERE uuid_to_bin('4659c2bb-9a49-484e-9327-a3d66f1e028c') = uuid; # 28951064\nSELECT * FROM crm_fields WHERE crm_configuration_id = 187 and object_type IN ('tasks', 'event');\n\n# *********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Checkstep%'; # 325, 256, 11753\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 325\nand sa.provider = 'hubspot';\n\nSELECT * FROM activities WHERE uuid_to_bin('7be372e2-1916-4d79-a2f3-ca3db1346db3') = uuid; # 28611085\nSELECT * FROM activities WHERE uuid_to_bin('980f0336-840b-4185-a5a9-30cf8b0749a8') = uuid; # 28719733\nSELECT * FROM activity_summary_logs where activity_id = 28719733;\n\n# *************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Learning%'; # 260, 356, 9444\nSELECT * FROM activity_summary_logs where sent_at BETWEEN '2025-06-09 11:38:00' AND '2025-06-09 11:40:00';\nSELECT * FROM leads WHERE crm_configuration_id = 356 and crm_provider_id = '230045001502770504'; # 823630\nselect * from activities where crm_configuration_id = 356 and lead_id = 841732;\n\nSELECT * from activity_summary_logs al join activities a on a.id = al.activity_id\nwhere a.crm_configuration_id = 356;\n\nselect * from activities where crm_configuration_id = 356\nand actual_end_time between '2025-06-09 11:00:00' and '2025-06-09 12:00:00'\norder by id desc;\n\nselect * from accounts where crm_configuration_id = 356 and crm_provider_id = '230045001514403366' order by id desc;\nselect * from leads where crm_configuration_id = 356 and crm_provider_id = '230045001514275654' order by id desc;\nselect * from contacts where crm_configuration_id = 356 and crm_provider_id = '230045001514403366' order by id desc;\nselect * from opportunities where crm_configuration_id = 356 and crm_provider_id = '230045001514403366' order by id desc;\n\nselect * from team_features where team_id = 260;\nselect * from features where id IN (1,2,4,6,18,19,20,9,10,3,23,24,25,26,27);\n\nSELECT * FROM activities WHERE uuid_to_bin('7be372e2-1916-4d79-a2f3-ca3db1346db3') = uuid;\n\nselect * from crm_fields;\nselect * from crm_layout_entities;\n\nSELECT * FROM teams WHERE name LIKE '%Optable%';\n\n# *************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Teamtailor%'; # 109, 218, 13969\nSELECT * FROM crm_configurations WHERE id = 218;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 109\nand sa.provider = 'salesforce';\nSELECT * FROM activities WHERE uuid_to_bin('675eeaeb-5681-42db-90bc-54c07a604408') = uuid; # 28655939\nSELECT * FROM crm_field_data WHERE activity_id = 28655939;\nSELECT * FROM crm_fields WHERE id in (94491,94493,94498);\n\nselect * from teams where crm_id IS NULL;\n\nSELECT * FROM activities WHERE uuid_to_bin('71aa8a0c-9652-4ff6-bee7-d98ae60abef6') = uuid;\n\n# *************************************************************************************************\nselect * from team_domains where team_id = 399;\nSELECT * FROM teams WHERE name LIKE '%Rydoo%'; # 399, 318, 13207\n\nselect * from calendar_events where id = 5163781;\nSELECT * FROM activities WHERE uuid_to_bin('be2cbc52-7fda-46a0-9ae0-25d9553eafc0') = uuid; # 29443896\nSELECT * FROM participants WHERE activity_id = 29443896;\nselect * from contacts where crm_configuration_id = 318 and email = 'marianne.westeng@strawberry.no';\nselect * from leads where crm_configuration_id = 318 and email = 'marianne.westeng@strawberry.no';\n\nselect * from activities where user_id = 14937 order by created_at ;\n\nselect * from users where id = 14937;\n\nselect * from contacts where crm_configuration_id = 318 and email LIKE '%@strawberry.se';\nselect * from opportunities where crm_configuration_id = 318 and crm_provider_id = '006Sf00000D1WOAIA3';\n\nselect * from activities a join participants p on a.id = p.activity_id\nwhere crm_configuration_id = 318 and a.updated_at > '2025-06-23T08:18:43Z';\n\n# *************************************************************************************************\nSELECT * FROM opportunities WHERE team_id = 379 and crm_provider_id = '39334518886';\nSELECT * FROM opportunities WHERE team_id = 379 order by id desc;\nSELECT * FROM teams WHERE id = 379;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 379 and sociable_id = 13852\nand sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations WHERE id = 307;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 307;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1027;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 307\n and id IN (144750,144855,145158,155227);\n\nSELECT * FROM activities;\n\n\nselect * from activities\nwhere created_at > '2025-07-01 00:00:00'\n# and created_at < '2025-08-01 00:00:00'\nand type not in ('email-outbound', 'email-inbound')\nand account_id is null\nand contact_id is null\nand lead_id is null\nand opportunity_id is not null\n;\nSELECT * FROM activities WHERE id IN (25344155, 25344296, 25501909, 28692187);\nSELECT * FROM crm_configurations WHERE id in (335,301,200);\n\nselect * from crm_fields where crm_configuration_id = 230 and crm_provider_id = 'Age2__c';\n\nSELECT * FROM teams WHERE name LIKE '%Resights%';\nselect * from crm_fields where crm_configuration_id = 1 and object_type = 'opportunity';\n\nselect * from crm_configurations where provider = 'bullhorn'; # 344\nselect * from teams where id IN (442);\n\nselect * from activities\nwhere crm_configuration_id = 177\nand provider = 'amazon-connect'\n order by id desc;\n# and source <> 'gong';\n\nselect * from activity_providers where provider = 'amazon-connect';\n\nSELECT * FROM activities WHERE uuid_to_bin('cec1993b-a7e5-4164-b74d-d680ea51d2f2') = uuid;\n\n\nselect * from crm_configurations where store_transcript = 1;\nSELECT * FROM teams WHERE id IN (80);\n\n# *************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Sedna%'; # 277, 213, 12594\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 277\nand sa.provider = 'salesforce';\n\nselect * from activities where crm_configuration_id = 213 and account_id = 2511502;\n\nselect * from crm_configurations where id = 213;\n\nSELECT * FROM activities WHERE uuid_to_bin('35aa790a-8569-4544-8268-66f9a4a26804') = uuid; # 33981604\nSELECT * FROM participants WHERE activity_id = 33981604;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 337 and object_type = 'task';\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 431\nand sa.provider = 'salesforce';\nSELECT * FROM activities WHERE uuid_to_bin('b5476c7d-19a8-491b-869d-676ea1e857b6') = uuid; # 33997223\nselect * from activity_summary_logs where activity_id = 33997223;\nselect * from activity_notes where activity_id = 33997223;\n\n# ***********************************\nSELECT * FROM teams WHERE name LIKE '%Abode%';\n\n\nselect * from features;\nselect * from teams t\nwhere t.status = 'active'\nand id NOT IN (select team_id from team_features where feature_id = 9)\n;\n\n\nselect * from playbook_layouts where playbook_id = 1725;\nSELECT * FROM activities WHERE uuid_to_bin('65cc283c-4849-49e6-927f-4c281c8fea19') = uuid; # 34297473\nselect * from teams where id = 318;\nselect * from crm_configurations where team_id = 318;\nselect * from playbooks where team_id = 318;\nSELECT * FROM crm_layouts where crm_configuration_id = 381;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1259;\nSELECT * FROM crm_fields WHERE id IN (192938,192936,192939);\n\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1266;\nSELECT * FROM crm_fields WHERE id IN (192980,192991,192997,192998,193064,193067);\n\nSELECT * FROM activities WHERE uuid_to_bin('a902289b-285c-48eb-9cc2-6ad6c5d938f5') = uuid; # 34297533\n\n\n\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 927;\nSELECT * FROM crm_fields WHERE id IN (131668,131669,131670,131671,131676,131797);\n\nSELECT * FROM teams WHERE name LIKE '%Peripass%'; # 351, 281, 12124\nselect * from crm_layouts where crm_configuration_id = 281;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 927;\nselect * from crm_fields where crm_configuration_id = 281 and id in (131668,131669,131670,131671,131676,131797);\nselect * from opportunities where crm_configuration_id = 281;\n\nSELECT * FROM activities WHERE id IN (34211315, 34130075);\nSELECT * FROM crm_field_data WHERE object_id IN (34211315, 34130075);\n\nselect cf.crm_configuration_id, cle.crm_layout_id, cle.id, cf.id from crm_field_data cfd\njoin crm_layout_entities cle on cle.id = cfd.crm_layout_entity_id\njoin crm_fields cf on cle.crm_field_id = cf.id\nwhere cf.deleted_at IS NOT NULL\nGROUP BY cle.id, cf.id;\n\nselect * from crm_layouts where id IN (355);\nselect u.email, t.crm_id, t.* from teams t\njoin users u on u.id = t.owner_id\nwhere crm_id IN (97);\n\nSELECT * FROM crm_fields WHERE id = 96492;\n\nselect * from permissions;\nselect * from permission_role where permission_id = 247;\nselect * from roles;\n\nselect * from migrations;\n# *****************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('291e3c21-11cc-4728-aee7-6e4bedf86d72') = uuid; # 34262174\nSELECT * FROM crm_configurations WHERE id = 301;\nSELECT * FROM teams WHERE id = 343;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 343\nand sa.provider = 'hubspot';\n\nselect * from participants where activity_id = 34262174;\n\nselect * from contacts where crm_configuration_id = 301 and id = 6976326;\nselect * from accounts where crm_configuration_id = 301 and id IN (4647626, 4815829); # 30761335403\n\nselect * from activity_summary_logs where activity_id = 34262174;\n\nselect * from users where status = 1 AND timezone = 'EST';\n\n# ****************************************************************************\nSELECT * FROM users WHERE id = 13869;\nSELECT * FROM crm_configurations WHERE id = 320;\nSELECT * FROM teams WHERE id = 401;\n\nSELECT * FROM activities WHERE uuid_to_bin('2228c16f-10be-48d5-90d4-67385219dc01') = uuid; # 29670601\n\nSELECT * FROM accounts WHERE id = 7761483;\nSELECT * FROM opportunities WHERE id = 6051814;\n\nSELECT * FROM teams WHERE name LIKE '%Seedlegals%';\n\n;select * from opportunities where updated_at > '2025-10-11' AND crm_provider_id = '34713761166';\n\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 177;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 577;\nSELECT * FROM crm_fields WHERE id IN (68458,68459,68480,68497,68524,68530,68554,68618,68662,68781,68810,68898,68981,69049,97467);\n\nSELECT t.id, crm.id, t.name, crm.sync_objects, crm.provider, crm.last_synced_at FROM crm_configurations crm join teams t on t.crm_id = crm.id\nwhere t.status = 'active' AND crm.provider = 'hubspot' AND crm.last_synced_at < '2025-10-22 00:00:00';\n\nSELECT * FROM activities WHERE uuid_to_bin('fa09449f-cba9-496a-b8f3-865cd3c72351') = uuid;\nSELECT * FROM crm_configurations where id = 184;\nSELECT * FROM teams WHERE id = 246;\nSELECT * FROM social_accounts WHERE sociable_id = 9259 and provider = 'hubspot';\n\nSELECT * FROM users WHERE email LIKE '%rhian.old@bud.co.uk%'; # 17700\nSELECT * FROM teams WHERE id = 551;\n\nSELECT * FROM crm_configurations WHERE id = 471;\nSELECT * FROM activities WHERE crm_configuration_id = 471 and crm_provider_id IS NOT NULL;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 471;\nSELECT * FROM crm_fields WHERE id = 307260;\nSELECT * FROM crm_field_values WHERE crm_field_id = 307260;\n\nselect * from crm_layouts where crm_configuration_id = 471;\n\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1547;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1548;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 551 and sa.provider = 'hubspot';\n\nSELECT * FROM teams WHERE name LIKE '%$PCS%';\n\n# ********************************************************************************************************\nselect * from crm_configurations crm\njoin teams t on t.crm_id = crm.id\nwhere t.status = 'active'\nand crm.provider = 'hubspot';\n\n# $slug = 'HUBSPOT_WEBHOOK_SYNC';\n# $team = Jiminny\\Models\\Team::find(2);\n# $feature = Feature::query()->where('slug', $slug)->first();\n# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);\n\n# hubspot_webhook_metrics\n\nselect * from crm_configurations where id = 331; # 416\nSELECT * FROM teams WHERE id = 416;\nSELECT * FROM opportunities WHERE team_id = 190;\n\nSELECT * FROM teams WHERE name LIKE '%Lead Forensics%';\nSELECT sa.id,\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 190 and sa.provider = 'hubspot';\n\n\n\nSELECT * FROM teams WHERE name LIKE '%Rapaport%'; # 431, 337\nSELECT * FROM teams where id = 431;\nSELECT * FROM crm_configurations where team_id = 431;\nSELECT * FROM activity_providers where team_id = 431;\nSELECT * FROM activities where crm_configuration_id = 337 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\nSELECT sa.id,\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 431 and sa.provider = 'salesforce';\n\nSELECT * FROM teams WHERE name LIKE '%BiP%'; # 401, 320\nSELECT * FROM teams where id = 401;\nSELECT * FROM crm_configurations where team_id = 401;\nSELECT * FROM activity_providers where team_id = 401;\nSELECT * FROM activities where crm_configuration_id = 320 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\nSELECT sa.id,\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 401 and sa.provider = 'salesforce';\n\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 307; # 379 - Story Terrace Inc , portalId: 3921157\nSELECT * FROM contacts WHERE team_id = 379 and updated_at > '2026-01-31 11:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 379 and updated_at > '2026-02-01 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 379 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 379 and sa.provider = 'hubspot';\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 485; # 563 - LATUS Group (ad94d501-5d09-44fd-878f-ca3a9f8865c3) , portalId: 3904501\nSELECT * FROM opportunities WHERE team_id = 563 and updated_at > '2026-02-02 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 563 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 338; # 432 - Formalize , portalId: 9214205\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 432 and sa.provider = 'hubspot';\nSELECT * FROM opportunities WHERE team_id = 432 and updated_at > '2026-02-02 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 432 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 436; # 519 - Moxso , portalId: 25531989\nSELECT * FROM opportunities WHERE team_id = 519 and updated_at > '2026-02-02 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 519 and updated_at > '2026-02-04 11:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 96; # 119 - Nourish Care , portalId: 26617984\nSELECT * FROM opportunities WHERE team_id = 119 and updated_at > '2026-02-02 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 119 and updated_at > '2026-02-04 11:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 331; # 416 - The National College , portalId: 7213852\nSELECT * FROM opportunities WHERE team_id = 416 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 416 and updated_at > '2026-02-04 11:00:00' order by updated_at desc;\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 308; # 380 - Foodles , portalId: 7723616\nSELECT * FROM opportunities WHERE team_id = 380 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 380 and updated_at > '2026-02-06 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 379; # 471 - imat-uve , portalId: 9177354\nSELECT * FROM opportunities WHERE team_id = 471 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 471 and updated_at > '2026-02-06 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 465; # 545 - Spotler , portalId: 144759271\nSELECT * FROM opportunities WHERE team_id = 545 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 545 and updated_at > '2026-02-06 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 455; # 537 - indevis , portalId: 25666868\nSELECT * FROM opportunities WHERE team_id = 537 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 537 and updated_at > '2026-02-06 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 200; # 265 - Jobadder , portalId: 6426676\nSELECT * FROM opportunities WHERE team_id = 265 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 265 and updated_at > '2026-02-06 10:30:00' order by updated_at desc;\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 335; # 429 - Eletive , portalId: 6110563\nSELECT * FROM opportunities WHERE team_id = 429 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 429 and updated_at > '2026-02-09 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 363; # 456 - Global Group , portalId: 8901981\nSELECT * FROM opportunities WHERE team_id = 456 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 456 and updated_at > '2026-02-09 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 297; # 369 - Unbiased , portalId: 9229005\nSELECT * FROM opportunities WHERE team_id = 369 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 369 and updated_at > '2026-02-09 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 353; # 449 - Fuuse , portalId: 25781745\nSELECT * FROM opportunities WHERE team_id = 449 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 449 and updated_at > '2026-02-09 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 487; # 566 - Nimbus , portalId: 39982590\nSELECT * FROM opportunities WHERE team_id = 566 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 566 and updated_at > '2026-02-09 10:30:00' order by updated_at desc;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 487;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1630;\nselect * from crm_fields where crm_configuration_id = 487 and\n(uuid_to_bin('4c6b2971-64d4-45b8-b377-427be758b5a5') = uuid or uuid_to_bin('59e368d8-65a0-4b77-b611-db37c99fbe68') = uuid);\nSELECT * FROM crm_field_values WHERE crm_field_id = 375177;\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 420; # 506 - voiio , portalId: 145629154\nSELECT * FROM opportunities WHERE team_id = 506 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 506 and updated_at > '2026-02-10 15:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 479; # 558 - Momice , portalId: 535962\nSELECT * FROM opportunities WHERE team_id = 558 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 558 and updated_at > '2026-02-10 15:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 59; # 80 - Storyclash GmbH , portalId: 4268479\nSELECT * FROM opportunities WHERE team_id = 80 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 80 and updated_at > '2026-02-10 15:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 175; # 203 - Team iAM , portalId: 5534732\nSELECT * FROM opportunities WHERE team_id = 203 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 203 and updated_at > '2026-02-10 15:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 368; # 460 - OneTouch Health , portalId: 5534732183355\nSELECT * FROM opportunities WHERE team_id = 460 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 460 and updated_at > '2026-02-10 15:00:00' order by updated_at desc;\n\n\n\nselect * from users where id = 29643;\nSELECT * FROM crm_field_values WHERE crm_field_id = 375177;\n# ********************************************************************\nSELECT * FROM teams WHERE name LIKE '%Buynomics%'; # 462, 482, 14910\nSELECT * FROM activities WHERE crm_configuration_id = 482\nand type NOT IN ('email-inbound', 'email-outbound')\n# and description like '%The call focused on understanding Welch%'\norder by id desc;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 462 and sa.provider = 'salesforce';\n\nselect * from contacts where crm_configuration_id = 482 and name = 'Cyndall Hill'; # 15504749\nselect * from contacts where id = 10891096; # 482\nSELECT * FROM activities WHERE crm_configuration_id = 482\nand type NOT IN ('email-inbound', 'email-outbound')\nand contact_id = 15504749\norder by id desc;\n\nselect * from activities where id = 36793003; # 96cc7bc1-8622-4d27-92f4-baf664fc1a56, 00UOf00000PDdOXMA1\nselect * from transcription where id = 7646782;\nselect * from ai_prompts where transcription_id = 7646782;\n\n# ********************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('7a8471a3-847e-4822-802b-ddf426bbc252') = uuid; # 37370018\nSELECT * FROM activity_summary_logs WHERE activity_id = 37370018;\nSELECT * FROM teams WHERE id = 555;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 555 and sa.provider = 'hubspot';\n\n# ********************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('7c17b8aa-09df-4f85-a0f7-51f47afd712d') = uuid; # 37395250\nSELECT * FROM activities WHERE uuid_to_bin('14d60388-260d-494b-aa0d-63fdb1c78026') = uuid; # 37395250\n\nSELECT a.* FROM activities a JOIN crm_configurations c on c.id = a.crm_configuration_id\nwhere a.type IN ('softphone', 'softphone-outbound') and c.provider = 'hubspot'\nand a.provider NOT IN ('hubspot')\n# and a.provider IN ('salesloft')\n# and c.id NOT IN (70)\n# and a.duration > 30\n# and actual_start_time > '2026-02-05 00:00:00'\norder by a.id desc;\n\nSELECT * FROM activities WHERE id = 37549787;\nSELECT * FROM crm_profiles WHERE user_id = 17613;\n\nSELECT * FROM crm_configurations WHERE id = 70;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 93 and sa.provider = 'hubspot';\n\nSELECT asf.activity_search_id, asf.id, asf.value\nFROM activity_search_filters asf\nWHERE asf.filter = 'group_id'\nAND asf.value IN (\n SELECT CONCAT(\n HEX(SUBSTR(uuid, 5, 4)), '-',\n HEX(SUBSTR(uuid, 3, 2)), '-',\n HEX(SUBSTR(uuid, 1, 2)), '-',\n HEX(SUBSTR(uuid, 9, 2)), '-',\n HEX(SUBSTR(uuid, 11))\n )\n FROM groups\n WHERE deleted_at IS NOT NULL\n);\n\nSELECT * FROM crm_configurations WHERE id = 373; # KPSBremen.de 465 # - no social account\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 465 and sa.provider = 'hubspot';\n\nselect * from crm_configurations where id = 494;\n\nSELECT * FROM teams WHERE name LIKE '%splose%'; # 572, 495, 18708\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 572 and sa.provider = 'pipedrive';\n\nselect * from opportunities where team_id = 572\n# and name like '%Onebright%'\n# and is_closed = 1 and is_won = 0\n order by id desc;\n\n\nselect * from users where deleted_at is null and status = 2;\n\nselect * from contacts where id = 17900517;\nselect * from accounts where id = 10109838;\nselect * from opportunities where id = 6955880;\n\nselect * from opportunity_contacts where opportunity_id = 6955880;\nselect * from opportunity_contacts where contact_id = 17900517;\n\nselect * from contact_roles cr join crm_configurations crm on cr.crm_configuration_id = crm.id\nwhere crm.provider != 'salesforce';\n\nSELECT * FROM activities WHERE uuid_to_bin('adcb8331-5988-4353-834e-383a355abba2') = uuid; # 38056424, crm 104659682404\nselect * from teams where id = 456;\nSELECT * FROM crm_configurations WHERE id = 363;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 456 and sa.provider = 'hubspot';\n\nselect * from crm_layouts where crm_configuration_id = 363;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id IN (1203, 1204, 1635);\nSELECT * FROM crm_fields WHERE id IN (181536, 181538, 213455);\n\nSELECT * FROM teams WHERE name LIKE '%Electric%'; # 342, 272, 12767\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 342 and sa.provider = 'pipedrive';\nSELECT * FROM opportunities WHERE crm_configuration_id = 272 and name like 'NORTHUMBRIA POL%'; # and updated_at > '2025-07-01 00:00:00';\nSELECT * FROM opportunities WHERE crm_configuration_id = 272 order by remotely_created_at asc; # and updated_at > '2025-07-01 00:00:00';\nSELECT * FROM opportunities WHERE crm_configuration_id = 272 and updated_at > '2026-01-01 00:00:00';\nSELECT * FROM crm_fields WHERE crm_configuration_id = 272 and object_type = 'opportunity';\nSELECT * FROM crm_field_values WHERE crm_field_id = 127164;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 342 and sa.provider = 'pipedrive';\n\nSELECT * FROM teams WHERE id = 472;\nSELECT * FROM crm_configurations WHERE id = 380;\nselect * from activities where id = 38285673; # 38285673\nSELECT * FROM users WHERE id = 16942;\nSELECT * FROM groups WHERE id = 1964;\nSELECT * FROM playbooks WHERE id = 2033;\n\nselect * from teams where created_at > '2026-03-09';\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 499; # 1065\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1678;\n\nSELECT * FROM teams WHERE id = 575;\nselect * from opportunities where team_id = 575;\n\nSELECT * FROM activities WHERE uuid_to_bin('96b1261f-2357-49f9-ab38-23ce12008ea0') = uuid;\n\nselect * from contacts c\nwhere c.crm_configuration_id = 370 order by c.updated_at desc;\n\nSELECT * FROM participants where activity_id = 38833541;\nSELECT * FROM participants where activity_id = 39216301;\nSELECT * FROM activity_summary_logs where activity_id = 39216301;\nSELECT * FROM activities WHERE uuid_to_bin('c7d99fbe-1fb1-41f2-8f4d-52e2bf70e1e9') = uuid; # 38833541, crm 478116564181\nSELECT * FROM activities WHERE uuid_to_bin('2e6ff4d3-9faa-447a-a8c1-9acde4d885ae') = uuid; # 39216301, crm 480171536586\nselect * from crm_profiles where crm_configuration_id = 319 and crm_provider_id = 525785080;\nselect * from opportunities where crm_configuration_id = 319 and crm_provider_id = 410150124747;\nselect * from accounts where crm_configuration_id = 319 and crm_provider_id = 47150650569;\nselect * from contacts where crm_configuration_id = 319 and crm_provider_id IN ('665587441856', '742723347700');\n# owner 13236 525785080\n# contact 1 16779180 665587441856 - activity - Alex Howes alex@supportroom.com created 2026-01-26\n# contact 2 19247563 742723347700 - ash@supportroom.com 2026-03-24\n# company 4176133 47150650569\n# deal 7100953 410150124747\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 400 and sa.provider = 'hubspot';\n\nselect * from features;\nselect * from team_features where feature_id = 40;\n\nselect * from teams where id = 556; # owner: 18101, crm: 477\nselect * from crm_configurations where id = 477;\nSELECT * FROM users WHERE id = 18101;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 556 and sa.provider = 'integration-app';\n\nselect * from opportunities where id = 7594349;\nselect * from opportunity_stages where opportunity_id = 7594349 order by created_at desc;\nselect * from business_processes where id = 6024;\nselect * from business_process_stages where stage_id = 16352;\nselect * from business_process_stages where business_process_id = 6024;\nselect * from stages where team_id = 459;\nselect * from teams where id = 459;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 459 and sa.provider = 'hubspot';\n\nSELECT os.stage_id, s.crm_provider_id, s.name, COUNT(*) as cnt\nFROM opportunity_stages os\nJOIN stages s ON s.id = os.stage_id\nWHERE os.opportunity_id = 7594349\nGROUP BY os.stage_id, s.crm_provider_id, s.name\nORDER BY cnt DESC;\n\nSELECT s.id, s.crm_provider_id, s.name, s.team_id, s.crm_configuration_id\nFROM stages s\nJOIN business_process_stages bps ON bps.stage_id = s.id\nWHERE bps.business_process_id = 6024\nAND s.crm_provider_id = 'contractsent';\n\nselect * from stages where id IN (16352,20612,18281,7344,16378,16309,5036,15223,14535,6293,12098,11607)\n\nSELECT * FROM teams WHERE name LIKE '%Pulsar Group%'; # 472, 380, 15138, raza.gilani@vuelio.com\nselect * from playbooks where team_id = 472; # event 226147\nSELECT * FROM playbook_categories WHERE playbook_id = 2288;\nSELECT * FROM crm_fields WHERE id = 226147;\nSELECT * FROM crm_field_values WHERE crm_field_id = 226147;\n\nSELECT * FROM crm_configurations WHERE id = 380;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 472 and sa.provider = 'salesforce';","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Cascade","depth":3,"role_description":"text"},{"role":"AXButton","text":"Options","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Structure","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Bookmarks","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Welcome to SonarQube for IDE","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Pull Requests","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Problems","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Terminal","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"TODO","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Windsurf Console","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"SonarQube for IDE","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Git","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Services","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Find","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Notifications","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cascade","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Database","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AI Chat","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More","depth":3,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Tests passed: 15 (a minute ago)","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"Hide processes (1)","depth":3,"role_description":"text"},{"role":"AXStaticText","text":"Windsurf Teams","depth":3,"help_text":"Windsurf","role_description":"text"},{"role":"AXStaticText","text":"279:1","depth":3,"help_text":"Go to Line","role_description":"text"},{"role":"AXStaticText","text":"Language Services Button","depth":3,"role_description":"text"},{"role":"AXStaticText","text":"UTF-8","depth":3,"help_text":"File Encoding: UTF-8","role_description":"text"},{"role":"AXStaticText","text":"Column selection mode","depth":3,"help_text":"Column selection mode","role_description":"text"},{"role":"AXStaticText","text":"4 spaces","depth":3,"role_description":"text"},{"role":"AXStaticText","text":"JSON: schema.json","depth":3,"bounds":{"left":0.0,"top":0.0,"width":0.0875,"height":0.025555555},"help_text":"JSON Schema: https://getcomposer.org/schema.json","role_description":"text"}]...
|
-7588596953593251659
|
2146738724037637229
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Services\Kiosk\AutomatedReports;
use Carbon\CarbonImmutable;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityActualDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityUpdatedDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\DealInsights\ClosingPeriodFilter;
use Jiminny\Component\ActivitySearch\FilterDefinitionCollection;
use Jiminny\Component\ActivitySearch\Service\ActivitySearch;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\Activity\SearchFilter;
use Jiminny\Models\User;
use Jiminny\Repositories\ElasticActivityRepository;
use Jiminny\Services\Kiosk\AutomatedReports\AskJiminnyReportActivityService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\VO\Repository\OnDemandActivitySearch\Criteria;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
class AskJiminnyReportActivityServiceTest extends TestCase
{
private ActivitySearch&MockObject $activitySearch;
private ElasticActivityRepository&MockObject $elasticRepository;
private LoggerInterface&MockObject $logger;
private AskJiminnyReportActivityService $service;
protected function setUp(): void
{
$this->activitySearch = $this->createMock(ActivitySearch::class);
$this->elasticRepository = $this->createMock(ElasticActivityRepository::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->service = new AskJiminnyReportActivityService(
$this->activitySearch,
$this->elasticRepository,
$this->logger,
);
}
private function makeFilter(string $key, ?string $value): SearchFilter&MockObject
{
$filter = $this->createMock(SearchFilter::class);
$filter->method('getFilterProperty')->willReturn($key);
$filter->method('getFilterValue')->willReturn($value);
return $filter;
}
private function makeUser(): User&MockObject
{
$tz = new \DateTimeZone('UTC');
$user = $this->createMock(User::class);
$user->method('getTimezone')->willReturn($tz);
$user->method('getId')->willReturn(1);
$user->method('getUuid')->willReturn('user-uuid');
return $user;
}
private function makeSavedSearch(array $filters): Search&MockObject
{
$savedSearch = $this->createMock(Search::class);
$savedSearch->method('getId')->willReturn(42);
$savedSearch->method('getFilters')->willReturn(new \Illuminate\Support\LazyCollection($filters));
return $savedSearch;
}
public function testGetActivityIdsForSavedSearchReturnsIds(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->expects($this->once())
->method('getArrayFilterKeys')
->with($user)
->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->expects($this->once())
->method('onDemandSearchIdsOnly')
->willReturn(['id-1', 'id-2', 'id-3']);
$this->logger->expects($this->once())
->method('info')
->with('[AskJiminnyReport] Fetched activity IDs for saved search');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1', 'id-2', 'id-3'], $result);
}
public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->expects($this->once())->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEmpty($result);
}
public function testGetActivityIdsFiltersOutDateFilters(): void
{
$user = $this->makeUser();
$nonDateFilter = $this->makeFilter('owner_id', '123');
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');
$updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');
$updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');
$savedSearch = $this->makeSavedSearch([
$nonDateFilter,
$startDateFilter,
$endDateFilter,
$updatedFromFilter,
$updatedToFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
}
public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void
{
$user = $this->makeUser();
$closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');
$closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');
$regularFilter = $this->makeFilter('rep_id', '99');
$savedSearch = $this->makeSavedSearch([
$closingStartFilter,
$closingEndFilter,
$regularFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesArrayFilters(): void
{
$user = $this->makeUser();
$filter1 = $this->makeFilter('outcome', 'positive');
$filter2 = $this->makeFilter('outcome', 'negative');
$savedSearch = $this->makeSavedSearch([$filter1, $filter2]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesScalarFilters(): void
{
$user = $this->makeUser();
$filter = $this->makeFilter('direction', 'inbound');
$savedSearch = $this->makeSavedSearch([$filter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-5'], $result);
}
public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
$this->assertFalse($capturedCriteria->isFirstRequest());
}
public function testGetActivityIdsLogsWithCorrectContext(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);
$this->logger->expects($this->once())
->method('info')
->with(
'[AskJiminnyReport] Fetched activity IDs for saved search',
$this->callback(fn ($context) => $context['saved_search_id'] === 42
&& $context['user_id'] === 1
&& $context['activity_count'] === 2)
);
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
}
public static function frequencyDateRangeProvider(): array
{
$now = CarbonImmutable::parse('2025-06-16 12:00:00');
return [
'daily' => [
AutomatedReportsService::FREQUENCY_DAILY,
$now->subDay()->startOfDay()->format('Y-m-d H:i:s'),
$now->subDay()->endOfDay()->format('Y-m-d H:i:s'),
],
'weekly' => [
AutomatedReportsService::FREQUENCY_WEEKLY,
$now->subWeek()->startOfWeek()->format('Y-m-d H:i:s'),
$now->subWeek()->endOfWeek()->format('Y-m-d H:i:s'),
],
'monthly' => [
AutomatedReportsService::FREQUENCY_MONTHLY,
$now->subMonthNoOverflow()->startOfMonth()->format('Y-m-d H:i:s'),
$now->subMonthNoOverflow()->endOfMonth()->format('Y-m-d H:i:s'),
],
'quarterly' => [
AutomatedReportsService::FREQUENCY_QUARTERLY,
$now->subQuarterNoOverflow()->startOfQuarter()->format('Y-m-d H:i:s'),
$now->subQuarterNoOverflow()->endOfQuarter()->format('Y-m-d H:i:s'),
],
];
}
/**
* @dataProvider frequencyDateRangeProvider
*/
public function testGetActivityIdsInjectsDateRangeForFrequency(
string $frequency,
string $expectedStartDate,
string $expectedEndDate,
): void {
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);
$this->assertNotNull($capturedCriteria);
$this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void
{
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');
$savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);
$this->assertNotNull($capturedCriteria);
$this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
27
9
23
3
105
Previous Highlighted Error
Next Highlighted Error
SELECT * FROM team_features where team_id = 1;
SELECT * FROM teams WHERE name LIKE '%Vixio%'; # 340,270,11922
SELECT * FROM users WHERE team_id = 340; # 12015
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 340
and sa.provider = 'salesforce';
# and sa.provider = 'salesloft';
select * from crm_fields where crm_configuration_id = 270 and object_type = 'event';
# 125558 - Event Type - Event_Type__c
# 125552 - Event Status - Event_Status__c
SELECT * FROM sidekick_settings WHERE team_id = 340;
SELECT * FROM crm_field_values WHERE crm_field_id in (125552);
select * from activities where crm_configuration_id = 270
and type = 'conference' and crm_provider_id IS NOT NULL
and actual_start_time > '2024-09-16 09:00:00' order by scheduled_start_time;
SELECT * FROM activities WHERE id = 20871677;
SELECT * FROM crm_field_data WHERE activity_id = 20871677;
select * from crm_layouts where crm_configuration_id = 270;
select * from crm_layout_entities where crm_layout_id in (886,887);
SELECT * FROM crm_configurations WHERE id = 270;
select * from playbooks where team_id = 340; # 1514
select * from groups where team_id = 340;
SELECT * FROM crm_fields WHERE id IN (125393, 125401);
select g.name as 'team name', p.name as 'playbook name', f.label as 'activity type field' from groups g
join playbooks p on g.playbook_id = p.id
join crm_fields f on p.activity_field_id = f.id
where g.team_id = 340;
SELECT * FROM activities WHERE uuid_to_bin('0c180357-67d2-419e-a8c3-b832a3490770') = uuid; # 20448716
select * from crm_field_data where object_id = 20448716;
select * from activities where crm_configuration_id = 270 and provider = 'salesloft' order by id desc;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%CybSafe%'; # 343,273,12008
select * from opportunities where team_id = 343;
select * from opportunities where team_id = 343 and crm_provider_id = '18099102526';
select * from opportunities where team_id = 343 and account_id = 945217482;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 343
and sa.provider = 'hubspot';
select * from accounts where team_id = 343 order by name asc;
select * from stages where crm_configuration_id = 273 and type = 'opportunity';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Voyado%'; # 353,283,12143
SELECT * FROM activities WHERE crm_configuration_id = 283 and account_id = 3777844 order by id desc;
SELECT * FROM accounts WHERE team_id = 353 AND name LIKE '%Salesloft%';
SELECT * FROM activities WHERE id = 20717903;
select * from participants where activity_id IN (20929172,20928605,20928468,20926272,20926271,20926270,20926269,20916499,20916454,20916436,20916435,20900015,20900014,20900013,20897312,20897243,20897241,20897237,20897232,20897229,20893648,20893231,20893230,20893229,20893228,20889784,20885039,20885038,20885037,20885036,20885035,20882728,20882708,20882703,20882702,20869828,20869811,20869806,20869801,20869799,20869798,20869796,20869795,20869794,20869761,20869760,20869759,20868688,20868687,20850340,20847195,20841710,20833967,20827021,20825307,20825305,20825297,20824615,20824400,20823927,20821760,20795588,20794233,20794057,20793710,20785811,20781789,20781394,20781307,20762651,20758453,20758282,20757323,20756643,20756636,20756629,20756627,20756606,20756605,20756604,20756603,20756602,20756600,20756599,20756598,20756595,20756594,20756589,20756587,20756577,20756573,20748918,20748386,20748385,20748384,20748383,20748382,20748381,20748380,20748379,20748377,20748375,20748373,20743301,20717905,20717904,20717903,20717901,20717899);
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 353
and sa.provider = 'salesforce';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%modern world business solutions%'; # 345,275,12016, [EMAIL]
SELECT * FROM activities WHERE uuid_to_bin('3921d399-3fef-4609-a291-b0097a166d43') = uuid;
# id: 20940638, user: 12022, contact: 5305871
SELECT * FROM activity_summary_logs WHERE activity_id = 20940638;
select * from contacts where team_id = 345 and crm_provider_id = '30891432415' order by name asc; # 5305871
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 345
and sa.provider = 'hubspot';
select * from users where team_id = 345 and id = 12022;
SELECT * FROM crm_profiles WHERE user_id = 12022;
SELECT * FROM participants WHERE activity_id = 20940638;
SELECT * FROM users u
JOIN crm_profiles cp ON u.id = cp.user_id
WHERE u.team_id = 345;
select * from contacts where team_id = 345 and crm_provider_id = '30880813535' order by name desc; # 5305871
select * from team_features where team_id = 345;
SELECT * FROM activities WHERE uuid_to_bin('11701e2d-2f82-4dab-a616-1db4fad238df') = uuid; # 21115197
SELECT * FROM participants WHERE activity_id = 20897406;
SELECT * FROM activities WHERE uuid_to_bin('63ba55cd-1abc-447d-83da-0137000005b7') = uuid; # 20953912
SELECT * FROM activities WHERE crm_configuration_id = 275 and provider = 'ringcentral' and title like '%1252629100%';
SELECT * FROM activities WHERE id = 20946641;
SELECT * FROM crm_profiles WHERE user_id = 10211;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Lunio%'; # 120,97,10984, [EMAIL]
SELECT * FROM opportunities WHERE crm_configuration_id = 97 and crm_provider_id = '006N1000006c5PpIAI';
select * from stages where crm_configuration_id = 97 and type = 'opportunity';
select * from opportunities where team_id = 120;
select * from crm_configurations crm join teams t on crm.id = t.crm_id
where 1=1
AND t.current_billing_plan IS NOT NULL
AND crm.auto_sync_activity = 0
and crm.provider = 'hubspot';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Exclaimer%'; # 270,205,10053,[EMAIL]
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 270
and sa.provider = 'salesforce';
SELECT * FROM activities WHERE uuid_to_bin('b54df794-2a9a-4957-8d80-09a600ead5f8') = uuid; # 21637956
SELECT * FROM crm_profiles WHERE user_id = 11446;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Cygnetise%'; # 372,300,12554, [EMAIL]
select * from playbooks where team_id = 372;
select * from crm_fields where crm_configuration_id = 300 and object_type = 'event'; # 141340
SELECT * FROM crm_field_values WHERE crm_field_id = 141340;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 372
and sa.provider = 'salesforce';
select * from crm_profiles where crm_configuration_id = 300;
SELECT * FROM crm_configurations WHERE team_id = 372;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Planday%'; # 291,242,11501,[EMAIL]
SELECT * FROM opportunities WHERE team_id = 291 and crm_provider_id = '006bG000005DO86QAG'; # 3207756
select * from crm_field_data where object_id = 3207756;
SELECT * FROM crm_fields WHERE id = 111834;
select f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value
FROM crm_fields f
JOIN crm_field_data fd ON f.id = fd.crm_field_id
WHERE f.crm_configuration_id = 242
AND f.object_type = 'opportunity'
AND fd.object_id IN (3207756)
ORDER BY fd.object_id, fd.updated_at;
SELECT * FROM crm_configurations WHERE auto_connect = 1;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Tour%'; # 187,209,8150,[EMAIL]
select * from group_deal_risk_types drgt join groups g on drgt.group_id = g.id
where g.team_id = 187;
select * from `groups` where team_id = 187;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 187
and sa.provider = 'salesforce';
# Destination - 98870 - Destination__c
# Stage - 79014 - StageName
# Land Arrangement - 98856 - Land_Arrangement__c
# Flight - 98848 - Flight__c
# Last activity date - 98812 - LastActivityDate
# Last modified date - 98809 - LastModifiedDate
# Last inbound mail timestamp - 99151 - Last_Inbound_Mail_Timestamp__c
# next call - 98864 - Next_Call__c
select * from crm_fields where crm_configuration_id = 209 and object_type = 'opportunity';
SELECT * FROM crm_layouts WHERE crm_configuration_id = 209;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 682;
select * from opportunities where team_id = 187 and name LIKE'%Muriel Sal%';
select * from opportunities where team_id = 187 and user_id = 9951 and is_closed = 0;
select * from activities where opportunity_id = 3538248;
SELECT * FROM crm_profiles WHERE user_id = 8150;
select * from deal_risks where opportunity_id = 3538248;
select * from teams where crm_id IS NULL;
SELECT opp.id AS opportunity_id,
u.group_id AS group_id,
MAX(
CASE
WHEN a.type IN ("sms-inbound", "sms-outbound") THEN a.created_at
ELSE a.actual_end_time
END) as last_date
FROM opportunities opp
left join activities a on a.opportunity_id = opp.id
inner join users u on opp.user_id = u.id
where opp.user_id IN (9951)
AND opp.is_closed = 0
and a.status IN ('completed', 'received', 'delivered') OR a.status IS NULL
group by opp.id;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Cybsafe%'; # 343,301,12008,[EMAIL]
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 343
and sa.provider = 'hubspot';
SELECT * FROM crm_profiles WHERE crm_configuration_id = 301;
SELECT * FROM contacts WHERE id = 6612363;
SELECT * FROM accounts WHERE id = 4235676;
SELECT * FROM opportunities WHERE crm_configuration_id = 301 and crm_provider_id = 32983784868;
select * from opportunity_stages where opportunity_id = 4503759;
# SELECT * FROM opportunities WHERE id = 4569937;
select * from activities where crm_configuration_id = 301;
SELECT * FROM activities WHERE uuid_to_bin('d3b2b28b-c3d0-4c2d-8ed0-eef42855278a') = uuid; # 26330370
SELECT * FROM participants WHERE activity_id = 26330370;
SELECT * FROM teams WHERE id = 375;
select * from playbooks where team_id = 375;
select * from stages where crm_configuration_id = 301 and type = 'opportunity';
select * from teams;
select * from contact_roles;
SELECT * FROM opportunities WHERE team_id = 343 and user_id = 12871 and close_date >= '2024-11-01';
select * from users u join crm_profiles cp on cp.user_id = u.id where u.team_id = 343;
SELECT * FROM crm_field_data WHERE object_id = 3771706;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 343
and sa.provider = 'hubspot';
SELECT * FROM crm_fields WHERE crm_configuration_id = 301 and object_type = 'opportunity'
and crm_provider_id LIKE "%traffic_light%";
SELECT * FROM crm_field_values WHERE crm_field_id IN (144020,144048,144111,144113,144126,144481,144508,144531);
SELECT fd.* FROM opportunities o
JOIN crm_field_data fd ON o.id = fd.object_id
WHERE o.team_id = 343
# and o.user_id IS NOT NULL
and fd.crm_field_id IN (144020,144048,144111,144113,144126,144481,144508,144531)
and fd.value != ''
order by value desc
# group by o.id
;
SELECT * FROM opportunities WHERE id = 3769843;
SELECT * FROM teams WHERE name LIKE '%Tour%'; # 187,209,8150, [EMAIL]
SELECT * FROM crm_layouts WHERE crm_configuration_id = 209;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 682;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Funding Circle%'; # 220,177,8603,[EMAIL]
SELECT * FROM activities WHERE uuid_to_bin('7a40e99b-3b37-4bb1-b983-325b81801c01') = uuid; # 23139839
SELECT * FROM opportunities WHERE id = 3855992;
SELECT * FROM users WHERE name LIKE '%Angus Pollard%'; # 8988
SELECT * FROM teams WHERE name LIKE '%Story Terrace%'; # 379, 307, 12894
SELECT * FROM crm_fields WHERE crm_configuration_id = 307 and object_type != 'opportunity';
select * from contacts where team_id = 379 and name like '%bebro%'; # 5874411, crm: 77229348507
SELECT * FROM crm_field_data WHERE object_id = 5874411;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 379
and sa.provider = 'hubspot';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%mentio%'; # 117, 94, 6371, [EMAIL]
SELECT * FROM activities WHERE uuid_to_bin('82939311-1af0-4506-8546-21e8d1fdf2c1') = uuid;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Tourlane%'; # 187, 209, 8150, [EMAIL]
SELECT * FROM opportunities WHERE team_id = 187 and crm_provider_id = '006Se000008xfvNIAQ'; # 3537793
select * from generic_ai_prompts where subject_id = 3537793;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Lunio%'; # 120, 97, 10984, [EMAIL]
SELECT * FROM crm_configurations WHERE id = 97;
SELECT * FROM crm_layouts WHERE crm_configuration_id = 97;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 355;
SELECT * FROM crm_fields WHERE id = 32682;
select cfd.value, o.* from opportunities o
join crm_field_data cfd on o.id = cfd.object_id and cfd.crm_field_id = 32682
where team_id = 120
and cfd.value != ''
;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 120
and sa.provider = 'salesforce';
select * from opportunities where team_id = 120 and crm_provider_id = '006N1000007X8MAIA0';
SELECT * FROM crm_field_data WHERE object_id = 2313439;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE id = 410;
SELECT * FROM teams WHERE name LIKE '%Local Business Oxford%';
select * from scorecards where team_id = 410;
select * from scorecard_rules;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Funding%'; # 220, 177, 8603, [EMAIL]
select * from activities a
join opportunities o on a.opportunity_id = o.id
join users u on o.user_id = u.id
where a.crm_configuration_id = 177 and a.type LIKE '%email-out%'
# and a.actual_end_time > '2024-12-16 00:00:00'
# and o.remotely_created_at > '2024-12-01 00:00:00'
# and u.group_id = 1014
and u.id = 9021
order by a.id desc;
SELECT * FROM opportunities WHERE id in (3981384,4017346);
SELECT * FROM users WHERE team_id = 220 and id IN (8775, 11435);
select * from users where id = 9021;
select * from inboxes where user_id = 9021;
select * from inbox_emails where inbox_id = 1349 and email_date > '2024-12-18 00:00:00';
select * from email_messages where team_id = 220
and orig_date > '2024-12-16 00:00:00' and orig_date < '2024-12-19 00:00:00'
and subject LIKE '%Personal%'
# and 'from' = '[EMAIL]'
;
select * from activities a
join opportunities o on a.opportunity_id = o.id
where a.user_id = 9021 and a.type LIKE '%email-out%'
and a.actual_end_time > '2024-12-18 00:00:00'
and o.user_id IS NOT NULL
and o.remotely_created_at > '2024-12-01 00:00:00'
order by a.id desc;
SELECT * FROM opportunities WHERE team_id = 220 and name LIKE '%Right Car move Limited%' and id = 3966852;
select * from activities where crm_configuration_id = 177 and type LIKE '%email%' and opportunity_id = 3966852 order by id desc;
select * from team_settings where name IN ('useCloseDate');
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Hurree%'; # 104, 81, 6175, [EMAIL]
SELECT * FROM opportunities WHERE team_id = 104 and name = 'PropOp';
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 104
and sa.provider = 'hubspot';
select * from crm_configurations where last_synced_at > '2025-01-19 01:00:00'
select * from teams where crm_id IS NULL;
select t.name as 'team', u.name as 'owner', u.email, u.phone
from teams t
join activity_providers ap on t.id = ap.team_id
join users u on t.owner_id = u.id
where 1=1
and t.status = 'active'
and ap.is_enabled = 1
# and u.status = 1
and ap.provider = 'ms-teams';
select * from crm_configurations where provider = 'bullhorn'; # 344
SELECT * FROM teams WHERE id = 442; # 14293
select * from users where team_id = 442;
select * from social_accounts sa where sa.sociable_id = 14293;
select * from invitations where team_id = 442;
# [PASSWORD_DOTS]
SELECT * FROM users WHERE email LIKE '%[EMAIL]%'; # 14022
SELECT * FROM teams WHERE id = 429;
select * from opportunities where team_id = 429 and crm_provider_id IN (16157415775, 22246219645);
select * from activities where opportunity_id in (4340436,4353519);
select * from transcription where activity_id IN (25630961,25381771);
select * from generic_ai_prompts where subject_id IN (4353519);
SELECT
a.id as activity_id,
a.opportunity_id,
a.type as activity_type,
a.language,
CONCAT(a.title, a.description) AS mail_content,
e.from AS mail_from,
e.to AS mail_to,
e.subject AS mail_subject,
e.body AS mail_body,
p.type as prompt_type,
p.status as prompt_status,
p.content AS prompt_content,
a.actual_start_time as created_at
FROM activities a
LEFT JOIN ai_prompts p ON a.transcription_id = p.transcription_id AND p.deleted_at IS NULL
LEFT JOIN email_messages e ON a.id = e.activity_id
WHERE a.actual_start_time > '2024-01-01 00:00:00'
AND a.opportunity_id IN (4353519)
AND a.status IN ('completed', 'received', 'delivered')
AND a.deleted_at IS NULL
AND a.type NOT IN ('sms-inbound', 'sms-outbound')
ORDER BY a.opportunity_id ASC, a.id ASC;
SELECT * FROM users WHERE name LIKE '%George Fierstone%'; # 14293
SELECT * FROM teams WHERE id = 442;
SELECT * FROM crm_configurations WHERE id = 344;
select * from team_features where team_id = 442;
select * from groups where team_id = 442;
select * from playbooks where team_id = 442;
select * from playbook_categories where playbook_id = 1729;
select * from crm_fields where crm_configuration_id = 344 and id = 172024;
SELECT * FROM crm_field_values WHERE crm_field_id = 172024;
select * from crm_layouts where crm_configuration_id = 344;
select * from playbook_layouts where playbook_id = 1729;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Learning%'; # 260, 221, 9444
select s.*
# , s.sent_at, u.name, a.*
from activity_summary_logs s
inner join activities a on a.id = s.activity_id
inner join users u on u.id = a.user_id
where a.crm_configuration_id = 356
and s.sent_at > date_sub(now(), interval 60 day)
order by a.actual_end_time desc;
select * from activities a
# inner join activity_summary_logs s on s.activity_id = a.id
where a.crm_configuration_id = 356 and a.actual_end_time > date_sub(now(), interval 60 day)
# and a.crm_provider_id is not null
# and provider <> 'ringcentral'
and status = 'completed'
order by a.actual_end_time desc;
select * from teams order by id desc; # 17328, 32, 17830, [EMAIL]
SELECT * FROM users;
SELECT * FROM users where team_id = 260 and status = 1; # 201 - 150 active
SELECT * FROM teams WHERE id = 260;
select * from team_settings where team_id = 260;
select * from crm_configurations where team_id = 260;
SELECT * FROM crm_layouts WHERE crm_configuration_id = 356;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 1184;
select * from accounts where crm_configuration_id = 221 order by id desc; # 7000
select * from leads where crm_configuration_id = 221 order by id desc; # 0
select * from contacts where crm_configuration_id = 221 order by id desc; # 200 000
select * from opportunities where crm_configuration_id = 221 order by id desc; # 0
select * from crm_profiles where crm_configuration_id = 221 order by id desc; # 23
select * from crm_fields where crm_configuration_id = 221;
select * from crm_field_values where crm_field_id = 5302 order by id desc;
select * from crm_layouts where crm_configuration_id = 221 order by id desc;
select * from stages where crm_configuration_id = 221 order by id desc;
select * from accounts where crm_configuration_id = 356 order by id desc; # 7000
select * from leads where crm_configuration_id = 356 order by id desc; # 0
select * from contacts where crm_configuration_id = 356 order by id desc; # 200 000
select * from opportunities where crm_configuration_id = 356 order by id desc; # 0
select * from crm_profiles where crm_configuration_id = 356 order by id desc; # 23
select * from crm_fields where crm_configuration_id = 356;
select * from crm_field_values where crm_field_id = 5302 order by id desc;
select * from crm_layouts where crm_configuration_id = 356 order by id desc;
select * from stages where crm_configuration_id = 356 order by id desc;
select * from playbooks where team_id = 260 order by id desc; # 4 (2 deleted)
select * from groups where team_id = 260 order by id desc; # 27 groups, (2 deleted)
select * from playbook_layouts where playbook_id IN (1410,1409,1276,1254); # 4
select ce.* from calendars c
join users u on c.user_id = u.id
join calendar_events ce on c.id = ce.calendar_id
where u.team_id = 260
and (ce.start_time > '2025-02-21 00:00:00')
;
# calendar events 1207
#
select * from opportunities where team_id = 260;
SELECT * FROM crm_field_data WHERE object_id = 4696496;
select * from activities where crm_configuration_id = 356 and crm_provider_id IS NOT NULL;
select * from activities where crm_configuration_id IN (221) and provider NOT IN ('ms-teams', 'uploader', 'zoom-bot')
# and type = 'conference' and status = 'scheduled' and activities.is_internal = 0
and created_at > '2024-03-01 00:00:00'
order by id desc; # 880 000, ringcentral, avaya
SELECT * FROM participants WHERE activity_id = 26371744;
# all activities 942 000 +
# conference 7385 - scheduled 984 - external 343
select * from activities where id = 26321812;
select * from participants where activity_id = 26321812;
select * from participants where activity_id in (26414510,26414514,26414516,26414604,26414653,26414655);
select * from leads where id in (720428,689175,731546,645866,621037);
select * from users where id = 13841;
select * from opportunities where user_id = 9541;
select * from stages where id = 15900;
select * from accounts where
# id IN (4160055,5053725,4965303,4896434)
id in (4584518,3249934,3218025,3891133,3399450,4172999,4485161,3101785,4587203,3070816,2870343,2870341,3563940,4550846,3424464,3249963,2870342)
;
select * from activities where id = 26654935;
SELECT * FROM opportunities WHERE id = 4803458;
SELECT * FROM opportunities where team_id = 260 and user_id = 13841 AND stage_id = 15900;
SELECT id, uuid, provider, type, lead_id, account_id, contact_id, opportunity_id, stage_id, status, recording_state, title, actual_start_time, actual_end_time
FROM activities WHERE user_id = 13841 AND opportunity_id IN (4729783, 4731717, 4731726, 4732064, 4732849, 4803458, 4813213);
SELECT DISTINCT
o.id, o.stage_id, s.name, a.title,
a.*
FROM activities a
# INNER JOIN tracks t ON a.id = t.activity_id
INNER JOIN users u ON a.user_id = u.id
INNER JOIN teams team ON u.team_id = team.id
INNER JOIN groups g ON u.group_id = g.id
INNER JOIN opportunities o ON a.opportunity_id = o.id
INNER JOIN stages s ON o.stage_id = s.id
WHERE
a.crm_configuration_id = 356
AND a.status IN ('completed', 'failed')
AND a.recording_state != 'stopped'
# and a.user_id = 13841
AND u.uuid = uuid_to_bin('6f40e4b8-c340-4059-b4ac-1728e87ea99e')
AND team.uuid = uuid_to_bin('a607fba7-452e-4683-b2af-00d6cb52c93c')
AND g.uuid = uuid_to_bin('b5d69e40-24a0-4c16-810b-5fa462299f94')
AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')
# AND t.type IN ('audio', 'video')
AND (
(a.actual_start_time BETWEEN '2025-03-13 00:00:00' AND '2025-03-18 07:59:59')
OR
(
a.actual_start_time IS NULL
AND a.type IN ('sms-outbound', 'sms-inbound')
AND a.created_at BETWEEN '2025-03-13 00:00:00' AND '2025-03-18 07:59:59'
)
)
AND (
a.is_private = 0
OR (
a.is_private = 1
AND u.uuid = uuid_to_bin('6f40e4b8-c340-4059-b4ac-1728e87ea99e')
)
)
AND (
# s.id = 15900
s.uuid = uuid_to_bin('04ca1c26-c666-4268-a129-419c0acffd73')
OR s.uuid IS NULL -- Include records without opportunity stage
)
ORDER BY a.actual_end_time DESC;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Lead Forensics%'; # 190, 162, 8474, [EMAIL]
SELECT * FROM users WHERE team_id = 190;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 190
and sa.provider = 'hubspot';
select * from role_user where user_id = 8474;
select * from crm_configurations where provider = 'bullhorn';
SELECT * FROM opportunities WHERE uuid_to_bin('94578249-65ec-4205-90f2-7d1a7d5ab64a') = uuid;
SELECT * FROM users WHERE uuid_to_bin('26dbadeb-926f-4150-b11b-771b9d4c2f9a') = uuid;
SELECT * FROM opportunities WHERE id = 4732493;
select * from activities where opportunity_id = 4732493;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE id = 443; # 358, 14315, [EMAIL]
SELECT * FROM opportunities WHERE team_id = 443;
SELECT a.id, a.type, a.user_id, a.status, a.deleted_at, u.name, u.email, u.team_id as activity_team_id, u.status, u.deleted_at, t.name, t.status, s.team_id as stage_team_id
FROM activities AS a
JOIN stages AS s ON a.stage_id = s.id
JOIN users AS u ON u.id = a.user_id
JOIN teams AS t ON t.id = s.team_id
WHERE u.team_id <> s.team_id and t.id > 135;
SELECT
crm_configuration_id,
crm_provider_id,
COUNT(*) as duplicate_count,
GROUP_CONCAT(id) as stage_ids,
GROUP_CONCAT(name) as stage_names
FROM stages
GROUP BY crm_configuration_id, crm_provider_id
HAVING COUNT(*) > 1
ORDER BY duplicate_count DESC;
select * from stages where id IN (14898,14907);
select * from business_processes;
SELECT *
FROM crm_configurations
WHERE team_id IN (
SELECT team_id
FROM crm_configurations
GROUP BY team_id
HAVING COUNT(*) > 1
)
ORDER BY team_id;
SELECT *
FROM teams
WHERE crm_id IN (
SELECT crm_id
FROM teams
GROUP BY crm_id
HAVING COUNT(*) > 1
)
ORDER BY crm_id;
# [PASSWORD_DOTS]
select * from crm_configurations where provider = 'integration-app';
SELECT * FROM teams WHERE id = 443; # Correre Naturale 358 14315 [EMAIL]
select * from activities where crm_configuration_id = 358 order by actual_end_time desc;
select id, uuid, actual_end_time, crm_provider_id, is_internal, playbook_category_id, type, user_id, lead_id, contact_id, account_id, opportunity_id, status, title from activities where crm_configuration_id = 358 order by actual_end_time desc;
select * from team_features where team_id = 358;
select * from activity_summary_logs;
select * from teams where id = 406;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Sportfive%'; # 267, 202, 14637, [EMAIL]
select * from activities where crm_configuration_id = 202 order by actual_end_time desc;
SELECT * FROM users where id = 14637;
SELECT * FROM teams where id = 267;
SELECT * FROM groups where id = 1118;
select g.name, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled_start_time, a.scheduled_end_time, a.actual_start_time, a.actual_end_time from activities a
inner join users u on u.id = a.user_id
inner join groups g on g.id = u.group_id
where a.crm_configuration_id = 202
and a.is_internal = 0
and (a.scheduled_start_time between '2025-03-19 00:00:00' and '2025-03-21 00:00:00')
and a.type = 'conference'
and a.status != 'completed'
and a.external_id is not null
order by a.scheduled_start_time desc;
SELECT * FROM activities
WHERE crm_configuration_id = 202
AND status IN ('completed', 'failed')
AND recording_state != 'stopped'
AND type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')
AND (is_private = 0 OR user_id = 14637)
AND (
(
actual_start_time BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'
) OR (
actual_start_time IS NULL
AND type IN ('sms-outbound', 'sms-inbound')
AND created_at BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'
)
)
AND NOT EXISTS (
SELECT 1
FROM tracks
WHERE
tracks.activity_id = activities.id
AND tracks.type IN ('audio', 'video')
)
ORDER BY actual_end_time DESC;
SELECT DISTINCT
a.*
FROM activities a
INNER JOIN tracks t ON a.id = t.activity_id
INNER JOIN users u ON a.user_id = u.id
INNER JOIN teams team ON u.team_id = team.id
WHERE
a.crm_configuration_id = 202
AND a.status IN ('completed', 'failed')
AND a.recording_state != 'stopped'
# and a.user_id = 14637
AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')
# AND t.type IN ('audio', 'video')
AND (
(a.actual_start_time BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59')
OR
(
a.actual_start_time IS NULL
AND a.type IN ('sms-outbound', 'sms-inbound')
AND a.created_at BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'
)
)
AND (
a.is_private = 0
OR (
a.is_private = 1
AND a.user_id = 14637
)
)
ORDER BY a.actual_end_time DESC
;
SELECT DISTINCT a.*
FROM activities a
INNER JOIN users u ON a.user_id = u.id
INNER JOIN teams t ON u.team_id = t.id
# INNER JOIN tracks tr ON a.id = tr.activity_id
# INNER JOIN groups g ON u.group_id = g.id
WHERE 1=1
AND t.id = 267
# AND t.uuid = uuid_to_bin('aed4927b-f1ea-499e-94c3-83762fd233e8')
AND a.status IN ('completed', 'failed')
AND a.recording_state != 'stopped'
AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')
# AND tr.type NOT IN ('audio', 'video')
AND (
a.is_private = 0
OR a.user_id = 14637
)
AND (
(a.actual_start_time BETWEEN '2025-03-19 00:00:00' AND '2025-03-21 23:59:59')
OR (
a.actual_start_time IS NULL
AND a.type IN ('sms-outbound', 'sms-inbound')
AND a.created_at BETWEEN '2025-03-19 00:00:00' AND '2025-03-21 23:59:59'
)
)
# and NOT EXISTS (
# SELECT 1
# FROM tracks t
# WHERE t.activity_id = a.id
# AND t.type IN ('audio', 'video')
# )
ORDER BY a.actual_end_time DESC;
SELECT * FROM tracks WHERE activity_id = 26485995;
select a.is_private, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled...
|
55720
|
|
55723
|
NULL
|
0
|
2026-04-20T10:03:28.486742+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776679408486_m2.jpg...
|
PhpStorm
|
faVsco.js – AskJiminnyReportActivityServiceTest.ph faVsco.js – AskJiminnyReportActivityServiceTest.php...
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Services\Kiosk\AutomatedReports;
use Carbon\CarbonImmutable;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityActualDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityUpdatedDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\DealInsights\ClosingPeriodFilter;
use Jiminny\Component\ActivitySearch\FilterDefinitionCollection;
use Jiminny\Component\ActivitySearch\Service\ActivitySearch;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\Activity\SearchFilter;
use Jiminny\Models\User;
use Jiminny\Repositories\ElasticActivityRepository;
use Jiminny\Services\Kiosk\AutomatedReports\AskJiminnyReportActivityService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\VO\Repository\OnDemandActivitySearch\Criteria;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
class AskJiminnyReportActivityServiceTest extends TestCase
{
private ActivitySearch&MockObject $activitySearch;
private ElasticActivityRepository&MockObject $elasticRepository;
private LoggerInterface&MockObject $logger;
private AskJiminnyReportActivityService $service;
protected function setUp(): void
{
$this->activitySearch = $this->createMock(ActivitySearch::class);
$this->elasticRepository = $this->createMock(ElasticActivityRepository::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->service = new AskJiminnyReportActivityService(
$this->activitySearch,
$this->elasticRepository,
$this->logger,
);
}
private function makeFilter(string $key, ?string $value): SearchFilter&MockObject
{
$filter = $this->createMock(SearchFilter::class);
$filter->method('getFilterProperty')->willReturn($key);
$filter->method('getFilterValue')->willReturn($value);
return $filter;
}
private function makeUser(): User&MockObject
{
$tz = new \DateTimeZone('UTC');
$user = $this->createMock(User::class);
$user->method('getTimezone')->willReturn($tz);
$user->method('getId')->willReturn(1);
$user->method('getUuid')->willReturn('user-uuid');
return $user;
}
private function makeSavedSearch(array $filters): Search&MockObject
{
$savedSearch = $this->createMock(Search::class);
$savedSearch->method('getId')->willReturn(42);
$savedSearch->method('getFilters')->willReturn(new \Illuminate\Support\LazyCollection($filters));
return $savedSearch;
}
public function testGetActivityIdsForSavedSearchReturnsIds(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->expects($this->once())
->method('getArrayFilterKeys')
->with($user)
->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->expects($this->once())
->method('onDemandSearchIdsOnly')
->willReturn(['id-1', 'id-2', 'id-3']);
$this->logger->expects($this->once())
->method('info')
->with('[AskJiminnyReport] Fetched activity IDs for saved search');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1', 'id-2', 'id-3'], $result);
}
public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->expects($this->once())->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEmpty($result);
}
public function testGetActivityIdsFiltersOutDateFilters(): void
{
$user = $this->makeUser();
$nonDateFilter = $this->makeFilter('owner_id', '123');
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');
$updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');
$updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');
$savedSearch = $this->makeSavedSearch([
$nonDateFilter,
$startDateFilter,
$endDateFilter,
$updatedFromFilter,
$updatedToFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
}
public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void
{
$user = $this->makeUser();
$closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');
$closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');
$regularFilter = $this->makeFilter('rep_id', '99');
$savedSearch = $this->makeSavedSearch([
$closingStartFilter,
$closingEndFilter,
$regularFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesArrayFilters(): void
{
$user = $this->makeUser();
$filter1 = $this->makeFilter('outcome', 'positive');
$filter2 = $this->makeFilter('outcome', 'negative');
$savedSearch = $this->makeSavedSearch([$filter1, $filter2]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesScalarFilters(): void
{
$user = $this->makeUser();
$filter = $this->makeFilter('direction', 'inbound');
$savedSearch = $this->makeSavedSearch([$filter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-5'], $result);
}
public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
$this->assertFalse($capturedCriteria->isFirstRequest());
}
public function testGetActivityIdsLogsWithCorrectContext(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);
$this->logger->expects($this->once())
->method('info')
->with(
'[AskJiminnyReport] Fetched activity IDs for saved search',
$this->callback(fn ($context) => $context['saved_search_id'] === 42
&& $context['user_id'] === 1
&& $context['activity_count'] === 2)
);
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
}
public static function frequencyDateRangeProvider(): array
{
$now = CarbonImmutable::parse('2025-06-16 12:00:00');
return [
'daily' => [
AutomatedReportsService::FREQUENCY_DAILY,
$now->subDay()->startOfDay()->format('Y-m-d H:i:s'),
$now->subDay()->endOfDay()->format('Y-m-d H:i:s'),
],
'weekly' => [
AutomatedReportsService::FREQUENCY_WEEKLY,
$now->subWeek()->startOfWeek()->format('Y-m-d H:i:s'),
$now->subWeek()->endOfWeek()->format('Y-m-d H:i:s'),
],
'monthly' => [
AutomatedReportsService::FREQUENCY_MONTHLY,
$now->subMonthNoOverflow()->startOfMonth()->format('Y-m-d H:i:s'),
$now->subMonthNoOverflow()->endOfMonth()->format('Y-m-d H:i:s'),
],
'quarterly' => [
AutomatedReportsService::FREQUENCY_QUARTERLY,
$now->subQuarterNoOverflow()->startOfQuarter()->format('Y-m-d H:i:s'),
$now->subQuarterNoOverflow()->endOfQuarter()->format('Y-m-d H:i:s'),
],
];
}
/**
* @dataProvider frequencyDateRangeProvider
*/
public function testGetActivityIdsInjectsDateRangeForFrequency(
string $frequency,
string $expectedStartDate,
string $expectedEndDate,
): void {
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);
$this->assertNotNull($capturedCriteria);
$this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void
{
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');
$savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);
$this->assertNotNull($capturedCriteria);
$this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
27
9
23
3
105
Previous Highlighted Error
Next Highlighted Error
SELECT * FROM team_features where team_id = 1;
SELECT * FROM teams WHERE name LIKE '%Vixio%'; # 340,270,11922
SELECT * FROM users WHERE team_id = 340; # 12015
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 340
and sa.provider = 'salesforce';
# and sa.provider = 'salesloft';
select * from crm_fields where crm_configuration_id = 270 and object_type = 'event';
# 125558 - Event Type - Event_Type__c
# 125552 - Event Status - Event_Status__c
SELECT * FROM sidekick_settings WHERE team_id = 340;
SELECT * FROM crm_field_values WHERE crm_field_id in (125552);
select * from activities where crm_configuration_id = 270
and type = 'conference' and crm_provider_id IS NOT NULL
and actual_start_time > '2024-09-16 09:00:00' order by scheduled_start_time;
SELECT * FROM activities WHERE id = 20871677;
SELECT * FROM crm_field_data WHERE activity_id = 20871677;
select * from crm_layouts where crm_configuration_id = 270;
select * from crm_layout_entities where crm_layout_id in (886,887);
SELECT * FROM crm_configurations WHERE id = 270;
select * from playbooks where team_id = 340; # 1514
select * from groups where team_id = 340;
SELECT * FROM crm_fields WHERE id IN (125393, 125401);
select g.name as 'team name', p.name as 'playbook name', f.label as 'activity type field' from groups g
join playbooks p on g.playbook_id = p.id
join crm_fields f on p.activity_field_id = f.id
where g.team_id = 340;
SELECT * FROM activities WHERE uuid_to_bin('0c180357-67d2-419e-a8c3-b832a3490770') = uuid; # 20448716
select * from crm_field_data where object_id = 20448716;
select * from activities where crm_configuration_id = 270 and provider = 'salesloft' order by id desc;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%CybSafe%'; # 343,273,12008
select * from opportunities where team_id = 343;
select * from opportunities where team_id = 343 and crm_provider_id = '18099102526';
select * from opportunities where team_id = 343 and account_id = 945217482;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 343
and sa.provider = 'hubspot';
select * from accounts where team_id = 343 order by name asc;
select * from stages where crm_configuration_id = 273 and type = 'opportunity';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Voyado%'; # 353,283,12143
SELECT * FROM activities WHERE crm_configuration_id = 283 and account_id = 3777844 order by id desc;
SELECT * FROM accounts WHERE team_id = 353 AND name LIKE '%Salesloft%';
SELECT * FROM activities WHERE id = 20717903;
select * from participants where activity_id IN (20929172,20928605,20928468,20926272,20926271,20926270,20926269,20916499,20916454,20916436,20916435,20900015,20900014,20900013,20897312,20897243,20897241,20897237,20897232,20897229,20893648,20893231,20893230,20893229,20893228,20889784,20885039,20885038,20885037,20885036,20885035,20882728,20882708,20882703,20882702,20869828,20869811,20869806,20869801,20869799,20869798,20869796,20869795,20869794,20869761,20869760,20869759,20868688,20868687,20850340,20847195,20841710,20833967,20827021,20825307,20825305,20825297,20824615,20824400,20823927,20821760,20795588,20794233,20794057,20793710,20785811,20781789,20781394,20781307,20762651,20758453,20758282,20757323,20756643,20756636,20756629,20756627,20756606,20756605,20756604,20756603,20756602,20756600,20756599,20756598,20756595,20756594,20756589,20756587,20756577,20756573,20748918,20748386,20748385,20748384,20748383,20748382,20748381,20748380,20748379,20748377,20748375,20748373,20743301,20717905,20717904,20717903,20717901,20717899);
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 353
and sa.provider = 'salesforce';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%modern world business solutions%'; # 345,275,12016, [EMAIL]
SELECT * FROM activities WHERE uuid_to_bin('3921d399-3fef-4609-a291-b0097a166d43') = uuid;
# id: 20940638, user: 12022, contact: 5305871
SELECT * FROM activity_summary_logs WHERE activity_id = 20940638;
select * from contacts where team_id = 345 and crm_provider_id = '30891432415' order by name asc; # 5305871
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 345
and sa.provider = 'hubspot';
select * from users where team_id = 345 and id = 12022;
SELECT * FROM crm_profiles WHERE user_id = 12022;
SELECT * FROM participants WHERE activity_id = 20940638;
SELECT * FROM users u
JOIN crm_profiles cp ON u.id = cp.user_id
WHERE u.team_id = 345;
select * from contacts where team_id = 345 and crm_provider_id = '30880813535' order by name desc; # 5305871
select * from team_features where team_id = 345;
SELECT * FROM activities WHERE uuid_to_bin('11701e2d-2f82-4dab-a616-1db4fad238df') = uuid; # 21115197
SELECT * FROM participants WHERE activity_id = 20897406;
SELECT * FROM activities WHERE uuid_to_bin('63ba55cd-1abc-447d-83da-0137000005b7') = uuid; # 20953912
SELECT * FROM activities WHERE crm_configuration_id = 275 and provider = 'ringcentral' and title like '%1252629100%';
SELECT * FROM activities WHERE id = 20946641;
SELECT * FROM crm_profiles WHERE user_id = 10211;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Lunio%'; # 120,97,10984, [EMAIL]
SELECT * FROM opportunities WHERE crm_configuration_id = 97 and crm_provider_id = '006N1000006c5PpIAI';
select * from stages where crm_configuration_id = 97 and type = 'opportunity';
select * from opportunities where team_id = 120;
select * from crm_configurations crm join teams t on crm.id = t.crm_id
where 1=1
AND t.current_billing_plan IS NOT NULL
AND crm.auto_sync_activity = 0
and crm.provider = 'hubspot';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Exclaimer%'; # 270,205,10053,[EMAIL]
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 270
and sa.provider = 'salesforce';
SELECT * FROM activities WHERE uuid_to_bin('b54df794-2a9a-4957-8d80-09a600ead5f8') = uuid; # 21637956
SELECT * FROM crm_profiles WHERE user_id = 11446;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Cygnetise%'; # 372,300,12554, [EMAIL]
select * from playbooks where team_id = 372;
select * from crm_fields where crm_configuration_id = 300 and object_type = 'event'; # 141340
SELECT * FROM crm_field_values WHERE crm_field_id = 141340;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 372
and sa.provider = 'salesforce';
select * from crm_profiles where crm_configuration_id = 300;
SELECT * FROM crm_configurations WHERE team_id = 372;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Planday%'; # 291,242,11501,[EMAIL]
SELECT * FROM opportunities WHERE team_id = 291 and crm_provider_id = '006bG000005DO86QAG'; # 3207756
select * from crm_field_data where object_id = 3207756;
SELECT * FROM crm_fields WHERE id = 111834;
select f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value
FROM crm_fields f
JOIN crm_field_data fd ON f.id = fd.crm_field_id
WHERE f.crm_configuration_id = 242
AND f.object_type = 'opportunity'
AND fd.object_id IN (3207756)
ORDER BY fd.object_id, fd.updated_at;
SELECT * FROM crm_configurations WHERE auto_connect = 1;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Tour%'; # 187,209,8150,[EMAIL]
select * from group_deal_risk_types drgt join groups g on drgt.group_id = g.id
where g.team_id = 187;
select * from `groups` where team_id = 187;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 187
and sa.provider = 'salesforce';
# Destination - 98870 - Destination__c
# Stage - 79014 - StageName
# Land Arrangement - 98856 - Land_Arrangement__c
# Flight - 98848 - Flight__c
# Last activity date - 98812 - LastActivityDate
# Last modified date - 98809 - LastModifiedDate
# Last inbound mail timestamp - 99151 - Last_Inbound_Mail_Timestamp__c
# next call - 98864 - Next_Call__c
select * from crm_fields where crm_configuration_id = 209 and object_type = 'opportunity';
SELECT * FROM crm_layouts WHERE crm_configuration_id = 209;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 682;
select * from opportunities where team_id = 187 and name LIKE'%Muriel Sal%';
select * from opportunities where team_id = 187 and user_id = 9951 and is_closed = 0;
select * from activities where opportunity_id = 3538248;
SELECT * FROM crm_profiles WHERE user_id = 8150;
select * from deal_risks where opportunity_id = 3538248;
select * from teams where crm_id IS NULL;
SELECT opp.id AS opportunity_id,
u.group_id AS group_id,
MAX(
CASE
WHEN a.type IN ("sms-inbound", "sms-outbound") THEN a.created_at
ELSE a.actual_end_time
END) as last_date
FROM opportunities opp
left join activities a on a.opportunity_id = opp.id
inner join users u on opp.user_id = u.id
where opp.user_id IN (9951)
AND opp.is_closed = 0
and a.status IN ('completed', 'received', 'delivered') OR a.status IS NULL
group by opp.id;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Cybsafe%'; # 343,301,12008,[EMAIL]
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 343
and sa.provider = 'hubspot';
SELECT * FROM crm_profiles WHERE crm_configuration_id = 301;
SELECT * FROM contacts WHERE id = 6612363;
SELECT * FROM accounts WHERE id = 4235676;
SELECT * FROM opportunities WHERE crm_configuration_id = 301 and crm_provider_id = 32983784868;
select * from opportunity_stages where opportunity_id = 4503759;
# SELECT * FROM opportunities WHERE id = 4569937;
select * from activities where crm_configuration_id = 301;
SELECT * FROM activities WHERE uuid_to_bin('d3b2b28b-c3d0-4c2d-8ed0-eef42855278a') = uuid; # 26330370
SELECT * FROM participants WHERE activity_id = 26330370;
SELECT * FROM teams WHERE id = 375;
select * from playbooks where team_id = 375;
select * from stages where crm_configuration_id = 301 and type = 'opportunity';
select * from teams;
select * from contact_roles;
SELECT * FROM opportunities WHERE team_id = 343 and user_id = 12871 and close_date >= '2024-11-01';
select * from users u join crm_profiles cp on cp.user_id = u.id where u.team_id = 343;
SELECT * FROM crm_field_data WHERE object_id = 3771706;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 343
and sa.provider = 'hubspot';
SELECT * FROM crm_fields WHERE crm_configuration_id = 301 and object_type = 'opportunity'
and crm_provider_id LIKE "%traffic_light%";
SELECT * FROM crm_field_values WHERE crm_field_id IN (144020,144048,144111,144113,144126,144481,144508,144531);
SELECT fd.* FROM opportunities o
JOIN crm_field_data fd ON o.id = fd.object_id
WHERE o.team_id = 343
# and o.user_id IS NOT NULL
and fd.crm_field_id IN (144020,144048,144111,144113,144126,144481,144508,144531)
and fd.value != ''
order by value desc
# group by o.id
;
SELECT * FROM opportunities WHERE id = 3769843;
SELECT * FROM teams WHERE name LIKE '%Tour%'; # 187,209,8150, [EMAIL]
SELECT * FROM crm_layouts WHERE crm_configuration_id = 209;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 682;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Funding Circle%'; # 220,177,8603,[EMAIL]
SELECT * FROM activities WHERE uuid_to_bin('7a40e99b-3b37-4bb1-b983-325b81801c01') = uuid; # 23139839
SELECT * FROM opportunities WHERE id = 3855992;
SELECT * FROM users WHERE name LIKE '%Angus Pollard%'; # 8988
SELECT * FROM teams WHERE name LIKE '%Story Terrace%'; # 379, 307, 12894
SELECT * FROM crm_fields WHERE crm_configuration_id = 307 and object_type != 'opportunity';
select * from contacts where team_id = 379 and name like '%bebro%'; # 5874411, crm: 77229348507
SELECT * FROM crm_field_data WHERE object_id = 5874411;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 379
and sa.provider = 'hubspot';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%mentio%'; # 117, 94, 6371, [EMAIL]
SELECT * FROM activities WHERE uuid_to_bin('82939311-1af0-4506-8546-21e8d1fdf2c1') = uuid;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Tourlane%'; # 187, 209, 8150, [EMAIL]
SELECT * FROM opportunities WHERE team_id = 187 and crm_provider_id = '006Se000008xfvNIAQ'; # 3537793
select * from generic_ai_prompts where subject_id = 3537793;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Lunio%'; # 120, 97, 10984, [EMAIL]
SELECT * FROM crm_configurations WHERE id = 97;
SELECT * FROM crm_layouts WHERE crm_configuration_id = 97;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 355;
SELECT * FROM crm_fields WHERE id = 32682;
select cfd.value, o.* from opportunities o
join crm_field_data cfd on o.id = cfd.object_id and cfd.crm_field_id = 32682
where team_id = 120
and cfd.value != ''
;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 120
and sa.provider = 'salesforce';
select * from opportunities where team_id = 120 and crm_provider_id = '006N1000007X8MAIA0';
SELECT * FROM crm_field_data WHERE object_id = 2313439;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE id = 410;
SELECT * FROM teams WHERE name LIKE '%Local Business Oxford%';
select * from scorecards where team_id = 410;
select * from scorecard_rules;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Funding%'; # 220, 177, 8603, [EMAIL]
select * from activities a
join opportunities o on a.opportunity_id = o.id
join users u on o.user_id = u.id
where a.crm_configuration_id = 177 and a.type LIKE '%email-out%'
# and a.actual_end_time > '2024-12-16 00:00:00'
# and o.remotely_created_at > '2024-12-01 00:00:00'
# and u.group_id = 1014
and u.id = 9021
order by a.id desc;
SELECT * FROM opportunities WHERE id in (3981384,4017346);
SELECT * FROM users WHERE team_id = 220 and id IN (8775, 11435);
select * from users where id = 9021;
select * from inboxes where user_id = 9021;
select * from inbox_emails where inbox_id = 1349 and email_date > '2024-12-18 00:00:00';
select * from email_messages where team_id = 220
and orig_date > '2024-12-16 00:00:00' and orig_date < '2024-12-19 00:00:00'
and subject LIKE '%Personal%'
# and 'from' = '[EMAIL]'
;
select * from activities a
join opportunities o on a.opportunity_id = o.id
where a.user_id = 9021 and a.type LIKE '%email-out%'
and a.actual_end_time > '2024-12-18 00:00:00'
and o.user_id IS NOT NULL
and o.remotely_created_at > '2024-12-01 00:00:00'
order by a.id desc;
SELECT * FROM opportunities WHERE team_id = 220 and name LIKE '%Right Car move Limited%' and id = 3966852;
select * from activities where crm_configuration_id = 177 and type LIKE '%email%' and opportunity_id = 3966852 order by id desc;
select * from team_settings where name IN ('useCloseDate');
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Hurree%'; # 104, 81, 6175, [EMAIL]
SELECT * FROM opportunities WHERE team_id = 104 and name = 'PropOp';
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 104
and sa.provider = 'hubspot';
select * from crm_configurations where last_synced_at > '2025-01-19 01:00:00'
select * from teams where crm_id IS NULL;
select t.name as 'team', u.name as 'owner', u.email, u.phone
from teams t
join activity_providers ap on t.id = ap.team_id
join users u on t.owner_id = u.id
where 1=1
and t.status = 'active'
and ap.is_enabled = 1
# and u.status = 1
and ap.provider = 'ms-teams';
select * from crm_configurations where provider = 'bullhorn'; # 344
SELECT * FROM teams WHERE id = 442; # 14293
select * from users where team_id = 442;
select * from social_accounts sa where sa.sociable_id = 14293;
select * from invitations where team_id = 442;
# [PASSWORD_DOTS]
SELECT * FROM users WHERE email LIKE '%[EMAIL]%'; # 14022
SELECT * FROM teams WHERE id = 429;
select * from opportunities where team_id = 429 and crm_provider_id IN (16157415775, 22246219645);
select * from activities where opportunity_id in (4340436,4353519);
select * from transcription where activity_id IN (25630961,25381771);
select * from generic_ai_prompts where subject_id IN (4353519);
SELECT
a.id as activity_id,
a.opportunity_id,
a.type as activity_type,
a.language,
CONCAT(a.title, a.description) AS mail_content,
e.from AS mail_from,
e.to AS mail_to,
e.subject AS mail_subject,
e.body AS mail_body,
p.type as prompt_type,
p.status as prompt_status,
p.content AS prompt_content,
a.actual_start_time as created_at
FROM activities a
LEFT JOIN ai_prompts p ON a.transcription_id = p.transcription_id AND p.deleted_at IS NULL
LEFT JOIN email_messages e ON a.id = e.activity_id
WHERE a.actual_start_time > '2024-01-01 00:00:00'
AND a.opportunity_id IN (4353519)
AND a.status IN ('completed', 'received', 'delivered')
AND a.deleted_at IS NULL
AND a.type NOT IN ('sms-inbound', 'sms-outbound')
ORDER BY a.opportunity_id ASC, a.id ASC;
SELECT * FROM users WHERE name LIKE '%George Fierstone%'; # 14293
SELECT * FROM teams WHERE id = 442;
SELECT * FROM crm_configurations WHERE id = 344;
select * from team_features where team_id = 442;
select * from groups where team_id = 442;
select * from playbooks where team_id = 442;
select * from playbook_categories where playbook_id = 1729;
select * from crm_fields where crm_configuration_id = 344 and id = 172024;
SELECT * FROM crm_field_values WHERE crm_field_id = 172024;
select * from crm_layouts where crm_configuration_id = 344;
select * from playbook_layouts where playbook_id = 1729;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Learning%'; # 260, 221, 9444
select s.*
# , s.sent_at, u.name, a.*
from activity_summary_logs s
inner join activities a on a.id = s.activity_id
inner join users u on u.id = a.user_id
where a.crm_configuration_id = 356
and s.sent_at > date_sub(now(), interval 60 day)
order by a.actual_end_time desc;
select * from activities a
# inner join activity_summary_logs s on s.activity_id = a.id
where a.crm_configuration_id = 356 and a.actual_end_time > date_sub(now(), interval 60 day)
# and a.crm_provider_id is not null
# and provider <> 'ringcentral'
and status = 'completed'
order by a.actual_end_time desc;
select * from teams order by id desc; # 17328, 32, 17830, [EMAIL]
SELECT * FROM users;
SELECT * FROM users where team_id = 260 and status = 1; # 201 - 150 active
SELECT * FROM teams WHERE id = 260;
select * from team_settings where team_id = 260;
select * from crm_configurations where team_id = 260;
SELECT * FROM crm_layouts WHERE crm_configuration_id = 356;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 1184;
select * from accounts where crm_configuration_id = 221 order by id desc; # 7000
select * from leads where crm_configuration_id = 221 order by id desc; # 0
select * from contacts where crm_configuration_id = 221 order by id desc; # 200 000
select * from opportunities where crm_configuration_id = 221 order by id desc; # 0
select * from crm_profiles where crm_configuration_id = 221 order by id desc; # 23
select * from crm_fields where crm_configuration_id = 221;
select * from crm_field_values where crm_field_id = 5302 order by id desc;
select * from crm_layouts where crm_configuration_id = 221 order by id desc;
select * from stages where crm_configuration_id = 221 order by id desc;
select * from accounts where crm_configuration_id = 356 order by id desc; # 7000
select * from leads where crm_configuration_id = 356 order by id desc; # 0
select * from contacts where crm_configuration_id = 356 order by id desc; # 200 000
select * from opportunities where crm_configuration_id = 356 order by id desc; # 0
select * from crm_profiles where crm_configuration_id = 356 order by id desc; # 23
select * from crm_fields where crm_configuration_id = 356;
select * from crm_field_values where crm_field_id = 5302 order by id desc;
select * from crm_layouts where crm_configuration_id = 356 order by id desc;
select * from stages where crm_configuration_id = 356 order by id desc;
select * from playbooks where team_id = 260 order by id desc; # 4 (2 deleted)
select * from groups where team_id = 260 order by id desc; # 27 groups, (2 deleted)
select * from playbook_layouts where playbook_id IN (1410,1409,1276,1254); # 4
select ce.* from calendars c
join users u on c.user_id = u.id
join calendar_events ce on c.id = ce.calendar_id
where u.team_id = 260
and (ce.start_time > '2025-02-21 00:00:00')
;
# calendar events 1207
#
select * from opportunities where team_id = 260;
SELECT * FROM crm_field_data WHERE object_id = 4696496;
select * from activities where crm_configuration_id = 356 and crm_provider_id IS NOT NULL;
select * from activities where crm_configuration_id IN (221) and provider NOT IN ('ms-teams', 'uploader', 'zoom-bot')
# and type = 'conference' and status = 'scheduled' and activities.is_internal = 0
and created_at > '2024-03-01 00:00:00'
order by id desc; # 880 000, ringcentral, avaya
SELECT * FROM participants WHERE activity_id = 26371744;
# all activities 942 000 +
# conference 7385 - scheduled 984 - external 343
select * from activities where id = 26321812;
select * from participants where activity_id = 26321812;
select * from participants where activity_id in (26414510,26414514,26414516,26414604,26414653,26414655);
select * from leads where id in (720428,689175,731546,645866,621037);
select * from users where id = 13841;
select * from opportunities where user_id = 9541;
select * from stages where id = 15900;
select * from accounts where
# id IN (4160055,5053725,4965303,4896434)
id in (4584518,3249934,3218025,3891133,3399450,4172999,4485161,3101785,4587203,3070816,2870343,2870341,3563940,4550846,3424464,3249963,2870342)
;
select * from activities where id = 26654935;
SELECT * FROM opportunities WHERE id = 4803458;
SELECT * FROM opportunities where team_id = 260 and user_id = 13841 AND stage_id = 15900;
SELECT id, uuid, provider, type, lead_id, account_id, contact_id, opportunity_id, stage_id, status, recording_state, title, actual_start_time, actual_end_time
FROM activities WHERE user_id = 13841 AND opportunity_id IN (4729783, 4731717, 4731726, 4732064, 4732849, 4803458, 4813213);
SELECT DISTINCT
o.id, o.stage_id, s.name, a.title,
a.*
FROM activities a
# INNER JOIN tracks t ON a.id = t.activity_id
INNER JOIN users u ON a.user_id = u.id
INNER JOIN teams team ON u.team_id = team.id
INNER JOIN groups g ON u.group_id = g.id
INNER JOIN opportunities o ON a.opportunity_id = o.id
INNER JOIN stages s ON o.stage_id = s.id
WHERE
a.crm_configuration_id = 356
AND a.status IN ('completed', 'failed')
AND a.recording_state != 'stopped'
# and a.user_id = 13841
AND u.uuid = uuid_to_bin('6f40e4b8-c340-4059-b4ac-1728e87ea99e')
AND team.uuid = uuid_to_bin('a607fba7-452e-4683-b2af-00d6cb52c93c')
AND g.uuid = uuid_to_bin('b5d69e40-24a0-4c16-810b-5fa462299f94')
AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')
# AND t.type IN ('audio', 'video')
AND (
(a.actual_start_time BETWEEN '2025-03-13 00:00:00' AND '2025-03-18 07:59:59')
OR
(
a.actual_start_time IS NULL
AND a.type IN ('sms-outbound', 'sms-inbound')
AND a.created_at BETWEEN '2025-03-13 00:00:00' AND '2025-03-18 07:59:59'
)
)
AND (
a.is_private = 0
OR (
a.is_private = 1
AND u.uuid = uuid_to_bin('6f40e4b8-c340-4059-b4ac-1728e87ea99e')
)
)
AND (
# s.id = 15900
s.uuid = uuid_to_bin('04ca1c26-c666-4268-a129-419c0acffd73')
OR s.uuid IS NULL -- Include records without opportunity stage
)
ORDER BY a.actual_end_time DESC;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Lead Forensics%'; # 190, 162, 8474, [EMAIL]
SELECT * FROM users WHERE team_id = 190;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 190
and sa.provider = 'hubspot';
select * from role_user where user_id = 8474;
select * from crm_configurations where provider = 'bullhorn';
SELECT * FROM opportunities WHERE uuid_to_bin('94578249-65ec-4205-90f2-7d1a7d5ab64a') = uuid;
SELECT * FROM users WHERE uuid_to_bin('26dbadeb-926f-4150-b11b-771b9d4c2f9a') = uuid;
SELECT * FROM opportunities WHERE id = 4732493;
select * from activities where opportunity_id = 4732493;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE id = 443; # 358, 14315, [EMAIL]
SELECT * FROM opportunities WHERE team_id = 443;
SELECT a.id, a.type, a.user_id, a.status, a.deleted_at, u.name, u.email, u.team_id as activity_team_id, u.status, u.deleted_at, t.name, t.status, s.team_id as stage_team_id
FROM activities AS a
JOIN stages AS s ON a.stage_id = s.id
JOIN users AS u ON u.id = a.user_id
JOIN teams AS t ON t.id = s.team_id
WHERE u.team_id <> s.team_id and t.id > 135;
SELECT
crm_configuration_id,
crm_provider_id,
COUNT(*) as duplicate_count,
GROUP_CONCAT(id) as stage_ids,
GROUP_CONCAT(name) as stage_names
FROM stages
GROUP BY crm_configuration_id, crm_provider_id
HAVING COUNT(*) > 1
ORDER BY duplicate_count DESC;
select * from stages where id IN (14898,14907);
select * from business_processes;
SELECT *
FROM crm_configurations
WHERE team_id IN (
SELECT team_id
FROM crm_configurations
GROUP BY team_id
HAVING COUNT(*) > 1
)
ORDER BY team_id;
SELECT *
FROM teams
WHERE crm_id IN (
SELECT crm_id
FROM teams
GROUP BY crm_id
HAVING COUNT(*) > 1
)
ORDER BY crm_id;
# [PASSWORD_DOTS]
select * from crm_configurations where provider = 'integration-app';
SELECT * FROM teams WHERE id = 443; # Correre Naturale 358 14315 [EMAIL]
select * from activities where crm_configuration_id = 358 order by actual_end_time desc;
select id, uuid, actual_end_time, crm_provider_id, is_internal, playbook_category_id, type, user_id, lead_id, contact_id, account_id, opportunity_id, status, title from activities where crm_configuration_id = 358 order by actual_end_time desc;
select * from team_features where team_id = 358;
select * from activity_summary_logs;
select * from teams where id = 406;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Sportfive%'; # 267, 202, 14637, [EMAIL]
select * from activities where crm_configuration_id = 202 order by actual_end_time desc;
SELECT * FROM users where id = 14637;
SELECT * FROM teams where id = 267;
SELECT * FROM groups where id = 1118;
select g.name, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled_start_time, a.scheduled_end_time, a.actual_start_time, a.actual_end_time from activities a
inner join users u on u.id = a.user_id
inner join groups g on g.id = u.group_id
where a.crm_configuration_id = 202
and a.is_internal = 0
and (a.scheduled_start_time between '2025-03-19 00:00:00' and '2025-03-21 00:00:00')
and a.type = 'conference'
and a.status != 'completed'
and a.external_id is not null
order by a.scheduled_start_time desc;
SELECT * FROM activities
WHERE crm_configuration_id = 202
AND status IN ('completed', 'failed')
AND recording_state != 'stopped'
AND type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')
AND (is_private = 0 OR user_id = 14637)
AND (
(
actual_start_time BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'
) OR (
actual_start_time IS NULL
AND type IN ('sms-outbound', 'sms-inbound')
AND created_at BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'
)
)
AND NOT EXISTS (
SELECT 1
FROM tracks
WHERE
tracks.activity_id = activities.id
AND tracks.type IN ('audio', 'video')
)
ORDER BY actual_end_time DESC;
SELECT DISTINCT
a.*
FROM activities a
INNER JOIN tracks t ON a.id = t.activity_id
INNER JOIN users u ON a.user_id = u.id
INNER JOIN teams team ON u.team_id = team.id
WHERE
a.crm_configuration_id = 202
AND a.status IN ('completed', 'failed')
AND a.recording_state != 'stopped'
# and a.user_id = 14637
AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')
# AND t.type IN ('audio', 'video')
AND (
(a.actual_start_time BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59')
OR
(
a.actual_start_time IS NULL
AND a.type IN ('sms-outbound', 'sms-inbound')
AND a.created_at BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'
)
)
AND (
a.is_private = 0
OR (
a.is_private = 1
AND a.user_id = 14637
)
)
ORDER BY a.actual_end_time DESC
;
SELECT DISTINCT a.*
FROM activities a
INNER JOIN users u ON a.user_id = u.id
INNER JOIN teams t ON u.team_id = t.id
# INNER JOIN tracks tr ON a.id = tr.activity_id
# INNER JOIN groups g ON u.group_id = g.id
WHERE 1=1
AND t.id = 267
# AND t.uuid = uuid_to_bin('aed4927b-f1ea-499e-94c3-83762fd233e8')
AND a.status IN ('completed', 'failed')
AND a.recording_state != 'stopped'
AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')
# AND tr.type NOT IN ('audio', 'video')
AND (
a.is_private = 0
OR a.user_id = 14637
)
AND (
(a.actual_start_time BETWEEN '2025-03-19 00:00:00' AND '2025-03-21 23:59:59')
OR (
a.actual_start_time IS NULL
AND a.type IN ('sms-outbound', 'sms-inbound')
AND a.created_at BETWEEN '2025-03-19 00:00:00' AND '2025-03-21 23:59:59'
)
)
# and NOT EXISTS (
# SELECT 1
# FROM tracks t
# WHERE t.activity_id = a.id
# AND t.type IN ('audio', 'video')
# )
ORDER BY a.actual_end_time DESC;
SELECT * FROM tracks WHERE activity_id = 26485995;
select a.is_private, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11894 on JY-18909-automated-reports-ask-jiminny, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #11894 exists for current branch JY-18909-automated-reports-ask-jiminny","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.006981383,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Services\\Kiosk\\AutomatedReports;\n\nuse Carbon\\CarbonImmutable;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityActualDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityUpdatedDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\DealInsights\\ClosingPeriodFilter;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionCollection;\nuse Jiminny\\Component\\ActivitySearch\\Service\\ActivitySearch;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\Activity\\SearchFilter;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\ElasticActivityRepository;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AskJiminnyReportActivityService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\VO\\Repository\\OnDemandActivitySearch\\Criteria;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\n\nclass AskJiminnyReportActivityServiceTest extends TestCase\n{\n private ActivitySearch&MockObject $activitySearch;\n private ElasticActivityRepository&MockObject $elasticRepository;\n private LoggerInterface&MockObject $logger;\n private AskJiminnyReportActivityService $service;\n\n protected function setUp(): void\n {\n $this->activitySearch = $this->createMock(ActivitySearch::class);\n $this->elasticRepository = $this->createMock(ElasticActivityRepository::class);\n $this->logger = $this->createMock(LoggerInterface::class);\n\n $this->service = new AskJiminnyReportActivityService(\n $this->activitySearch,\n $this->elasticRepository,\n $this->logger,\n );\n }\n\n private function makeFilter(string $key, ?string $value): SearchFilter&MockObject\n {\n $filter = $this->createMock(SearchFilter::class);\n $filter->method('getFilterProperty')->willReturn($key);\n $filter->method('getFilterValue')->willReturn($value);\n\n return $filter;\n }\n\n private function makeUser(): User&MockObject\n {\n $tz = new \\DateTimeZone('UTC');\n $user = $this->createMock(User::class);\n $user->method('getTimezone')->willReturn($tz);\n $user->method('getId')->willReturn(1);\n $user->method('getUuid')->willReturn('user-uuid');\n\n return $user;\n }\n\n private function makeSavedSearch(array $filters): Search&MockObject\n {\n $savedSearch = $this->createMock(Search::class);\n $savedSearch->method('getId')->willReturn(42);\n $savedSearch->method('getFilters')->willReturn(new \\Illuminate\\Support\\LazyCollection($filters));\n\n return $savedSearch;\n }\n\n public function testGetActivityIdsForSavedSearchReturnsIds(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->expects($this->once())\n ->method('getArrayFilterKeys')\n ->with($user)\n ->willReturn([]);\n\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n\n $this->elasticRepository->expects($this->once())\n ->method('onDemandSearchIdsOnly')\n ->willReturn(['id-1', 'id-2', 'id-3']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[AskJiminnyReport] Fetched activity IDs for saved search');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1', 'id-2', 'id-3'], $result);\n }\n\n public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $this->logger->expects($this->once())->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEmpty($result);\n }\n\n public function testGetActivityIdsFiltersOutDateFilters(): void\n {\n $user = $this->makeUser();\n\n $nonDateFilter = $this->makeFilter('owner_id', '123');\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');\n $updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');\n $updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');\n\n $savedSearch = $this->makeSavedSearch([\n $nonDateFilter,\n $startDateFilter,\n $endDateFilter,\n $updatedFromFilter,\n $updatedToFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n }\n\n public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void\n {\n $user = $this->makeUser();\n\n $closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');\n $closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');\n $regularFilter = $this->makeFilter('rep_id', '99');\n\n $savedSearch = $this->makeSavedSearch([\n $closingStartFilter,\n $closingEndFilter,\n $regularFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesArrayFilters(): void\n {\n $user = $this->makeUser();\n\n $filter1 = $this->makeFilter('outcome', 'positive');\n $filter2 = $this->makeFilter('outcome', 'negative');\n\n $savedSearch = $this->makeSavedSearch([$filter1, $filter2]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesScalarFilters(): void\n {\n $user = $this->makeUser();\n\n $filter = $this->makeFilter('direction', 'inbound');\n $savedSearch = $this->makeSavedSearch([$filter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-5'], $result);\n }\n\n public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertFalse($capturedCriteria->isFirstRequest());\n }\n\n public function testGetActivityIdsLogsWithCorrectContext(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with(\n '[AskJiminnyReport] Fetched activity IDs for saved search',\n $this->callback(fn ($context) => $context['saved_search_id'] === 42\n && $context['user_id'] === 1\n && $context['activity_count'] === 2)\n );\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n }\n\n public static function frequencyDateRangeProvider(): array\n {\n $now = CarbonImmutable::parse('2025-06-16 12:00:00');\n\n return [\n 'daily' => [\n AutomatedReportsService::FREQUENCY_DAILY,\n $now->subDay()->startOfDay()->format('Y-m-d H:i:s'),\n $now->subDay()->endOfDay()->format('Y-m-d H:i:s'),\n ],\n 'weekly' => [\n AutomatedReportsService::FREQUENCY_WEEKLY,\n $now->subWeek()->startOfWeek()->format('Y-m-d H:i:s'),\n $now->subWeek()->endOfWeek()->format('Y-m-d H:i:s'),\n ],\n 'monthly' => [\n AutomatedReportsService::FREQUENCY_MONTHLY,\n $now->subMonthNoOverflow()->startOfMonth()->format('Y-m-d H:i:s'),\n $now->subMonthNoOverflow()->endOfMonth()->format('Y-m-d H:i:s'),\n ],\n 'quarterly' => [\n AutomatedReportsService::FREQUENCY_QUARTERLY,\n $now->subQuarterNoOverflow()->startOfQuarter()->format('Y-m-d H:i:s'),\n $now->subQuarterNoOverflow()->endOfQuarter()->format('Y-m-d H:i:s'),\n ],\n ];\n }\n\n /**\n * @dataProvider frequencyDateRangeProvider\n */\n public function testGetActivityIdsInjectsDateRangeForFrequency(\n string $frequency,\n string $expectedStartDate,\n string $expectedEndDate,\n ): void {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n\n public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void\n {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');\n $savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Services\\Kiosk\\AutomatedReports;\n\nuse Carbon\\CarbonImmutable;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityActualDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityUpdatedDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\DealInsights\\ClosingPeriodFilter;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionCollection;\nuse Jiminny\\Component\\ActivitySearch\\Service\\ActivitySearch;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\Activity\\SearchFilter;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\ElasticActivityRepository;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AskJiminnyReportActivityService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\VO\\Repository\\OnDemandActivitySearch\\Criteria;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\n\nclass AskJiminnyReportActivityServiceTest extends TestCase\n{\n private ActivitySearch&MockObject $activitySearch;\n private ElasticActivityRepository&MockObject $elasticRepository;\n private LoggerInterface&MockObject $logger;\n private AskJiminnyReportActivityService $service;\n\n protected function setUp(): void\n {\n $this->activitySearch = $this->createMock(ActivitySearch::class);\n $this->elasticRepository = $this->createMock(ElasticActivityRepository::class);\n $this->logger = $this->createMock(LoggerInterface::class);\n\n $this->service = new AskJiminnyReportActivityService(\n $this->activitySearch,\n $this->elasticRepository,\n $this->logger,\n );\n }\n\n private function makeFilter(string $key, ?string $value): SearchFilter&MockObject\n {\n $filter = $this->createMock(SearchFilter::class);\n $filter->method('getFilterProperty')->willReturn($key);\n $filter->method('getFilterValue')->willReturn($value);\n\n return $filter;\n }\n\n private function makeUser(): User&MockObject\n {\n $tz = new \\DateTimeZone('UTC');\n $user = $this->createMock(User::class);\n $user->method('getTimezone')->willReturn($tz);\n $user->method('getId')->willReturn(1);\n $user->method('getUuid')->willReturn('user-uuid');\n\n return $user;\n }\n\n private function makeSavedSearch(array $filters): Search&MockObject\n {\n $savedSearch = $this->createMock(Search::class);\n $savedSearch->method('getId')->willReturn(42);\n $savedSearch->method('getFilters')->willReturn(new \\Illuminate\\Support\\LazyCollection($filters));\n\n return $savedSearch;\n }\n\n public function testGetActivityIdsForSavedSearchReturnsIds(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->expects($this->once())\n ->method('getArrayFilterKeys')\n ->with($user)\n ->willReturn([]);\n\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n\n $this->elasticRepository->expects($this->once())\n ->method('onDemandSearchIdsOnly')\n ->willReturn(['id-1', 'id-2', 'id-3']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[AskJiminnyReport] Fetched activity IDs for saved search');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1', 'id-2', 'id-3'], $result);\n }\n\n public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $this->logger->expects($this->once())->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEmpty($result);\n }\n\n public function testGetActivityIdsFiltersOutDateFilters(): void\n {\n $user = $this->makeUser();\n\n $nonDateFilter = $this->makeFilter('owner_id', '123');\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');\n $updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');\n $updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');\n\n $savedSearch = $this->makeSavedSearch([\n $nonDateFilter,\n $startDateFilter,\n $endDateFilter,\n $updatedFromFilter,\n $updatedToFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n }\n\n public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void\n {\n $user = $this->makeUser();\n\n $closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');\n $closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');\n $regularFilter = $this->makeFilter('rep_id', '99');\n\n $savedSearch = $this->makeSavedSearch([\n $closingStartFilter,\n $closingEndFilter,\n $regularFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesArrayFilters(): void\n {\n $user = $this->makeUser();\n\n $filter1 = $this->makeFilter('outcome', 'positive');\n $filter2 = $this->makeFilter('outcome', 'negative');\n\n $savedSearch = $this->makeSavedSearch([$filter1, $filter2]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesScalarFilters(): void\n {\n $user = $this->makeUser();\n\n $filter = $this->makeFilter('direction', 'inbound');\n $savedSearch = $this->makeSavedSearch([$filter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-5'], $result);\n }\n\n public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertFalse($capturedCriteria->isFirstRequest());\n }\n\n public function testGetActivityIdsLogsWithCorrectContext(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with(\n '[AskJiminnyReport] Fetched activity IDs for saved search',\n $this->callback(fn ($context) => $context['saved_search_id'] === 42\n && $context['user_id'] === 1\n && $context['activity_count'] === 2)\n );\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n }\n\n public static function frequencyDateRangeProvider(): array\n {\n $now = CarbonImmutable::parse('2025-06-16 12:00:00');\n\n return [\n 'daily' => [\n AutomatedReportsService::FREQUENCY_DAILY,\n $now->subDay()->startOfDay()->format('Y-m-d H:i:s'),\n $now->subDay()->endOfDay()->format('Y-m-d H:i:s'),\n ],\n 'weekly' => [\n AutomatedReportsService::FREQUENCY_WEEKLY,\n $now->subWeek()->startOfWeek()->format('Y-m-d H:i:s'),\n $now->subWeek()->endOfWeek()->format('Y-m-d H:i:s'),\n ],\n 'monthly' => [\n AutomatedReportsService::FREQUENCY_MONTHLY,\n $now->subMonthNoOverflow()->startOfMonth()->format('Y-m-d H:i:s'),\n $now->subMonthNoOverflow()->endOfMonth()->format('Y-m-d H:i:s'),\n ],\n 'quarterly' => [\n AutomatedReportsService::FREQUENCY_QUARTERLY,\n $now->subQuarterNoOverflow()->startOfQuarter()->format('Y-m-d H:i:s'),\n $now->subQuarterNoOverflow()->endOfQuarter()->format('Y-m-d H:i:s'),\n ],\n ];\n }\n\n /**\n * @dataProvider frequencyDateRangeProvider\n */\n public function testGetActivityIdsInjectsDateRangeForFrequency(\n string $frequency,\n string $expectedStartDate,\n string $expectedEndDate,\n ): void {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n\n public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void\n {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');\n $savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"bounds":{"left":0.40492022,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"bounds":{"left":0.41356382,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"bounds":{"left":0.4245346,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"bounds":{"left":0.4331782,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"bounds":{"left":0.4418218,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"bounds":{"left":0.45279256,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"bounds":{"left":0.4637633,"top":0.09896249,"width":0.024268618,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"bounds":{"left":0.49035904,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"bounds":{"left":0.5013298,"top":0.09896249,"width":0.029587766,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"bounds":{"left":0.69913566,"top":0.09896249,"width":0.02825798,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"27","depth":4,"bounds":{"left":0.6565825,"top":0.123703115,"width":0.009973404,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.66855055,"top":0.123703115,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"23","depth":4,"bounds":{"left":0.67852396,"top":0.123703115,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.69082445,"top":0.123703115,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"105","depth":4,"bounds":{"left":0.70079786,"top":0.123703115,"width":0.011968086,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7144282,"top":0.12210695,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.72174203,"top":0.12210695,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"SELECT * FROM team_features where team_id = 1;\n\nSELECT * FROM teams WHERE name LIKE '%Vixio%'; # 340,270,11922\nSELECT * FROM users WHERE team_id = 340; # 12015\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 340\nand sa.provider = 'salesforce';\n# and sa.provider = 'salesloft';\n\nselect * from crm_fields where crm_configuration_id = 270 and object_type = 'event';\n# 125558 - Event Type - Event_Type__c\n# 125552 - Event Status - Event_Status__c\n\nSELECT * FROM sidekick_settings WHERE team_id = 340;\n\nSELECT * FROM crm_field_values WHERE crm_field_id in (125552);\n\nselect * from activities where crm_configuration_id = 270\nand type = 'conference' and crm_provider_id IS NOT NULL\nand actual_start_time > '2024-09-16 09:00:00' order by scheduled_start_time;\n\nSELECT * FROM activities WHERE id = 20871677;\nSELECT * FROM crm_field_data WHERE activity_id = 20871677;\n\nselect * from crm_layouts where crm_configuration_id = 270;\nselect * from crm_layout_entities where crm_layout_id in (886,887);\n\nSELECT * FROM crm_configurations WHERE id = 270;\n\nselect * from playbooks where team_id = 340; # 1514\nselect * from groups where team_id = 340;\nSELECT * FROM crm_fields WHERE id IN (125393, 125401);\n\nselect g.name as 'team name', p.name as 'playbook name', f.label as 'activity type field' from groups g\njoin playbooks p on g.playbook_id = p.id\njoin crm_fields f on p.activity_field_id = f.id\nwhere g.team_id = 340;\n\nSELECT * FROM activities WHERE uuid_to_bin('0c180357-67d2-419e-a8c3-b832a3490770') = uuid; # 20448716\nselect * from crm_field_data where object_id = 20448716;\n\nselect * from activities where crm_configuration_id = 270 and provider = 'salesloft' order by id desc;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%CybSafe%'; # 343,273,12008\nselect * from opportunities where team_id = 343;\nselect * from opportunities where team_id = 343 and crm_provider_id = '18099102526';\nselect * from opportunities where team_id = 343 and account_id = 945217482;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 343\nand sa.provider = 'hubspot';\n\nselect * from accounts where team_id = 343 order by name asc;\n\nselect * from stages where crm_configuration_id = 273 and type = 'opportunity';\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Voyado%'; # 353,283,12143\nSELECT * FROM activities WHERE crm_configuration_id = 283 and account_id = 3777844 order by id desc;\nSELECT * FROM accounts WHERE team_id = 353 AND name LIKE '%Salesloft%';\nSELECT * FROM activities WHERE id = 20717903;\n\nselect * from participants where activity_id IN (20929172,20928605,20928468,20926272,20926271,20926270,20926269,20916499,20916454,20916436,20916435,20900015,20900014,20900013,20897312,20897243,20897241,20897237,20897232,20897229,20893648,20893231,20893230,20893229,20893228,20889784,20885039,20885038,20885037,20885036,20885035,20882728,20882708,20882703,20882702,20869828,20869811,20869806,20869801,20869799,20869798,20869796,20869795,20869794,20869761,20869760,20869759,20868688,20868687,20850340,20847195,20841710,20833967,20827021,20825307,20825305,20825297,20824615,20824400,20823927,20821760,20795588,20794233,20794057,20793710,20785811,20781789,20781394,20781307,20762651,20758453,20758282,20757323,20756643,20756636,20756629,20756627,20756606,20756605,20756604,20756603,20756602,20756600,20756599,20756598,20756595,20756594,20756589,20756587,20756577,20756573,20748918,20748386,20748385,20748384,20748383,20748382,20748381,20748380,20748379,20748377,20748375,20748373,20743301,20717905,20717904,20717903,20717901,20717899);\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 353\nand sa.provider = 'salesforce';\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%modern world business solutions%'; # 345,275,12016, l.atkinson@mwbsolutions.co.uk\nSELECT * FROM activities WHERE uuid_to_bin('3921d399-3fef-4609-a291-b0097a166d43') = uuid;\n# id: 20940638, user: 12022, contact: 5305871\nSELECT * FROM activity_summary_logs WHERE activity_id = 20940638;\nselect * from contacts where team_id = 345 and crm_provider_id = '30891432415' order by name asc; # 5305871\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 345\nand sa.provider = 'hubspot';\n\nselect * from users where team_id = 345 and id = 12022;\nSELECT * FROM crm_profiles WHERE user_id = 12022;\nSELECT * FROM participants WHERE activity_id = 20940638;\nSELECT * FROM users u\nJOIN crm_profiles cp ON u.id = cp.user_id\nWHERE u.team_id = 345;\n\nselect * from contacts where team_id = 345 and crm_provider_id = '30880813535' order by name desc; # 5305871\n\nselect * from team_features where team_id = 345;\nSELECT * FROM activities WHERE uuid_to_bin('11701e2d-2f82-4dab-a616-1db4fad238df') = uuid; # 21115197\nSELECT * FROM participants WHERE activity_id = 20897406;\n\n\n\nSELECT * FROM activities WHERE uuid_to_bin('63ba55cd-1abc-447d-83da-0137000005b7') = uuid; # 20953912\nSELECT * FROM activities WHERE crm_configuration_id = 275 and provider = 'ringcentral' and title like '%1252629100%';\n\n\nSELECT * FROM activities WHERE id = 20946641;\nSELECT * FROM crm_profiles WHERE user_id = 10211;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Lunio%'; # 120,97,10984, triger@lunio.ai\nSELECT * FROM opportunities WHERE crm_configuration_id = 97 and crm_provider_id = '006N1000006c5PpIAI';\nselect * from stages where crm_configuration_id = 97 and type = 'opportunity';\nselect * from opportunities where team_id = 120;\n\n\nselect * from crm_configurations crm join teams t on crm.id = t.crm_id\nwhere 1=1\nAND t.current_billing_plan IS NOT NULL\nAND crm.auto_sync_activity = 0\nand crm.provider = 'hubspot';\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Exclaimer%'; # 270,205,10053,james.lewendon@exclaimer.com\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 270\nand sa.provider = 'salesforce';\nSELECT * FROM activities WHERE uuid_to_bin('b54df794-2a9a-4957-8d80-09a600ead5f8') = uuid; # 21637956\nSELECT * FROM crm_profiles WHERE user_id = 11446;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Cygnetise%'; # 372,300,12554, alex.chikly@cygnetise.com\nselect * from playbooks where team_id = 372;\nselect * from crm_fields where crm_configuration_id = 300 and object_type = 'event'; # 141340\nSELECT * FROM crm_field_values WHERE crm_field_id = 141340;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 372\nand sa.provider = 'salesforce';\n\nselect * from crm_profiles where crm_configuration_id = 300;\nSELECT * FROM crm_configurations WHERE team_id = 372;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Planday%'; # 291,242,11501,mfa@planday.com\nSELECT * FROM opportunities WHERE team_id = 291 and crm_provider_id = '006bG000005DO86QAG'; # 3207756\nselect * from crm_field_data where object_id = 3207756;\nSELECT * FROM crm_fields WHERE id = 111834;\n\nselect f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value\nFROM crm_fields f\nJOIN crm_field_data fd ON f.id = fd.crm_field_id\nWHERE f.crm_configuration_id = 242\nAND f.object_type = 'opportunity'\nAND fd.object_id IN (3207756)\nORDER BY fd.object_id, fd.updated_at;\n\nSELECT * FROM crm_configurations WHERE auto_connect = 1;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Tour%'; # 187,209,8150,salesforce-admin@tourlane.com\nselect * from group_deal_risk_types drgt join groups g on drgt.group_id = g.id\nwhere g.team_id = 187;\n\nselect * from `groups` where team_id = 187;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 187\nand sa.provider = 'salesforce';\n\n# Destination - 98870 - Destination__c\n# Stage - 79014 - StageName\n# Land Arrangement - 98856 - Land_Arrangement__c\n# Flight - 98848 - Flight__c\n# Last activity date - 98812 - LastActivityDate\n# Last modified date - 98809 - LastModifiedDate\n# Last inbound mail timestamp - 99151 - Last_Inbound_Mail_Timestamp__c\n# next call - 98864 - Next_Call__c\n\nselect * from crm_fields where crm_configuration_id = 209 and object_type = 'opportunity';\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 209;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 682;\n\nselect * from opportunities where team_id = 187 and name LIKE'%Muriel Sal%';\nselect * from opportunities where team_id = 187 and user_id = 9951 and is_closed = 0;\nselect * from activities where opportunity_id = 3538248;\n\nSELECT * FROM crm_profiles WHERE user_id = 8150;\n\nselect * from deal_risks where opportunity_id = 3538248;\n\nselect * from teams where crm_id IS NULL;\n\nSELECT opp.id AS opportunity_id,\n u.group_id AS group_id,\n MAX(\n CASE\n WHEN a.type IN (\"sms-inbound\", \"sms-outbound\") THEN a.created_at\n ELSE a.actual_end_time\n END) as last_date\nFROM opportunities opp\nleft join activities a on a.opportunity_id = opp.id\ninner join users u on opp.user_id = u.id\nwhere opp.user_id IN (9951)\n\nAND opp.is_closed = 0\nand a.status IN ('completed', 'received', 'delivered') OR a.status IS NULL\ngroup by opp.id;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Cybsafe%'; # 343,301,12008,polly.morphew@cybsafe.com\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 343\nand sa.provider = 'hubspot';\n\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 301;\nSELECT * FROM contacts WHERE id = 6612363;\nSELECT * FROM accounts WHERE id = 4235676;\nSELECT * FROM opportunities WHERE crm_configuration_id = 301 and crm_provider_id = 32983784868;\nselect * from opportunity_stages where opportunity_id = 4503759;\n# SELECT * FROM opportunities WHERE id = 4569937;\n\nselect * from activities where crm_configuration_id = 301;\nSELECT * FROM activities WHERE uuid_to_bin('d3b2b28b-c3d0-4c2d-8ed0-eef42855278a') = uuid; # 26330370\nSELECT * FROM participants WHERE activity_id = 26330370;\n\nSELECT * FROM teams WHERE id = 375;\nselect * from playbooks where team_id = 375;\n\nselect * from stages where crm_configuration_id = 301 and type = 'opportunity';\n\nselect * from teams;\nselect * from contact_roles;\n\nSELECT * FROM opportunities WHERE team_id = 343 and user_id = 12871 and close_date >= '2024-11-01';\n\nselect * from users u join crm_profiles cp on cp.user_id = u.id where u.team_id = 343;\n\nSELECT * FROM crm_field_data WHERE object_id = 3771706;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 343\nand sa.provider = 'hubspot';\n\nSELECT * FROM crm_fields WHERE crm_configuration_id = 301 and object_type = 'opportunity'\nand crm_provider_id LIKE \"%traffic_light%\";\nSELECT * FROM crm_field_values WHERE crm_field_id IN (144020,144048,144111,144113,144126,144481,144508,144531);\n\nSELECT fd.* FROM opportunities o\nJOIN crm_field_data fd ON o.id = fd.object_id\nWHERE o.team_id = 343\n# and o.user_id IS NOT NULL\nand fd.crm_field_id IN (144020,144048,144111,144113,144126,144481,144508,144531)\nand fd.value != ''\norder by value desc\n# group by o.id\n;\n\nSELECT * FROM opportunities WHERE id = 3769843;\n\nSELECT * FROM teams WHERE name LIKE '%Tour%'; # 187,209,8150, salesforce-admin@tourlane.com\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 209;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 682;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Funding Circle%'; # 220,177,8603,aswini.mishra@fundingcircle.com\nSELECT * FROM activities WHERE uuid_to_bin('7a40e99b-3b37-4bb1-b983-325b81801c01') = uuid; # 23139839\n\n\nSELECT * FROM opportunities WHERE id = 3855992;\n\nSELECT * FROM users WHERE name LIKE '%Angus Pollard%'; # 8988\n\nSELECT * FROM teams WHERE name LIKE '%Story Terrace%'; # 379, 307, 12894\nSELECT * FROM crm_fields WHERE crm_configuration_id = 307 and object_type != 'opportunity';\n\nselect * from contacts where team_id = 379 and name like '%bebro%'; # 5874411, crm: 77229348507\nSELECT * FROM crm_field_data WHERE object_id = 5874411;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 379\nand sa.provider = 'hubspot';\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%mentio%'; # 117, 94, 6371, nikhil.kumar@mention-me.com\nSELECT * FROM activities WHERE uuid_to_bin('82939311-1af0-4506-8546-21e8d1fdf2c1') = uuid;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Tourlane%'; # 187, 209, 8150, salesforce-admin@tourlane.com\nSELECT * FROM opportunities WHERE team_id = 187 and crm_provider_id = '006Se000008xfvNIAQ'; # 3537793\nselect * from generic_ai_prompts where subject_id = 3537793;\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Lunio%'; # 120, 97, 10984, triger@lunio.ai\nSELECT * FROM crm_configurations WHERE id = 97;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 97;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 355;\nSELECT * FROM crm_fields WHERE id = 32682;\n\nselect cfd.value, o.* from opportunities o\njoin crm_field_data cfd on o.id = cfd.object_id and cfd.crm_field_id = 32682\nwhere team_id = 120\nand cfd.value != ''\n;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 120\nand sa.provider = 'salesforce';\n\nselect * from opportunities where team_id = 120 and crm_provider_id = '006N1000007X8MAIA0';\nSELECT * FROM crm_field_data WHERE object_id = 2313439;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE id = 410;\nSELECT * FROM teams WHERE name LIKE '%Local Business Oxford%';\nselect * from scorecards where team_id = 410;\nselect * from scorecard_rules;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Funding%'; # 220, 177, 8603, aswini.mishra@fundingcircle.com\nselect * from activities a\njoin opportunities o on a.opportunity_id = o.id\njoin users u on o.user_id = u.id\nwhere a.crm_configuration_id = 177 and a.type LIKE '%email-out%'\n# and a.actual_end_time > '2024-12-16 00:00:00'\n# and o.remotely_created_at > '2024-12-01 00:00:00'\n# and u.group_id = 1014\nand u.id = 9021\norder by a.id desc;\nSELECT * FROM opportunities WHERE id in (3981384,4017346);\nSELECT * FROM users WHERE team_id = 220 and id IN (8775, 11435);\n\nselect * from users where id = 9021;\nselect * from inboxes where user_id = 9021;\n\nselect * from inbox_emails where inbox_id = 1349 and email_date > '2024-12-18 00:00:00';\n\nselect * from email_messages where team_id = 220\nand orig_date > '2024-12-16 00:00:00' and orig_date < '2024-12-19 00:00:00'\nand subject LIKE '%Personal%'\n# and 'from' = 'credit@fundingcircle.com'\n;\n\nselect * from activities a\njoin opportunities o on a.opportunity_id = o.id\nwhere a.user_id = 9021 and a.type LIKE '%email-out%'\nand a.actual_end_time > '2024-12-18 00:00:00'\nand o.user_id IS NOT NULL\nand o.remotely_created_at > '2024-12-01 00:00:00'\norder by a.id desc;\n\nSELECT * FROM opportunities WHERE team_id = 220 and name LIKE '%Right Car move Limited%' and id = 3966852;\nselect * from activities where crm_configuration_id = 177 and type LIKE '%email%' and opportunity_id = 3966852 order by id desc;\n\nselect * from team_settings where name IN ('useCloseDate');\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Hurree%'; # 104, 81, 6175, jfarrell@hurree.co\nSELECT * FROM opportunities WHERE team_id = 104 and name = 'PropOp';\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 104\nand sa.provider = 'hubspot';\n\nselect * from crm_configurations where last_synced_at > '2025-01-19 01:00:00'\nselect * from teams where crm_id IS NULL;\n\nselect t.name as 'team', u.name as 'owner', u.email, u.phone\nfrom teams t\njoin activity_providers ap on t.id = ap.team_id\njoin users u on t.owner_id = u.id\nwhere 1=1\n and t.status = 'active'\n and ap.is_enabled = 1\n# and u.status = 1\n and ap.provider = 'ms-teams';\n\nselect * from crm_configurations where provider = 'bullhorn'; # 344\nSELECT * FROM teams WHERE id = 442; # 14293\nselect * from users where team_id = 442;\nselect * from social_accounts sa where sa.sociable_id = 14293;\nselect * from invitations where team_id = 442;\n\n# ********************************************************************************************************\nSELECT * FROM users WHERE email LIKE '%nea.liikamaa@eletive.com%'; # 14022\nSELECT * FROM teams WHERE id = 429;\nselect * from opportunities where team_id = 429 and crm_provider_id IN (16157415775, 22246219645);\nselect * from activities where opportunity_id in (4340436,4353519);\n\nselect * from transcription where activity_id IN (25630961,25381771);\nselect * from generic_ai_prompts where subject_id IN (4353519);\n\nSELECT\n a.id as activity_id,\n a.opportunity_id,\n a.type as activity_type,\n a.language,\n CONCAT(a.title, a.description) AS mail_content,\n e.from AS mail_from,\n e.to AS mail_to,\n e.subject AS mail_subject,\n e.body AS mail_body,\n p.type as prompt_type,\n p.status as prompt_status,\n p.content AS prompt_content,\n a.actual_start_time as created_at\nFROM activities a\n LEFT JOIN ai_prompts p ON a.transcription_id = p.transcription_id AND p.deleted_at IS NULL\n LEFT JOIN email_messages e ON a.id = e.activity_id\nWHERE a.actual_start_time > '2024-01-01 00:00:00'\n AND a.opportunity_id IN (4353519)\n AND a.status IN ('completed', 'received', 'delivered')\n AND a.deleted_at IS NULL\n AND a.type NOT IN ('sms-inbound', 'sms-outbound')\nORDER BY a.opportunity_id ASC, a.id ASC;\n\nSELECT * FROM users WHERE name LIKE '%George Fierstone%'; # 14293\nSELECT * FROM teams WHERE id = 442;\nSELECT * FROM crm_configurations WHERE id = 344;\nselect * from team_features where team_id = 442;\nselect * from groups where team_id = 442;\nselect * from playbooks where team_id = 442;\nselect * from playbook_categories where playbook_id = 1729;\nselect * from crm_fields where crm_configuration_id = 344 and id = 172024;\nSELECT * FROM crm_field_values WHERE crm_field_id = 172024;\nselect * from crm_layouts where crm_configuration_id = 344;\nselect * from playbook_layouts where playbook_id = 1729;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Learning%'; # 260, 221, 9444\n\nselect s.*\n# , s.sent_at, u.name, a.*\nfrom activity_summary_logs s\ninner join activities a on a.id = s.activity_id\ninner join users u on u.id = a.user_id\nwhere a.crm_configuration_id = 356\nand s.sent_at > date_sub(now(), interval 60 day)\norder by a.actual_end_time desc;\n\nselect * from activities a\n# inner join activity_summary_logs s on s.activity_id = a.id\nwhere a.crm_configuration_id = 356 and a.actual_end_time > date_sub(now(), interval 60 day)\n# and a.crm_provider_id is not null\n# and provider <> 'ringcentral'\nand status = 'completed'\norder by a.actual_end_time desc;\n\nselect * from teams order by id desc; # 17328, 32, 17830, integration-account@jiminny.com\nSELECT * FROM users;\nSELECT * FROM users where team_id = 260 and status = 1; # 201 - 150 active\nSELECT * FROM teams WHERE id = 260;\nselect * from team_settings where team_id = 260;\nselect * from crm_configurations where team_id = 260;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 356;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1184;\n\nselect * from accounts where crm_configuration_id = 221 order by id desc; # 7000\nselect * from leads where crm_configuration_id = 221 order by id desc; # 0\nselect * from contacts where crm_configuration_id = 221 order by id desc; # 200 000\nselect * from opportunities where crm_configuration_id = 221 order by id desc; # 0\nselect * from crm_profiles where crm_configuration_id = 221 order by id desc; # 23\nselect * from crm_fields where crm_configuration_id = 221;\nselect * from crm_field_values where crm_field_id = 5302 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 221 order by id desc;\nselect * from stages where crm_configuration_id = 221 order by id desc;\n\nselect * from accounts where crm_configuration_id = 356 order by id desc; # 7000\nselect * from leads where crm_configuration_id = 356 order by id desc; # 0\nselect * from contacts where crm_configuration_id = 356 order by id desc; # 200 000\nselect * from opportunities where crm_configuration_id = 356 order by id desc; # 0\nselect * from crm_profiles where crm_configuration_id = 356 order by id desc; # 23\nselect * from crm_fields where crm_configuration_id = 356;\nselect * from crm_field_values where crm_field_id = 5302 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 356 order by id desc;\nselect * from stages where crm_configuration_id = 356 order by id desc;\n\nselect * from playbooks where team_id = 260 order by id desc; # 4 (2 deleted)\nselect * from groups where team_id = 260 order by id desc; # 27 groups, (2 deleted)\nselect * from playbook_layouts where playbook_id IN (1410,1409,1276,1254); # 4\nselect ce.* from calendars c\njoin users u on c.user_id = u.id\njoin calendar_events ce on c.id = ce.calendar_id\nwhere u.team_id = 260\nand (ce.start_time > '2025-02-21 00:00:00')\n;\n# calendar events 1207\n#\n\nselect * from opportunities where team_id = 260;\nSELECT * FROM crm_field_data WHERE object_id = 4696496;\n\nselect * from activities where crm_configuration_id = 356 and crm_provider_id IS NOT NULL;\nselect * from activities where crm_configuration_id IN (221) and provider NOT IN ('ms-teams', 'uploader', 'zoom-bot')\n# and type = 'conference' and status = 'scheduled' and activities.is_internal = 0\nand created_at > '2024-03-01 00:00:00'\norder by id desc; # 880 000, ringcentral, avaya\nSELECT * FROM participants WHERE activity_id = 26371744;\n\n# all activities 942 000 +\n# conference 7385 - scheduled 984 - external 343\n\nselect * from activities where id = 26321812;\nselect * from participants where activity_id = 26321812;\nselect * from participants where activity_id in (26414510,26414514,26414516,26414604,26414653,26414655);\nselect * from leads where id in (720428,689175,731546,645866,621037);\n\nselect * from users where id = 13841;\nselect * from opportunities where user_id = 9541;\nselect * from stages where id = 15900;\n\nselect * from accounts where\n# id IN (4160055,5053725,4965303,4896434)\nid in (4584518,3249934,3218025,3891133,3399450,4172999,4485161,3101785,4587203,3070816,2870343,2870341,3563940,4550846,3424464,3249963,2870342)\n;\n\nselect * from activities where id = 26654935;\nSELECT * FROM opportunities WHERE id = 4803458;\n\nSELECT * FROM opportunities where team_id = 260 and user_id = 13841 AND stage_id = 15900;\nSELECT id, uuid, provider, type, lead_id, account_id, contact_id, opportunity_id, stage_id, status, recording_state, title, actual_start_time, actual_end_time\nFROM activities WHERE user_id = 13841 AND opportunity_id IN (4729783, 4731717, 4731726, 4732064, 4732849, 4803458, 4813213);\n\nSELECT DISTINCT\n o.id, o.stage_id, s.name, a.title,\n a.*\nFROM activities a\n# INNER JOIN tracks t ON a.id = t.activity_id\nINNER JOIN users u ON a.user_id = u.id\nINNER JOIN teams team ON u.team_id = team.id\nINNER JOIN groups g ON u.group_id = g.id\nINNER JOIN opportunities o ON a.opportunity_id = o.id\nINNER JOIN stages s ON o.stage_id = s.id\nWHERE\n a.crm_configuration_id = 356\n AND a.status IN ('completed', 'failed')\n AND a.recording_state != 'stopped'\n# and a.user_id = 13841\n AND u.uuid = uuid_to_bin('6f40e4b8-c340-4059-b4ac-1728e87ea99e')\n AND team.uuid = uuid_to_bin('a607fba7-452e-4683-b2af-00d6cb52c93c')\n AND g.uuid = uuid_to_bin('b5d69e40-24a0-4c16-810b-5fa462299f94')\n\n AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')\n# AND t.type IN ('audio', 'video')\n AND (\n (a.actual_start_time BETWEEN '2025-03-13 00:00:00' AND '2025-03-18 07:59:59')\n OR\n (\n a.actual_start_time IS NULL\n AND a.type IN ('sms-outbound', 'sms-inbound')\n AND a.created_at BETWEEN '2025-03-13 00:00:00' AND '2025-03-18 07:59:59'\n )\n )\n AND (\n a.is_private = 0\n OR (\n a.is_private = 1\n AND u.uuid = uuid_to_bin('6f40e4b8-c340-4059-b4ac-1728e87ea99e')\n )\n )\n AND (\n# s.id = 15900\n s.uuid = uuid_to_bin('04ca1c26-c666-4268-a129-419c0acffd73')\n OR s.uuid IS NULL -- Include records without opportunity stage\n )\n\nORDER BY a.actual_end_time DESC;\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Lead Forensics%'; # 190, 162, 8474, willsc@leadforensics.com\nSELECT * FROM users WHERE team_id = 190;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 190\nand sa.provider = 'hubspot';\n\nselect * from role_user where user_id = 8474;\n\nselect * from crm_configurations where provider = 'bullhorn';\n\nSELECT * FROM opportunities WHERE uuid_to_bin('94578249-65ec-4205-90f2-7d1a7d5ab64a') = uuid;\nSELECT * FROM users WHERE uuid_to_bin('26dbadeb-926f-4150-b11b-771b9d4c2f9a') = uuid;\n\nSELECT * FROM opportunities WHERE id = 4732493;\nselect * from activities where opportunity_id = 4732493;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE id = 443; # 358, 14315, andrea.romano@correrenaturale.com\nSELECT * FROM opportunities WHERE team_id = 443;\n\nSELECT a.id, a.type, a.user_id, a.status, a.deleted_at, u.name, u.email, u.team_id as activity_team_id, u.status, u.deleted_at, t.name, t.status, s.team_id as stage_team_id\nFROM activities AS a\nJOIN stages AS s ON a.stage_id = s.id\nJOIN users AS u ON u.id = a.user_id\nJOIN teams AS t ON t.id = s.team_id\nWHERE u.team_id <> s.team_id and t.id > 135;\n\n\nSELECT\n crm_configuration_id,\n crm_provider_id,\n COUNT(*) as duplicate_count,\n GROUP_CONCAT(id) as stage_ids,\n GROUP_CONCAT(name) as stage_names\nFROM stages\nGROUP BY crm_configuration_id, crm_provider_id\nHAVING COUNT(*) > 1\nORDER BY duplicate_count DESC;\n\nselect * from stages where id IN (14898,14907);\n\nselect * from business_processes;\n\nSELECT *\nFROM crm_configurations\nWHERE team_id IN (\n SELECT team_id\n FROM crm_configurations\n GROUP BY team_id\n HAVING COUNT(*) > 1\n)\nORDER BY team_id;\n\nSELECT *\nFROM teams\nWHERE crm_id IN (\n SELECT crm_id\n FROM teams\n GROUP BY crm_id\n HAVING COUNT(*) > 1\n)\nORDER BY crm_id;\n\n# ***************************************************************************\nselect * from crm_configurations where provider = 'integration-app';\nSELECT * FROM teams WHERE id = 443; # Correre Naturale 358 14315 andrea.romano@correrenaturale.com\nselect * from activities where crm_configuration_id = 358 order by actual_end_time desc;\nselect id, uuid, actual_end_time, crm_provider_id, is_internal, playbook_category_id, type, user_id, lead_id, contact_id, account_id, opportunity_id, status, title from activities where crm_configuration_id = 358 order by actual_end_time desc;\nselect * from team_features where team_id = 358;\nselect * from activity_summary_logs;\n\nselect * from teams where id = 406;\n\n# ************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Sportfive%'; # 267, 202, 14637, srv.salesforce@sportfive.com\nselect * from activities where crm_configuration_id = 202 order by actual_end_time desc;\n\nSELECT * FROM users where id = 14637;\nSELECT * FROM teams where id = 267;\nSELECT * FROM groups where id = 1118;\n\nselect g.name, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled_start_time, a.scheduled_end_time, a.actual_start_time, a.actual_end_time from activities a\ninner join users u on u.id = a.user_id\ninner join groups g on g.id = u.group_id\nwhere a.crm_configuration_id = 202\nand a.is_internal = 0\nand (a.scheduled_start_time between '2025-03-19 00:00:00' and '2025-03-21 00:00:00')\nand a.type = 'conference'\nand a.status != 'completed'\nand a.external_id is not null\norder by a.scheduled_start_time desc;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 202\n AND status IN ('completed', 'failed')\n AND recording_state != 'stopped'\n AND type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')\n AND (is_private = 0 OR user_id = 14637)\n AND (\n (\n actual_start_time BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'\n ) OR (\n actual_start_time IS NULL\n AND type IN ('sms-outbound', 'sms-inbound')\n AND created_at BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'\n )\n )\n AND NOT EXISTS (\n SELECT 1\n FROM tracks\n WHERE\n tracks.activity_id = activities.id\n AND tracks.type IN ('audio', 'video')\n )\nORDER BY actual_end_time DESC;\n\nSELECT DISTINCT\n a.*\nFROM activities a\nINNER JOIN tracks t ON a.id = t.activity_id\nINNER JOIN users u ON a.user_id = u.id\nINNER JOIN teams team ON u.team_id = team.id\nWHERE\n a.crm_configuration_id = 202\n AND a.status IN ('completed', 'failed')\n AND a.recording_state != 'stopped'\n# and a.user_id = 14637\n AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')\n# AND t.type IN ('audio', 'video')\n AND (\n (a.actual_start_time BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59')\n OR\n (\n a.actual_start_time IS NULL\n AND a.type IN ('sms-outbound', 'sms-inbound')\n AND a.created_at BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'\n )\n )\n AND (\n a.is_private = 0\n OR (\n a.is_private = 1\n AND a.user_id = 14637\n )\n )\n\nORDER BY a.actual_end_time DESC\n;\n\nSELECT DISTINCT a.*\nFROM activities a\nINNER JOIN users u ON a.user_id = u.id\nINNER JOIN teams t ON u.team_id = t.id\n# INNER JOIN tracks tr ON a.id = tr.activity_id\n# INNER JOIN groups g ON u.group_id = g.id\nWHERE 1=1\n AND t.id = 267\n# AND t.uuid = uuid_to_bin('aed4927b-f1ea-499e-94c3-83762fd233e8')\n AND a.status IN ('completed', 'failed')\n AND a.recording_state != 'stopped'\n AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')\n# AND tr.type NOT IN ('audio', 'video')\n AND (\n a.is_private = 0\n OR a.user_id = 14637\n )\n AND (\n (a.actual_start_time BETWEEN '2025-03-19 00:00:00' AND '2025-03-21 23:59:59')\n OR (\n a.actual_start_time IS NULL\n AND a.type IN ('sms-outbound', 'sms-inbound')\n AND a.created_at BETWEEN '2025-03-19 00:00:00' AND '2025-03-21 23:59:59'\n )\n )\n# and NOT EXISTS (\n# SELECT 1\n# FROM tracks t\n# WHERE t.activity_id = a.id\n# AND t.type IN ('audio', 'video')\n# )\n\nORDER BY a.actual_end_time DESC;\n\nSELECT * FROM tracks WHERE activity_id = 26485995;\n\nselect a.is_private, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled_start_time, a.scheduled_end_time, a.actual_start_time, a.actual_end_time from activities a\ninner join users u on u.id = a.user_id\nwhere a.crm_configuration_id = 202\n# and a.is_internal = 0\nand (a.actual_start_time between '2025-03-19 00:00:00' and '2025-03-21 00:00:00')\nand a.type IN (\"softphone\",\"softphone-inbound\",\"conference\",\"sms-inbound\")\nand a.status IN ('completed', 'failed')\n# and a.external_id is not null\norder by a.actual_end_time desc;\n\nselect * from activities a where a.crm_configuration_id = 202\nand a.actual_start_time between '2025-03-20 00:00:00' and '2025-03-21 00:00:00'\n# AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')\n\nselect g.name, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled_start_time, a.scheduled_end_time, a.actual_start_time, a.actual_end_time from activities a\ninner join users u on u.id = a.user_id\ninner join groups g on g.id = u.group_id\nwhere a.crm_configuration_id = 202\nand a.is_internal = 0\nand (a.scheduled_start_time between '2025-03-19 00:00:00' and '2025-03-21 00:00:00')\nand a.type = 'conference'\nand a.status != 'completed'\nand a.external_id is not null\norder by a.scheduled_start_time desc;\n\nSELECT * FROM teams WHERE name LIKE '%Tourlane%';\nSELECT * FROM crm_fields WHERE crm_configuration_id = 209 and object_type = 'opportunity';\nSELECT * FROM crm_field_data WHERE crm_field_id = 98809;\n\nselect * from users where status = 1 AND timezone = 'MDT';\n\nselect * from opportunities where id = 3769814;\nselect * from deal_risks where opportunity_id = 3769814;\n\nselect cp.* from crm_profiles cp\njoin users u on cp.user_id = u.id\njoin crm_configurations crm on cp.crm_configuration_id = crm.id\nwhere crm.provider = 'hubspot' AND u.status = 1 AND log_notes != 'none';\n\nselect * from crm_fields where id = 154575;\n\nselect * from team_features where feature = 'SUPPORTS_SYNC_MISSING_CALL_DISPOSITIONS';\nSELECT * FROM teams WHERE id = 176; # crm 148\nselect * from activities where crm_configuration_id = 148 and provider = 'hubspot' order by id desc;\n\nselect * from activity_providers where provider = 'amazon-connect';\n\nselect * from crm_fields cf\njoin crm_configurations crm on crm.id = cf.crm_configuration_id\nwhere crm.provider = 'hubspot' and cf.object_type IN ('account', 'contact');\n\n# *********************************************************************************************\nSELECT * FROM users WHERE id IN (15415, 15418);\nSELECT * FROM groups WHERE id IN (1805,1806);\nSELECT * FROM playbooks WHERE id = 1860;\nSELECT * FROM playbook_categories WHERE id = 38634;\nSELECT * FROM crm_fields WHERE id = 189962;\n\nSELECT * FROM teams WHERE name = 'Pulsar Group'; # 472, 380, 15138 raza.gilani@vuelio.com\n\nSELECT * FROM crm_profiles WHERE user_id = 15415;\nSELECT * FROM social_accounts WHERE sociable_id = 15415 and provider = 'salesforce';\n\nselect * from sidekick_settings where team_id = 472;\n\nSELECT * FROM activities WHERE uuid_to_bin('452c58c7-b87c-4fdd-953e-d7af185e9588') = uuid; # 28617536, user: 15418\nSELECT * FROM activities WHERE uuid_to_bin('399114ee-d3a8-458c-bff5-5f654658db0a') = uuid; # 28344407, user: 15415\nSELECT * FROM activities WHERE uuid_to_bin('f0aa567f-0ab1-4bbb-96aa-37dcf184676b') = uuid; # 28580288, user: 15415\nSELECT * FROM activities WHERE uuid_to_bin('50c086b1-2770-4bca-b5ae-6bac22ec426b') = uuid; # 28566069, user: 15415\n\n# *********************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%TeamTailor%'; # 109, 218, 13969, salesforce-integrations@teamtailor.com\nselect * from crm_configurations where id = 218;\nSELECT * FROM activities WHERE uuid_to_bin('e39b5857-7fdb-4f5a-951a-8d3ca69bb1b0') = uuid; # 28338765\nSELECT * FROM users WHERE id IN (13232, 13230);\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 109\nand sa.provider = 'salesforce';\n\n0057R00000EPL5HQAX Inez Ekblad\n\n1091cb81-5ea1-4951-a0ed-f00b568f0140 Triman Kaur\n\nSELECT * FROM crm_profiles WHERE user_id IN (13232, 13230);\n\n############################################################################################\nSELECT * FROM activities WHERE uuid_to_bin('675eeaeb-5681-42db-90bc-54c07a604408') = uuid; # 28655939 00UVg00000FLvnSMAT\nSELECT * FROM crm_field_data WHERE activity_id = 28655939;\nSELECT * FROM crm_fields WHERE id IN (94491,94493,94498);\nSELECT * FROM users WHERE id = 13658;\nSELECT * FROM teams WHERE id = 109;\nSELECT * FROM crm_configurations WHERE id = 218;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 109\nand sa.provider = 'salesforce';\n\n# ********************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Strengthscope%'; # 481, 390, 15420, katy.holden@strengthscope.comk\nSELECT * FROM stages WHERE crm_configuration_id = 390;\nselect * from business_processes where team_id = 481 and crm_configuration_id = 390;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 481\nand sa.provider = 'salesforce';\n\n\nSELECT * FROM users WHERE id = 15780; # team 462\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 462\nand sa.provider = 'hubspot';\n\n\nselect * from teams where id = 495;\nSELECT * FROM users WHERE id = 15794;\nselect * from social_accounts where sociable_id = 15794;\n\n# ********************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Flight%'; # 427, 333, 13752\nSELECT * FROM accounts WHERE team_id = 427 and crm_provider_id = '668731000183444517';\n\n# ********************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Group GTI%'; # 495, 407, 15794\nSELECT * FROM activities WHERE crm_configuration_id = 407\nand status = 'completed' and type = 'conference'\norder by id desc;\n\nselect ru.*, pr.*, p.* from users u join role_user ru on ru.user_id = u.id\njoin permission_role pr on pr.role_id = ru.role_id\n join permissions p on p.id = pr.permission_id\nwhere team_id = 495 and p.name IN ('dial');\n\nselect * from permission_role;\n\nselect * from activities where crm_configuration_id = 407 and status = 'completed' order by id desc;\nSELECT * FROM activities WHERE id = 29512773;\nSELECT * FROM activities WHERE id IN (29042721,28991325,29002874);\n\nSELECT al.* from activity_summary_logs al join activities a on a.id = al.activity_id\nwhere a.crm_configuration_id = 407\n# and a.id IN (29042721,28991325,29002874);\n\nSELECT * FROM users WHERE id = 15794;\nSELECT * FROM users WHERE team_id = 495;\nSELECT * FROM social_accounts WHERE sociable_id = 15794;\nSELECT * FROM opportunities WHERE team_id = 495 and name like '%OC:%';\nSELECT * FROM contacts WHERE team_id = 495;\nSELECT * FROM leads WHERE team_id = 495;\nSELECT * FROM accounts WHERE team_id = 495;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 407;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 407;\nSELECT * FROM crm_configurations WHERE id = 407;\nSELECT * FROM opportunities WHERE team_id = 495 and close_date BETWEEN '2025-06-01' AND '2025-07-01'\nand user_id IS NOT NULL and is_closed = 1 and is_won = 1;\n\n# ********************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Hamilton Court FX LLP%'; # 249, 187, 10103\nSELECT * FROM activities WHERE uuid_to_bin('4659c2bb-9a49-484e-9327-a3d66f1e028c') = uuid; # 28951064\nSELECT * FROM crm_fields WHERE crm_configuration_id = 187 and object_type IN ('tasks', 'event');\n\n# *********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Checkstep%'; # 325, 256, 11753\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 325\nand sa.provider = 'hubspot';\n\nSELECT * FROM activities WHERE uuid_to_bin('7be372e2-1916-4d79-a2f3-ca3db1346db3') = uuid; # 28611085\nSELECT * FROM activities WHERE uuid_to_bin('980f0336-840b-4185-a5a9-30cf8b0749a8') = uuid; # 28719733\nSELECT * FROM activity_summary_logs where activity_id = 28719733;\n\n# *************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Learning%'; # 260, 356, 9444\nSELECT * FROM activity_summary_logs where sent_at BETWEEN '2025-06-09 11:38:00' AND '2025-06-09 11:40:00';\nSELECT * FROM leads WHERE crm_configuration_id = 356 and crm_provider_id = '230045001502770504'; # 823630\nselect * from activities where crm_configuration_id = 356 and lead_id = 841732;\n\nSELECT * from activity_summary_logs al join activities a on a.id = al.activity_id\nwhere a.crm_configuration_id = 356;\n\nselect * from activities where crm_configuration_id = 356\nand actual_end_time between '2025-06-09 11:00:00' and '2025-06-09 12:00:00'\norder by id desc;\n\nselect * from accounts where crm_configuration_id = 356 and crm_provider_id = '230045001514403366' order by id desc;\nselect * from leads where crm_configuration_id = 356 and crm_provider_id = '230045001514275654' order by id desc;\nselect * from contacts where crm_configuration_id = 356 and crm_provider_id = '230045001514403366' order by id desc;\nselect * from opportunities where crm_configuration_id = 356 and crm_provider_id = '230045001514403366' order by id desc;\n\nselect * from team_features where team_id = 260;\nselect * from features where id IN (1,2,4,6,18,19,20,9,10,3,23,24,25,26,27);\n\nSELECT * FROM activities WHERE uuid_to_bin('7be372e2-1916-4d79-a2f3-ca3db1346db3') = uuid;\n\nselect * from crm_fields;\nselect * from crm_layout_entities;\n\nSELECT * FROM teams WHERE name LIKE '%Optable%';\n\n# *************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Teamtailor%'; # 109, 218, 13969\nSELECT * FROM crm_configurations WHERE id = 218;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 109\nand sa.provider = 'salesforce';\nSELECT * FROM activities WHERE uuid_to_bin('675eeaeb-5681-42db-90bc-54c07a604408') = uuid; # 28655939\nSELECT * FROM crm_field_data WHERE activity_id = 28655939;\nSELECT * FROM crm_fields WHERE id in (94491,94493,94498);\n\nselect * from teams where crm_id IS NULL;\n\nSELECT * FROM activities WHERE uuid_to_bin('71aa8a0c-9652-4ff6-bee7-d98ae60abef6') = uuid;\n\n# *************************************************************************************************\nselect * from team_domains where team_id = 399;\nSELECT * FROM teams WHERE name LIKE '%Rydoo%'; # 399, 318, 13207\n\nselect * from calendar_events where id = 5163781;\nSELECT * FROM activities WHERE uuid_to_bin('be2cbc52-7fda-46a0-9ae0-25d9553eafc0') = uuid; # 29443896\nSELECT * FROM participants WHERE activity_id = 29443896;\nselect * from contacts where crm_configuration_id = 318 and email = 'marianne.westeng@strawberry.no';\nselect * from leads where crm_configuration_id = 318 and email = 'marianne.westeng@strawberry.no';\n\nselect * from activities where user_id = 14937 order by created_at ;\n\nselect * from users where id = 14937;\n\nselect * from contacts where crm_configuration_id = 318 and email LIKE '%@strawberry.se';\nselect * from opportunities where crm_configuration_id = 318 and crm_provider_id = '006Sf00000D1WOAIA3';\n\nselect * from activities a join participants p on a.id = p.activity_id\nwhere crm_configuration_id = 318 and a.updated_at > '2025-06-23T08:18:43Z';\n\n# *************************************************************************************************\nSELECT * FROM opportunities WHERE team_id = 379 and crm_provider_id = '39334518886';\nSELECT * FROM opportunities WHERE team_id = 379 order by id desc;\nSELECT * FROM teams WHERE id = 379;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 379 and sociable_id = 13852\nand sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations WHERE id = 307;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 307;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1027;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 307\n and id IN (144750,144855,145158,155227);\n\nSELECT * FROM activities;\n\n\nselect * from activities\nwhere created_at > '2025-07-01 00:00:00'\n# and created_at < '2025-08-01 00:00:00'\nand type not in ('email-outbound', 'email-inbound')\nand account_id is null\nand contact_id is null\nand lead_id is null\nand opportunity_id is not null\n;\nSELECT * FROM activities WHERE id IN (25344155, 25344296, 25501909, 28692187);\nSELECT * FROM crm_configurations WHERE id in (335,301,200);\n\nselect * from crm_fields where crm_configuration_id = 230 and crm_provider_id = 'Age2__c';\n\nSELECT * FROM teams WHERE name LIKE '%Resights%';\nselect * from crm_fields where crm_configuration_id = 1 and object_type = 'opportunity';\n\nselect * from crm_configurations where provider = 'bullhorn'; # 344\nselect * from teams where id IN (442);\n\nselect * from activities\nwhere crm_configuration_id = 177\nand provider = 'amazon-connect'\n order by id desc;\n# and source <> 'gong';\n\nselect * from activity_providers where provider = 'amazon-connect';\n\nSELECT * FROM activities WHERE uuid_to_bin('cec1993b-a7e5-4164-b74d-d680ea51d2f2') = uuid;\n\n\nselect * from crm_configurations where store_transcript = 1;\nSELECT * FROM teams WHERE id IN (80);\n\n# *************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Sedna%'; # 277, 213, 12594\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 277\nand sa.provider = 'salesforce';\n\nselect * from activities where crm_configuration_id = 213 and account_id = 2511502;\n\nselect * from crm_configurations where id = 213;\n\nSELECT * FROM activities WHERE uuid_to_bin('35aa790a-8569-4544-8268-66f9a4a26804') = uuid; # 33981604\nSELECT * FROM participants WHERE activity_id = 33981604;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 337 and object_type = 'task';\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 431\nand sa.provider = 'salesforce';\nSELECT * FROM activities WHERE uuid_to_bin('b5476c7d-19a8-491b-869d-676ea1e857b6') = uuid; # 33997223\nselect * from activity_summary_logs where activity_id = 33997223;\nselect * from activity_notes where activity_id = 33997223;\n\n# ***********************************\nSELECT * FROM teams WHERE name LIKE '%Abode%';\n\n\nselect * from features;\nselect * from teams t\nwhere t.status = 'active'\nand id NOT IN (select team_id from team_features where feature_id = 9)\n;\n\n\nselect * from playbook_layouts where playbook_id = 1725;\nSELECT * FROM activities WHERE uuid_to_bin('65cc283c-4849-49e6-927f-4c281c8fea19') = uuid; # 34297473\nselect * from teams where id = 318;\nselect * from crm_configurations where team_id = 318;\nselect * from playbooks where team_id = 318;\nSELECT * FROM crm_layouts where crm_configuration_id = 381;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1259;\nSELECT * FROM crm_fields WHERE id IN (192938,192936,192939);\n\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1266;\nSELECT * FROM crm_fields WHERE id IN (192980,192991,192997,192998,193064,193067);\n\nSELECT * FROM activities WHERE uuid_to_bin('a902289b-285c-48eb-9cc2-6ad6c5d938f5') = uuid; # 34297533\n\n\n\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 927;\nSELECT * FROM crm_fields WHERE id IN (131668,131669,131670,131671,131676,131797);\n\nSELECT * FROM teams WHERE name LIKE '%Peripass%'; # 351, 281, 12124\nselect * from crm_layouts where crm_configuration_id = 281;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 927;\nselect * from crm_fields where crm_configuration_id = 281 and id in (131668,131669,131670,131671,131676,131797);\nselect * from opportunities where crm_configuration_id = 281;\n\nSELECT * FROM activities WHERE id IN (34211315, 34130075);\nSELECT * FROM crm_field_data WHERE object_id IN (34211315, 34130075);\n\nselect cf.crm_configuration_id, cle.crm_layout_id, cle.id, cf.id from crm_field_data cfd\njoin crm_layout_entities cle on cle.id = cfd.crm_layout_entity_id\njoin crm_fields cf on cle.crm_field_id = cf.id\nwhere cf.deleted_at IS NOT NULL\nGROUP BY cle.id, cf.id;\n\nselect * from crm_layouts where id IN (355);\nselect u.email, t.crm_id, t.* from teams t\njoin users u on u.id = t.owner_id\nwhere crm_id IN (97);\n\nSELECT * FROM crm_fields WHERE id = 96492;\n\nselect * from permissions;\nselect * from permission_role where permission_id = 247;\nselect * from roles;\n\nselect * from migrations;\n# *****************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('291e3c21-11cc-4728-aee7-6e4bedf86d72') = uuid; # 34262174\nSELECT * FROM crm_configurations WHERE id = 301;\nSELECT * FROM teams WHERE id = 343;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 343\nand sa.provider = 'hubspot';\n\nselect * from participants where activity_id = 34262174;\n\nselect * from contacts where crm_configuration_id = 301 and id = 6976326;\nselect * from accounts where crm_configuration_id = 301 and id IN (4647626, 4815829); # 30761335403\n\nselect * from activity_summary_logs where activity_id = 34262174;\n\nselect * from users where status = 1 AND timezone = 'EST';\n\n# ****************************************************************************\nSELECT * FROM users WHERE id = 13869;\nSELECT * FROM crm_configurations WHERE id = 320;\nSELECT * FROM teams WHERE id = 401;\n\nSELECT * FROM activities WHERE uuid_to_bin('2228c16f-10be-48d5-90d4-67385219dc01') = uuid; # 29670601\n\nSELECT * FROM accounts WHERE id = 7761483;\nSELECT * FROM opportunities WHERE id = 6051814;\n\nSELECT * FROM teams WHERE name LIKE '%Seedlegals%';\n\n;select * from opportunities where updated_at > '2025-10-11' AND crm_provider_id = '34713761166';\n\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 177;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 577;\nSELECT * FROM crm_fields WHERE id IN (68458,68459,68480,68497,68524,68530,68554,68618,68662,68781,68810,68898,68981,69049,97467);\n\nSELECT t.id, crm.id, t.name, crm.sync_objects, crm.provider, crm.last_synced_at FROM crm_configurations crm join teams t on t.crm_id = crm.id\nwhere t.status = 'active' AND crm.provider = 'hubspot' AND crm.last_synced_at < '2025-10-22 00:00:00';\n\nSELECT * FROM activities WHERE uuid_to_bin('fa09449f-cba9-496a-b8f3-865cd3c72351') = uuid;\nSELECT * FROM crm_configurations where id = 184;\nSELECT * FROM teams WHERE id = 246;\nSELECT * FROM social_accounts WHERE sociable_id = 9259 and provider = 'hubspot';\n\nSELECT * FROM users WHERE email LIKE '%rhian.old@bud.co.uk%'; # 17700\nSELECT * FROM teams WHERE id = 551;\n\nSELECT * FROM crm_configurations WHERE id = 471;\nSELECT * FROM activities WHERE crm_configuration_id = 471 and crm_provider_id IS NOT NULL;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 471;\nSELECT * FROM crm_fields WHERE id = 307260;\nSELECT * FROM crm_field_values WHERE crm_field_id = 307260;\n\nselect * from crm_layouts where crm_configuration_id = 471;\n\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1547;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1548;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 551 and sa.provider = 'hubspot';\n\nSELECT * FROM teams WHERE name LIKE '%$PCS%';\n\n# ********************************************************************************************************\nselect * from crm_configurations crm\njoin teams t on t.crm_id = crm.id\nwhere t.status = 'active'\nand crm.provider = 'hubspot';\n\n# $slug = 'HUBSPOT_WEBHOOK_SYNC';\n# $team = Jiminny\\Models\\Team::find(2);\n# $feature = Feature::query()->where('slug', $slug)->first();\n# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);\n\n# hubspot_webhook_metrics\n\nselect * from crm_configurations where id = 331; # 416\nSELECT * FROM teams WHERE id = 416;\nSELECT * FROM opportunities WHERE team_id = 190;\n\nSELECT * FROM teams WHERE name LIKE '%Lead Forensics%';\nSELECT sa.id,\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 190 and sa.provider = 'hubspot';\n\n\n\nSELECT * FROM teams WHERE name LIKE '%Rapaport%'; # 431, 337\nSELECT * FROM teams where id = 431;\nSELECT * FROM crm_configurations where team_id = 431;\nSELECT * FROM activity_providers where team_id = 431;\nSELECT * FROM activities where crm_configuration_id = 337 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\nSELECT sa.id,\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 431 and sa.provider = 'salesforce';\n\nSELECT * FROM teams WHERE name LIKE '%BiP%'; # 401, 320\nSELECT * FROM teams where id = 401;\nSELECT * FROM crm_configurations where team_id = 401;\nSELECT * FROM activity_providers where team_id = 401;\nSELECT * FROM activities where crm_configuration_id = 320 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\nSELECT sa.id,\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 401 and sa.provider = 'salesforce';\n\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 307; # 379 - Story Terrace Inc , portalId: 3921157\nSELECT * FROM contacts WHERE team_id = 379 and updated_at > '2026-01-31 11:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 379 and updated_at > '2026-02-01 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 379 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 379 and sa.provider = 'hubspot';\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 485; # 563 - LATUS Group (ad94d501-5d09-44fd-878f-ca3a9f8865c3) , portalId: 3904501\nSELECT * FROM opportunities WHERE team_id = 563 and updated_at > '2026-02-02 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 563 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 338; # 432 - Formalize , portalId: 9214205\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 432 and sa.provider = 'hubspot';\nSELECT * FROM opportunities WHERE team_id = 432 and updated_at > '2026-02-02 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 432 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 436; # 519 - Moxso , portalId: 25531989\nSELECT * FROM opportunities WHERE team_id = 519 and updated_at > '2026-02-02 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 519 and updated_at > '2026-02-04 11:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 96; # 119 - Nourish Care , portalId: 26617984\nSELECT * FROM opportunities WHERE team_id = 119 and updated_at > '2026-02-02 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 119 and updated_at > '2026-02-04 11:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 331; # 416 - The National College , portalId: 7213852\nSELECT * FROM opportunities WHERE team_id = 416 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 416 and updated_at > '2026-02-04 11:00:00' order by updated_at desc;\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 308; # 380 - Foodles , portalId: 7723616\nSELECT * FROM opportunities WHERE team_id = 380 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 380 and updated_at > '2026-02-06 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 379; # 471 - imat-uve , portalId: 9177354\nSELECT * FROM opportunities WHERE team_id = 471 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 471 and updated_at > '2026-02-06 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 465; # 545 - Spotler , portalId: 144759271\nSELECT * FROM opportunities WHERE team_id = 545 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 545 and updated_at > '2026-02-06 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 455; # 537 - indevis , portalId: 25666868\nSELECT * FROM opportunities WHERE team_id = 537 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 537 and updated_at > '2026-02-06 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 200; # 265 - Jobadder , portalId: 6426676\nSELECT * FROM opportunities WHERE team_id = 265 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 265 and updated_at > '2026-02-06 10:30:00' order by updated_at desc;\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 335; # 429 - Eletive , portalId: 6110563\nSELECT * FROM opportunities WHERE team_id = 429 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 429 and updated_at > '2026-02-09 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 363; # 456 - Global Group , portalId: 8901981\nSELECT * FROM opportunities WHERE team_id = 456 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 456 and updated_at > '2026-02-09 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 297; # 369 - Unbiased , portalId: 9229005\nSELECT * FROM opportunities WHERE team_id = 369 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 369 and updated_at > '2026-02-09 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 353; # 449 - Fuuse , portalId: 25781745\nSELECT * FROM opportunities WHERE team_id = 449 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 449 and updated_at > '2026-02-09 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 487; # 566 - Nimbus , portalId: 39982590\nSELECT * FROM opportunities WHERE team_id = 566 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 566 and updated_at > '2026-02-09 10:30:00' order by updated_at desc;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 487;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1630;\nselect * from crm_fields where crm_configuration_id = 487 and\n(uuid_to_bin('4c6b2971-64d4-45b8-b377-427be758b5a5') = uuid or uuid_to_bin('59e368d8-65a0-4b77-b611-db37c99fbe68') = uuid);\nSELECT * FROM crm_field_values WHERE crm_field_id = 375177;\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 420; # 506 - voiio , portalId: 145629154\nSELECT * FROM opportunities WHERE team_id = 506 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 506 and updated_at > '2026-02-10 15:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 479; # 558 - Momice , portalId: 535962\nSELECT * FROM opportunities WHERE team_id = 558 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 558 and updated_at > '2026-02-10 15:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 59; # 80 - Storyclash GmbH , portalId: 4268479\nSELECT * FROM opportunities WHERE team_id = 80 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 80 and updated_at > '2026-02-10 15:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 175; # 203 - Team iAM , portalId: 5534732\nSELECT * FROM opportunities WHERE team_id = 203 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 203 and updated_at > '2026-02-10 15:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 368; # 460 - OneTouch Health , portalId: 5534732183355\nSELECT * FROM opportunities WHERE team_id = 460 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 460 and updated_at > '2026-02-10 15:00:00' order by updated_at desc;\n\n\n\nselect * from users where id = 29643;\nSELECT * FROM crm_field_values WHERE crm_field_id = 375177;\n# ********************************************************************\nSELECT * FROM teams WHERE name LIKE '%Buynomics%'; # 462, 482, 14910\nSELECT * FROM activities WHERE crm_configuration_id = 482\nand type NOT IN ('email-inbound', 'email-outbound')\n# and description like '%The call focused on understanding Welch%'\norder by id desc;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 462 and sa.provider = 'salesforce';\n\nselect * from contacts where crm_configuration_id = 482 and name = 'Cyndall Hill'; # 15504749\nselect * from contacts where id = 10891096; # 482\nSELECT * FROM activities WHERE crm_configuration_id = 482\nand type NOT IN ('email-inbound', 'email-outbound')\nand contact_id = 15504749\norder by id desc;\n\nselect * from activities where id = 36793003; # 96cc7bc1-8622-4d27-92f4-baf664fc1a56, 00UOf00000PDdOXMA1\nselect * from transcription where id = 7646782;\nselect * from ai_prompts where transcription_id = 7646782;\n\n# ********************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('7a8471a3-847e-4822-802b-ddf426bbc252') = uuid; # 37370018\nSELECT * FROM activity_summary_logs WHERE activity_id = 37370018;\nSELECT * FROM teams WHERE id = 555;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 555 and sa.provider = 'hubspot';\n\n# ********************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('7c17b8aa-09df-4f85-a0f7-51f47afd712d') = uuid; # 37395250\nSELECT * FROM activities WHERE uuid_to_bin('14d60388-260d-494b-aa0d-63fdb1c78026') = uuid; # 37395250\n\nSELECT a.* FROM activities a JOIN crm_configurations c on c.id = a.crm_configuration_id\nwhere a.type IN ('softphone', 'softphone-outbound') and c.provider = 'hubspot'\nand a.provider NOT IN ('hubspot')\n# and a.provider IN ('salesloft')\n# and c.id NOT IN (70)\n# and a.duration > 30\n# and actual_start_time > '2026-02-05 00:00:00'\norder by a.id desc;\n\nSELECT * FROM activities WHERE id = 37549787;\nSELECT * FROM crm_profiles WHERE user_id = 17613;\n\nSELECT * FROM crm_configurations WHERE id = 70;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 93 and sa.provider = 'hubspot';\n\nSELECT asf.activity_search_id, asf.id, asf.value\nFROM activity_search_filters asf\nWHERE asf.filter = 'group_id'\nAND asf.value IN (\n SELECT CONCAT(\n HEX(SUBSTR(uuid, 5, 4)), '-',\n HEX(SUBSTR(uuid, 3, 2)), '-',\n HEX(SUBSTR(uuid, 1, 2)), '-',\n HEX(SUBSTR(uuid, 9, 2)), '-',\n HEX(SUBSTR(uuid, 11))\n )\n FROM groups\n WHERE deleted_at IS NOT NULL\n);\n\nSELECT * FROM crm_configurations WHERE id = 373; # KPSBremen.de 465 # - no social account\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 465 and sa.provider = 'hubspot';\n\nselect * from crm_configurations where id = 494;\n\nSELECT * FROM teams WHERE name LIKE '%splose%'; # 572, 495, 18708\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 572 and sa.provider = 'pipedrive';\n\nselect * from opportunities where team_id = 572\n# and name like '%Onebright%'\n# and is_closed = 1 and is_won = 0\n order by id desc;\n\n\nselect * from users where deleted_at is null and status = 2;\n\nselect * from contacts where id = 17900517;\nselect * from accounts where id = 10109838;\nselect * from opportunities where id = 6955880;\n\nselect * from opportunity_contacts where opportunity_id = 6955880;\nselect * from opportunity_contacts where contact_id = 17900517;\n\nselect * from contact_roles cr join crm_configurations crm on cr.crm_configuration_id = crm.id\nwhere crm.provider != 'salesforce';\n\nSELECT * FROM activities WHERE uuid_to_bin('adcb8331-5988-4353-834e-383a355abba2') = uuid; # 38056424, crm 104659682404\nselect * from teams where id = 456;\nSELECT * FROM crm_configurations WHERE id = 363;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 456 and sa.provider = 'hubspot';\n\nselect * from crm_layouts where crm_configuration_id = 363;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id IN (1203, 1204, 1635);\nSELECT * FROM crm_fields WHERE id IN (181536, 181538, 213455);\n\nSELECT * FROM teams WHERE name LIKE '%Electric%'; # 342, 272, 12767\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 342 and sa.provider = 'pipedrive';\nSELECT * FROM opportunities WHERE crm_configuration_id = 272 and name like 'NORTHUMBRIA POL%'; # and updated_at > '2025-07-01 00:00:00';\nSELECT * FROM opportunities WHERE crm_configuration_id = 272 order by remotely_created_at asc; # and updated_at > '2025-07-01 00:00:00';\nSELECT * FROM opportunities WHERE crm_configuration_id = 272 and updated_at > '2026-01-01 00:00:00';\nSELECT * FROM crm_fields WHERE crm_configuration_id = 272 and object_type = 'opportunity';\nSELECT * FROM crm_field_values WHERE crm_field_id = 127164;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 342 and sa.provider = 'pipedrive';\n\nSELECT * FROM teams WHERE id = 472;\nSELECT * FROM crm_configurations WHERE id = 380;\nselect * from activities where id = 38285673; # 38285673\nSELECT * FROM users WHERE id = 16942;\nSELECT * FROM groups WHERE id = 1964;\nSELECT * FROM playbooks WHERE id = 2033;\n\nselect * from teams where created_at > '2026-03-09';\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 499; # 1065\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1678;\n\nSELECT * FROM teams WHERE id = 575;\nselect * from opportunities where team_id = 575;\n\nSELECT * FROM activities WHERE uuid_to_bin('96b1261f-2357-49f9-ab38-23ce12008ea0') = uuid;\n\nselect * from contacts c\nwhere c.crm_configuration_id = 370 order by c.updated_at desc;\n\nSELECT * FROM participants where activity_id = 38833541;\nSELECT * FROM participants where activity_id = 39216301;\nSELECT * FROM activity_summary_logs where activity_id = 39216301;\nSELECT * FROM activities WHERE uuid_to_bin('c7d99fbe-1fb1-41f2-8f4d-52e2bf70e1e9') = uuid; # 38833541, crm 478116564181\nSELECT * FROM activities WHERE uuid_to_bin('2e6ff4d3-9faa-447a-a8c1-9acde4d885ae') = uuid; # 39216301, crm 480171536586\nselect * from crm_profiles where crm_configuration_id = 319 and crm_provider_id = 525785080;\nselect * from opportunities where crm_configuration_id = 319 and crm_provider_id = 410150124747;\nselect * from accounts where crm_configuration_id = 319 and crm_provider_id = 47150650569;\nselect * from contacts where crm_configuration_id = 319 and crm_provider_id IN ('665587441856', '742723347700');\n# owner 13236 525785080\n# contact 1 16779180 665587441856 - activity - Alex Howes alex@supportroom.com created 2026-01-26\n# contact 2 19247563 742723347700 - ash@supportroom.com 2026-03-24\n# company 4176133 47150650569\n# deal 7100953 410150124747\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 400 and sa.provider = 'hubspot';\n\nselect * from features;\nselect * from team_features where feature_id = 40;\n\nselect * from teams where id = 556; # owner: 18101, crm: 477\nselect * from crm_configurations where id = 477;\nSELECT * FROM users WHERE id = 18101;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 556 and sa.provider = 'integration-app';\n\nselect * from opportunities where id = 7594349;\nselect * from opportunity_stages where opportunity_id = 7594349 order by created_at desc;\nselect * from business_processes where id = 6024;\nselect * from business_process_stages where stage_id = 16352;\nselect * from business_process_stages where business_process_id = 6024;\nselect * from stages where team_id = 459;\nselect * from teams where id = 459;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 459 and sa.provider = 'hubspot';\n\nSELECT os.stage_id, s.crm_provider_id, s.name, COUNT(*) as cnt\nFROM opportunity_stages os\nJOIN stages s ON s.id = os.stage_id\nWHERE os.opportunity_id = 7594349\nGROUP BY os.stage_id, s.crm_provider_id, s.name\nORDER BY cnt DESC;\n\nSELECT s.id, s.crm_provider_id, s.name, s.team_id, s.crm_configuration_id\nFROM stages s\nJOIN business_process_stages bps ON bps.stage_id = s.id\nWHERE bps.business_process_id = 6024\nAND s.crm_provider_id = 'contractsent';\n\nselect * from stages where id IN (16352,20612,18281,7344,16378,16309,5036,15223,14535,6293,12098,11607)\n\nSELECT * FROM teams WHERE name LIKE '%Pulsar Group%'; # 472, 380, 15138, raza.gilani@vuelio.com\nselect * from playbooks where team_id = 472; # event 226147\nSELECT * FROM playbook_categories WHERE playbook_id = 2288;\nSELECT * FROM crm_fields WHERE id = 226147;\nSELECT * FROM crm_field_values WHERE crm_field_id = 226147;\n\nSELECT * FROM crm_configurations WHERE id = 380;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 472 and sa.provider = 'salesforce';","depth":4,"value":"SELECT * FROM team_features where team_id = 1;\n\nSELECT * FROM teams WHERE name LIKE '%Vixio%'; # 340,270,11922\nSELECT * FROM users WHERE team_id = 340; # 12015\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 340\nand sa.provider = 'salesforce';\n# and sa.provider = 'salesloft';\n\nselect * from crm_fields where crm_configuration_id = 270 and object_type = 'event';\n# 125558 - Event Type - Event_Type__c\n# 125552 - Event Status - Event_Status__c\n\nSELECT * FROM sidekick_settings WHERE team_id = 340;\n\nSELECT * FROM crm_field_values WHERE crm_field_id in (125552);\n\nselect * from activities where crm_configuration_id = 270\nand type = 'conference' and crm_provider_id IS NOT NULL\nand actual_start_time > '2024-09-16 09:00:00' order by scheduled_start_time;\n\nSELECT * FROM activities WHERE id = 20871677;\nSELECT * FROM crm_field_data WHERE activity_id = 20871677;\n\nselect * from crm_layouts where crm_configuration_id = 270;\nselect * from crm_layout_entities where crm_layout_id in (886,887);\n\nSELECT * FROM crm_configurations WHERE id = 270;\n\nselect * from playbooks where team_id = 340; # 1514\nselect * from groups where team_id = 340;\nSELECT * FROM crm_fields WHERE id IN (125393, 125401);\n\nselect g.name as 'team name', p.name as 'playbook name', f.label as 'activity type field' from groups g\njoin playbooks p on g.playbook_id = p.id\njoin crm_fields f on p.activity_field_id = f.id\nwhere g.team_id = 340;\n\nSELECT * FROM activities WHERE uuid_to_bin('0c180357-67d2-419e-a8c3-b832a3490770') = uuid; # 20448716\nselect * from crm_field_data where object_id = 20448716;\n\nselect * from activities where crm_configuration_id = 270 and provider = 'salesloft' order by id desc;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%CybSafe%'; # 343,273,12008\nselect * from opportunities where team_id = 343;\nselect * from opportunities where team_id = 343 and crm_provider_id = '18099102526';\nselect * from opportunities where team_id = 343 and account_id = 945217482;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 343\nand sa.provider = 'hubspot';\n\nselect * from accounts where team_id = 343 order by name asc;\n\nselect * from stages where crm_configuration_id = 273 and type = 'opportunity';\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Voyado%'; # 353,283,12143\nSELECT * FROM activities WHERE crm_configuration_id = 283 and account_id = 3777844 order by id desc;\nSELECT * FROM accounts WHERE team_id = 353 AND name LIKE '%Salesloft%';\nSELECT * FROM activities WHERE id = 20717903;\n\nselect * from participants where activity_id IN (20929172,20928605,20928468,20926272,20926271,20926270,20926269,20916499,20916454,20916436,20916435,20900015,20900014,20900013,20897312,20897243,20897241,20897237,20897232,20897229,20893648,20893231,20893230,20893229,20893228,20889784,20885039,20885038,20885037,20885036,20885035,20882728,20882708,20882703,20882702,20869828,20869811,20869806,20869801,20869799,20869798,20869796,20869795,20869794,20869761,20869760,20869759,20868688,20868687,20850340,20847195,20841710,20833967,20827021,20825307,20825305,20825297,20824615,20824400,20823927,20821760,20795588,20794233,20794057,20793710,20785811,20781789,20781394,20781307,20762651,20758453,20758282,20757323,20756643,20756636,20756629,20756627,20756606,20756605,20756604,20756603,20756602,20756600,20756599,20756598,20756595,20756594,20756589,20756587,20756577,20756573,20748918,20748386,20748385,20748384,20748383,20748382,20748381,20748380,20748379,20748377,20748375,20748373,20743301,20717905,20717904,20717903,20717901,20717899);\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 353\nand sa.provider = 'salesforce';\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%modern world business solutions%'; # 345,275,12016, l.atkinson@mwbsolutions.co.uk\nSELECT * FROM activities WHERE uuid_to_bin('3921d399-3fef-4609-a291-b0097a166d43') = uuid;\n# id: 20940638, user: 12022, contact: 5305871\nSELECT * FROM activity_summary_logs WHERE activity_id = 20940638;\nselect * from contacts where team_id = 345 and crm_provider_id = '30891432415' order by name asc; # 5305871\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 345\nand sa.provider = 'hubspot';\n\nselect * from users where team_id = 345 and id = 12022;\nSELECT * FROM crm_profiles WHERE user_id = 12022;\nSELECT * FROM participants WHERE activity_id = 20940638;\nSELECT * FROM users u\nJOIN crm_profiles cp ON u.id = cp.user_id\nWHERE u.team_id = 345;\n\nselect * from contacts where team_id = 345 and crm_provider_id = '30880813535' order by name desc; # 5305871\n\nselect * from team_features where team_id = 345;\nSELECT * FROM activities WHERE uuid_to_bin('11701e2d-2f82-4dab-a616-1db4fad238df') = uuid; # 21115197\nSELECT * FROM participants WHERE activity_id = 20897406;\n\n\n\nSELECT * FROM activities WHERE uuid_to_bin('63ba55cd-1abc-447d-83da-0137000005b7') = uuid; # 20953912\nSELECT * FROM activities WHERE crm_configuration_id = 275 and provider = 'ringcentral' and title like '%1252629100%';\n\n\nSELECT * FROM activities WHERE id = 20946641;\nSELECT * FROM crm_profiles WHERE user_id = 10211;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Lunio%'; # 120,97,10984, triger@lunio.ai\nSELECT * FROM opportunities WHERE crm_configuration_id = 97 and crm_provider_id = '006N1000006c5PpIAI';\nselect * from stages where crm_configuration_id = 97 and type = 'opportunity';\nselect * from opportunities where team_id = 120;\n\n\nselect * from crm_configurations crm join teams t on crm.id = t.crm_id\nwhere 1=1\nAND t.current_billing_plan IS NOT NULL\nAND crm.auto_sync_activity = 0\nand crm.provider = 'hubspot';\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Exclaimer%'; # 270,205,10053,james.lewendon@exclaimer.com\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 270\nand sa.provider = 'salesforce';\nSELECT * FROM activities WHERE uuid_to_bin('b54df794-2a9a-4957-8d80-09a600ead5f8') = uuid; # 21637956\nSELECT * FROM crm_profiles WHERE user_id = 11446;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Cygnetise%'; # 372,300,12554, alex.chikly@cygnetise.com\nselect * from playbooks where team_id = 372;\nselect * from crm_fields where crm_configuration_id = 300 and object_type = 'event'; # 141340\nSELECT * FROM crm_field_values WHERE crm_field_id = 141340;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 372\nand sa.provider = 'salesforce';\n\nselect * from crm_profiles where crm_configuration_id = 300;\nSELECT * FROM crm_configurations WHERE team_id = 372;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Planday%'; # 291,242,11501,mfa@planday.com\nSELECT * FROM opportunities WHERE team_id = 291 and crm_provider_id = '006bG000005DO86QAG'; # 3207756\nselect * from crm_field_data where object_id = 3207756;\nSELECT * FROM crm_fields WHERE id = 111834;\n\nselect f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value\nFROM crm_fields f\nJOIN crm_field_data fd ON f.id = fd.crm_field_id\nWHERE f.crm_configuration_id = 242\nAND f.object_type = 'opportunity'\nAND fd.object_id IN (3207756)\nORDER BY fd.object_id, fd.updated_at;\n\nSELECT * FROM crm_configurations WHERE auto_connect = 1;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Tour%'; # 187,209,8150,salesforce-admin@tourlane.com\nselect * from group_deal_risk_types drgt join groups g on drgt.group_id = g.id\nwhere g.team_id = 187;\n\nselect * from `groups` where team_id = 187;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 187\nand sa.provider = 'salesforce';\n\n# Destination - 98870 - Destination__c\n# Stage - 79014 - StageName\n# Land Arrangement - 98856 - Land_Arrangement__c\n# Flight - 98848 - Flight__c\n# Last activity date - 98812 - LastActivityDate\n# Last modified date - 98809 - LastModifiedDate\n# Last inbound mail timestamp - 99151 - Last_Inbound_Mail_Timestamp__c\n# next call - 98864 - Next_Call__c\n\nselect * from crm_fields where crm_configuration_id = 209 and object_type = 'opportunity';\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 209;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 682;\n\nselect * from opportunities where team_id = 187 and name LIKE'%Muriel Sal%';\nselect * from opportunities where team_id = 187 and user_id = 9951 and is_closed = 0;\nselect * from activities where opportunity_id = 3538248;\n\nSELECT * FROM crm_profiles WHERE user_id = 8150;\n\nselect * from deal_risks where opportunity_id = 3538248;\n\nselect * from teams where crm_id IS NULL;\n\nSELECT opp.id AS opportunity_id,\n u.group_id AS group_id,\n MAX(\n CASE\n WHEN a.type IN (\"sms-inbound\", \"sms-outbound\") THEN a.created_at\n ELSE a.actual_end_time\n END) as last_date\nFROM opportunities opp\nleft join activities a on a.opportunity_id = opp.id\ninner join users u on opp.user_id = u.id\nwhere opp.user_id IN (9951)\n\nAND opp.is_closed = 0\nand a.status IN ('completed', 'received', 'delivered') OR a.status IS NULL\ngroup by opp.id;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Cybsafe%'; # 343,301,12008,polly.morphew@cybsafe.com\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 343\nand sa.provider = 'hubspot';\n\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 301;\nSELECT * FROM contacts WHERE id = 6612363;\nSELECT * FROM accounts WHERE id = 4235676;\nSELECT * FROM opportunities WHERE crm_configuration_id = 301 and crm_provider_id = 32983784868;\nselect * from opportunity_stages where opportunity_id = 4503759;\n# SELECT * FROM opportunities WHERE id = 4569937;\n\nselect * from activities where crm_configuration_id = 301;\nSELECT * FROM activities WHERE uuid_to_bin('d3b2b28b-c3d0-4c2d-8ed0-eef42855278a') = uuid; # 26330370\nSELECT * FROM participants WHERE activity_id = 26330370;\n\nSELECT * FROM teams WHERE id = 375;\nselect * from playbooks where team_id = 375;\n\nselect * from stages where crm_configuration_id = 301 and type = 'opportunity';\n\nselect * from teams;\nselect * from contact_roles;\n\nSELECT * FROM opportunities WHERE team_id = 343 and user_id = 12871 and close_date >= '2024-11-01';\n\nselect * from users u join crm_profiles cp on cp.user_id = u.id where u.team_id = 343;\n\nSELECT * FROM crm_field_data WHERE object_id = 3771706;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 343\nand sa.provider = 'hubspot';\n\nSELECT * FROM crm_fields WHERE crm_configuration_id = 301 and object_type = 'opportunity'\nand crm_provider_id LIKE \"%traffic_light%\";\nSELECT * FROM crm_field_values WHERE crm_field_id IN (144020,144048,144111,144113,144126,144481,144508,144531);\n\nSELECT fd.* FROM opportunities o\nJOIN crm_field_data fd ON o.id = fd.object_id\nWHERE o.team_id = 343\n# and o.user_id IS NOT NULL\nand fd.crm_field_id IN (144020,144048,144111,144113,144126,144481,144508,144531)\nand fd.value != ''\norder by value desc\n# group by o.id\n;\n\nSELECT * FROM opportunities WHERE id = 3769843;\n\nSELECT * FROM teams WHERE name LIKE '%Tour%'; # 187,209,8150, salesforce-admin@tourlane.com\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 209;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 682;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Funding Circle%'; # 220,177,8603,aswini.mishra@fundingcircle.com\nSELECT * FROM activities WHERE uuid_to_bin('7a40e99b-3b37-4bb1-b983-325b81801c01') = uuid; # 23139839\n\n\nSELECT * FROM opportunities WHERE id = 3855992;\n\nSELECT * FROM users WHERE name LIKE '%Angus Pollard%'; # 8988\n\nSELECT * FROM teams WHERE name LIKE '%Story Terrace%'; # 379, 307, 12894\nSELECT * FROM crm_fields WHERE crm_configuration_id = 307 and object_type != 'opportunity';\n\nselect * from contacts where team_id = 379 and name like '%bebro%'; # 5874411, crm: 77229348507\nSELECT * FROM crm_field_data WHERE object_id = 5874411;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 379\nand sa.provider = 'hubspot';\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%mentio%'; # 117, 94, 6371, nikhil.kumar@mention-me.com\nSELECT * FROM activities WHERE uuid_to_bin('82939311-1af0-4506-8546-21e8d1fdf2c1') = uuid;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Tourlane%'; # 187, 209, 8150, salesforce-admin@tourlane.com\nSELECT * FROM opportunities WHERE team_id = 187 and crm_provider_id = '006Se000008xfvNIAQ'; # 3537793\nselect * from generic_ai_prompts where subject_id = 3537793;\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Lunio%'; # 120, 97, 10984, triger@lunio.ai\nSELECT * FROM crm_configurations WHERE id = 97;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 97;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 355;\nSELECT * FROM crm_fields WHERE id = 32682;\n\nselect cfd.value, o.* from opportunities o\njoin crm_field_data cfd on o.id = cfd.object_id and cfd.crm_field_id = 32682\nwhere team_id = 120\nand cfd.value != ''\n;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 120\nand sa.provider = 'salesforce';\n\nselect * from opportunities where team_id = 120 and crm_provider_id = '006N1000007X8MAIA0';\nSELECT * FROM crm_field_data WHERE object_id = 2313439;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE id = 410;\nSELECT * FROM teams WHERE name LIKE '%Local Business Oxford%';\nselect * from scorecards where team_id = 410;\nselect * from scorecard_rules;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Funding%'; # 220, 177, 8603, aswini.mishra@fundingcircle.com\nselect * from activities a\njoin opportunities o on a.opportunity_id = o.id\njoin users u on o.user_id = u.id\nwhere a.crm_configuration_id = 177 and a.type LIKE '%email-out%'\n# and a.actual_end_time > '2024-12-16 00:00:00'\n# and o.remotely_created_at > '2024-12-01 00:00:00'\n# and u.group_id = 1014\nand u.id = 9021\norder by a.id desc;\nSELECT * FROM opportunities WHERE id in (3981384,4017346);\nSELECT * FROM users WHERE team_id = 220 and id IN (8775, 11435);\n\nselect * from users where id = 9021;\nselect * from inboxes where user_id = 9021;\n\nselect * from inbox_emails where inbox_id = 1349 and email_date > '2024-12-18 00:00:00';\n\nselect * from email_messages where team_id = 220\nand orig_date > '2024-12-16 00:00:00' and orig_date < '2024-12-19 00:00:00'\nand subject LIKE '%Personal%'\n# and 'from' = 'credit@fundingcircle.com'\n;\n\nselect * from activities a\njoin opportunities o on a.opportunity_id = o.id\nwhere a.user_id = 9021 and a.type LIKE '%email-out%'\nand a.actual_end_time > '2024-12-18 00:00:00'\nand o.user_id IS NOT NULL\nand o.remotely_created_at > '2024-12-01 00:00:00'\norder by a.id desc;\n\nSELECT * FROM opportunities WHERE team_id = 220 and name LIKE '%Right Car move Limited%' and id = 3966852;\nselect * from activities where crm_configuration_id = 177 and type LIKE '%email%' and opportunity_id = 3966852 order by id desc;\n\nselect * from team_settings where name IN ('useCloseDate');\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Hurree%'; # 104, 81, 6175, jfarrell@hurree.co\nSELECT * FROM opportunities WHERE team_id = 104 and name = 'PropOp';\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 104\nand sa.provider = 'hubspot';\n\nselect * from crm_configurations where last_synced_at > '2025-01-19 01:00:00'\nselect * from teams where crm_id IS NULL;\n\nselect t.name as 'team', u.name as 'owner', u.email, u.phone\nfrom teams t\njoin activity_providers ap on t.id = ap.team_id\njoin users u on t.owner_id = u.id\nwhere 1=1\n and t.status = 'active'\n and ap.is_enabled = 1\n# and u.status = 1\n and ap.provider = 'ms-teams';\n\nselect * from crm_configurations where provider = 'bullhorn'; # 344\nSELECT * FROM teams WHERE id = 442; # 14293\nselect * from users where team_id = 442;\nselect * from social_accounts sa where sa.sociable_id = 14293;\nselect * from invitations where team_id = 442;\n\n# ********************************************************************************************************\nSELECT * FROM users WHERE email LIKE '%nea.liikamaa@eletive.com%'; # 14022\nSELECT * FROM teams WHERE id = 429;\nselect * from opportunities where team_id = 429 and crm_provider_id IN (16157415775, 22246219645);\nselect * from activities where opportunity_id in (4340436,4353519);\n\nselect * from transcription where activity_id IN (25630961,25381771);\nselect * from generic_ai_prompts where subject_id IN (4353519);\n\nSELECT\n a.id as activity_id,\n a.opportunity_id,\n a.type as activity_type,\n a.language,\n CONCAT(a.title, a.description) AS mail_content,\n e.from AS mail_from,\n e.to AS mail_to,\n e.subject AS mail_subject,\n e.body AS mail_body,\n p.type as prompt_type,\n p.status as prompt_status,\n p.content AS prompt_content,\n a.actual_start_time as created_at\nFROM activities a\n LEFT JOIN ai_prompts p ON a.transcription_id = p.transcription_id AND p.deleted_at IS NULL\n LEFT JOIN email_messages e ON a.id = e.activity_id\nWHERE a.actual_start_time > '2024-01-01 00:00:00'\n AND a.opportunity_id IN (4353519)\n AND a.status IN ('completed', 'received', 'delivered')\n AND a.deleted_at IS NULL\n AND a.type NOT IN ('sms-inbound', 'sms-outbound')\nORDER BY a.opportunity_id ASC, a.id ASC;\n\nSELECT * FROM users WHERE name LIKE '%George Fierstone%'; # 14293\nSELECT * FROM teams WHERE id = 442;\nSELECT * FROM crm_configurations WHERE id = 344;\nselect * from team_features where team_id = 442;\nselect * from groups where team_id = 442;\nselect * from playbooks where team_id = 442;\nselect * from playbook_categories where playbook_id = 1729;\nselect * from crm_fields where crm_configuration_id = 344 and id = 172024;\nSELECT * FROM crm_field_values WHERE crm_field_id = 172024;\nselect * from crm_layouts where crm_configuration_id = 344;\nselect * from playbook_layouts where playbook_id = 1729;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Learning%'; # 260, 221, 9444\n\nselect s.*\n# , s.sent_at, u.name, a.*\nfrom activity_summary_logs s\ninner join activities a on a.id = s.activity_id\ninner join users u on u.id = a.user_id\nwhere a.crm_configuration_id = 356\nand s.sent_at > date_sub(now(), interval 60 day)\norder by a.actual_end_time desc;\n\nselect * from activities a\n# inner join activity_summary_logs s on s.activity_id = a.id\nwhere a.crm_configuration_id = 356 and a.actual_end_time > date_sub(now(), interval 60 day)\n# and a.crm_provider_id is not null\n# and provider <> 'ringcentral'\nand status = 'completed'\norder by a.actual_end_time desc;\n\nselect * from teams order by id desc; # 17328, 32, 17830, integration-account@jiminny.com\nSELECT * FROM users;\nSELECT * FROM users where team_id = 260 and status = 1; # 201 - 150 active\nSELECT * FROM teams WHERE id = 260;\nselect * from team_settings where team_id = 260;\nselect * from crm_configurations where team_id = 260;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 356;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1184;\n\nselect * from accounts where crm_configuration_id = 221 order by id desc; # 7000\nselect * from leads where crm_configuration_id = 221 order by id desc; # 0\nselect * from contacts where crm_configuration_id = 221 order by id desc; # 200 000\nselect * from opportunities where crm_configuration_id = 221 order by id desc; # 0\nselect * from crm_profiles where crm_configuration_id = 221 order by id desc; # 23\nselect * from crm_fields where crm_configuration_id = 221;\nselect * from crm_field_values where crm_field_id = 5302 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 221 order by id desc;\nselect * from stages where crm_configuration_id = 221 order by id desc;\n\nselect * from accounts where crm_configuration_id = 356 order by id desc; # 7000\nselect * from leads where crm_configuration_id = 356 order by id desc; # 0\nselect * from contacts where crm_configuration_id = 356 order by id desc; # 200 000\nselect * from opportunities where crm_configuration_id = 356 order by id desc; # 0\nselect * from crm_profiles where crm_configuration_id = 356 order by id desc; # 23\nselect * from crm_fields where crm_configuration_id = 356;\nselect * from crm_field_values where crm_field_id = 5302 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 356 order by id desc;\nselect * from stages where crm_configuration_id = 356 order by id desc;\n\nselect * from playbooks where team_id = 260 order by id desc; # 4 (2 deleted)\nselect * from groups where team_id = 260 order by id desc; # 27 groups, (2 deleted)\nselect * from playbook_layouts where playbook_id IN (1410,1409,1276,1254); # 4\nselect ce.* from calendars c\njoin users u on c.user_id = u.id\njoin calendar_events ce on c.id = ce.calendar_id\nwhere u.team_id = 260\nand (ce.start_time > '2025-02-21 00:00:00')\n;\n# calendar events 1207\n#\n\nselect * from opportunities where team_id = 260;\nSELECT * FROM crm_field_data WHERE object_id = 4696496;\n\nselect * from activities where crm_configuration_id = 356 and crm_provider_id IS NOT NULL;\nselect * from activities where crm_configuration_id IN (221) and provider NOT IN ('ms-teams', 'uploader', 'zoom-bot')\n# and type = 'conference' and status = 'scheduled' and activities.is_internal = 0\nand created_at > '2024-03-01 00:00:00'\norder by id desc; # 880 000, ringcentral, avaya\nSELECT * FROM participants WHERE activity_id = 26371744;\n\n# all activities 942 000 +\n# conference 7385 - scheduled 984 - external 343\n\nselect * from activities where id = 26321812;\nselect * from participants where activity_id = 26321812;\nselect * from participants where activity_id in (26414510,26414514,26414516,26414604,26414653,26414655);\nselect * from leads where id in (720428,689175,731546,645866,621037);\n\nselect * from users where id = 13841;\nselect * from opportunities where user_id = 9541;\nselect * from stages where id = 15900;\n\nselect * from accounts where\n# id IN (4160055,5053725,4965303,4896434)\nid in (4584518,3249934,3218025,3891133,3399450,4172999,4485161,3101785,4587203,3070816,2870343,2870341,3563940,4550846,3424464,3249963,2870342)\n;\n\nselect * from activities where id = 26654935;\nSELECT * FROM opportunities WHERE id = 4803458;\n\nSELECT * FROM opportunities where team_id = 260 and user_id = 13841 AND stage_id = 15900;\nSELECT id, uuid, provider, type, lead_id, account_id, contact_id, opportunity_id, stage_id, status, recording_state, title, actual_start_time, actual_end_time\nFROM activities WHERE user_id = 13841 AND opportunity_id IN (4729783, 4731717, 4731726, 4732064, 4732849, 4803458, 4813213);\n\nSELECT DISTINCT\n o.id, o.stage_id, s.name, a.title,\n a.*\nFROM activities a\n# INNER JOIN tracks t ON a.id = t.activity_id\nINNER JOIN users u ON a.user_id = u.id\nINNER JOIN teams team ON u.team_id = team.id\nINNER JOIN groups g ON u.group_id = g.id\nINNER JOIN opportunities o ON a.opportunity_id = o.id\nINNER JOIN stages s ON o.stage_id = s.id\nWHERE\n a.crm_configuration_id = 356\n AND a.status IN ('completed', 'failed')\n AND a.recording_state != 'stopped'\n# and a.user_id = 13841\n AND u.uuid = uuid_to_bin('6f40e4b8-c340-4059-b4ac-1728e87ea99e')\n AND team.uuid = uuid_to_bin('a607fba7-452e-4683-b2af-00d6cb52c93c')\n AND g.uuid = uuid_to_bin('b5d69e40-24a0-4c16-810b-5fa462299f94')\n\n AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')\n# AND t.type IN ('audio', 'video')\n AND (\n (a.actual_start_time BETWEEN '2025-03-13 00:00:00' AND '2025-03-18 07:59:59')\n OR\n (\n a.actual_start_time IS NULL\n AND a.type IN ('sms-outbound', 'sms-inbound')\n AND a.created_at BETWEEN '2025-03-13 00:00:00' AND '2025-03-18 07:59:59'\n )\n )\n AND (\n a.is_private = 0\n OR (\n a.is_private = 1\n AND u.uuid = uuid_to_bin('6f40e4b8-c340-4059-b4ac-1728e87ea99e')\n )\n )\n AND (\n# s.id = 15900\n s.uuid = uuid_to_bin('04ca1c26-c666-4268-a129-419c0acffd73')\n OR s.uuid IS NULL -- Include records without opportunity stage\n )\n\nORDER BY a.actual_end_time DESC;\n# ********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Lead Forensics%'; # 190, 162, 8474, willsc@leadforensics.com\nSELECT * FROM users WHERE team_id = 190;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 190\nand sa.provider = 'hubspot';\n\nselect * from role_user where user_id = 8474;\n\nselect * from crm_configurations where provider = 'bullhorn';\n\nSELECT * FROM opportunities WHERE uuid_to_bin('94578249-65ec-4205-90f2-7d1a7d5ab64a') = uuid;\nSELECT * FROM users WHERE uuid_to_bin('26dbadeb-926f-4150-b11b-771b9d4c2f9a') = uuid;\n\nSELECT * FROM opportunities WHERE id = 4732493;\nselect * from activities where opportunity_id = 4732493;\n\n# ********************************************************************************************************\nSELECT * FROM teams WHERE id = 443; # 358, 14315, andrea.romano@correrenaturale.com\nSELECT * FROM opportunities WHERE team_id = 443;\n\nSELECT a.id, a.type, a.user_id, a.status, a.deleted_at, u.name, u.email, u.team_id as activity_team_id, u.status, u.deleted_at, t.name, t.status, s.team_id as stage_team_id\nFROM activities AS a\nJOIN stages AS s ON a.stage_id = s.id\nJOIN users AS u ON u.id = a.user_id\nJOIN teams AS t ON t.id = s.team_id\nWHERE u.team_id <> s.team_id and t.id > 135;\n\n\nSELECT\n crm_configuration_id,\n crm_provider_id,\n COUNT(*) as duplicate_count,\n GROUP_CONCAT(id) as stage_ids,\n GROUP_CONCAT(name) as stage_names\nFROM stages\nGROUP BY crm_configuration_id, crm_provider_id\nHAVING COUNT(*) > 1\nORDER BY duplicate_count DESC;\n\nselect * from stages where id IN (14898,14907);\n\nselect * from business_processes;\n\nSELECT *\nFROM crm_configurations\nWHERE team_id IN (\n SELECT team_id\n FROM crm_configurations\n GROUP BY team_id\n HAVING COUNT(*) > 1\n)\nORDER BY team_id;\n\nSELECT *\nFROM teams\nWHERE crm_id IN (\n SELECT crm_id\n FROM teams\n GROUP BY crm_id\n HAVING COUNT(*) > 1\n)\nORDER BY crm_id;\n\n# ***************************************************************************\nselect * from crm_configurations where provider = 'integration-app';\nSELECT * FROM teams WHERE id = 443; # Correre Naturale 358 14315 andrea.romano@correrenaturale.com\nselect * from activities where crm_configuration_id = 358 order by actual_end_time desc;\nselect id, uuid, actual_end_time, crm_provider_id, is_internal, playbook_category_id, type, user_id, lead_id, contact_id, account_id, opportunity_id, status, title from activities where crm_configuration_id = 358 order by actual_end_time desc;\nselect * from team_features where team_id = 358;\nselect * from activity_summary_logs;\n\nselect * from teams where id = 406;\n\n# ************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Sportfive%'; # 267, 202, 14637, srv.salesforce@sportfive.com\nselect * from activities where crm_configuration_id = 202 order by actual_end_time desc;\n\nSELECT * FROM users where id = 14637;\nSELECT * FROM teams where id = 267;\nSELECT * FROM groups where id = 1118;\n\nselect g.name, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled_start_time, a.scheduled_end_time, a.actual_start_time, a.actual_end_time from activities a\ninner join users u on u.id = a.user_id\ninner join groups g on g.id = u.group_id\nwhere a.crm_configuration_id = 202\nand a.is_internal = 0\nand (a.scheduled_start_time between '2025-03-19 00:00:00' and '2025-03-21 00:00:00')\nand a.type = 'conference'\nand a.status != 'completed'\nand a.external_id is not null\norder by a.scheduled_start_time desc;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 202\n AND status IN ('completed', 'failed')\n AND recording_state != 'stopped'\n AND type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')\n AND (is_private = 0 OR user_id = 14637)\n AND (\n (\n actual_start_time BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'\n ) OR (\n actual_start_time IS NULL\n AND type IN ('sms-outbound', 'sms-inbound')\n AND created_at BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'\n )\n )\n AND NOT EXISTS (\n SELECT 1\n FROM tracks\n WHERE\n tracks.activity_id = activities.id\n AND tracks.type IN ('audio', 'video')\n )\nORDER BY actual_end_time DESC;\n\nSELECT DISTINCT\n a.*\nFROM activities a\nINNER JOIN tracks t ON a.id = t.activity_id\nINNER JOIN users u ON a.user_id = u.id\nINNER JOIN teams team ON u.team_id = team.id\nWHERE\n a.crm_configuration_id = 202\n AND a.status IN ('completed', 'failed')\n AND a.recording_state != 'stopped'\n# and a.user_id = 14637\n AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')\n# AND t.type IN ('audio', 'video')\n AND (\n (a.actual_start_time BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59')\n OR\n (\n a.actual_start_time IS NULL\n AND a.type IN ('sms-outbound', 'sms-inbound')\n AND a.created_at BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'\n )\n )\n AND (\n a.is_private = 0\n OR (\n a.is_private = 1\n AND a.user_id = 14637\n )\n )\n\nORDER BY a.actual_end_time DESC\n;\n\nSELECT DISTINCT a.*\nFROM activities a\nINNER JOIN users u ON a.user_id = u.id\nINNER JOIN teams t ON u.team_id = t.id\n# INNER JOIN tracks tr ON a.id = tr.activity_id\n# INNER JOIN groups g ON u.group_id = g.id\nWHERE 1=1\n AND t.id = 267\n# AND t.uuid = uuid_to_bin('aed4927b-f1ea-499e-94c3-83762fd233e8')\n AND a.status IN ('completed', 'failed')\n AND a.recording_state != 'stopped'\n AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')\n# AND tr.type NOT IN ('audio', 'video')\n AND (\n a.is_private = 0\n OR a.user_id = 14637\n )\n AND (\n (a.actual_start_time BETWEEN '2025-03-19 00:00:00' AND '2025-03-21 23:59:59')\n OR (\n a.actual_start_time IS NULL\n AND a.type IN ('sms-outbound', 'sms-inbound')\n AND a.created_at BETWEEN '2025-03-19 00:00:00' AND '2025-03-21 23:59:59'\n )\n )\n# and NOT EXISTS (\n# SELECT 1\n# FROM tracks t\n# WHERE t.activity_id = a.id\n# AND t.type IN ('audio', 'video')\n# )\n\nORDER BY a.actual_end_time DESC;\n\nSELECT * FROM tracks WHERE activity_id = 26485995;\n\nselect a.is_private, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled_start_time, a.scheduled_end_time, a.actual_start_time, a.actual_end_time from activities a\ninner join users u on u.id = a.user_id\nwhere a.crm_configuration_id = 202\n# and a.is_internal = 0\nand (a.actual_start_time between '2025-03-19 00:00:00' and '2025-03-21 00:00:00')\nand a.type IN (\"softphone\",\"softphone-inbound\",\"conference\",\"sms-inbound\")\nand a.status IN ('completed', 'failed')\n# and a.external_id is not null\norder by a.actual_end_time desc;\n\nselect * from activities a where a.crm_configuration_id = 202\nand a.actual_start_time between '2025-03-20 00:00:00' and '2025-03-21 00:00:00'\n# AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')\n\nselect g.name, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled_start_time, a.scheduled_end_time, a.actual_start_time, a.actual_end_time from activities a\ninner join users u on u.id = a.user_id\ninner join groups g on g.id = u.group_id\nwhere a.crm_configuration_id = 202\nand a.is_internal = 0\nand (a.scheduled_start_time between '2025-03-19 00:00:00' and '2025-03-21 00:00:00')\nand a.type = 'conference'\nand a.status != 'completed'\nand a.external_id is not null\norder by a.scheduled_start_time desc;\n\nSELECT * FROM teams WHERE name LIKE '%Tourlane%';\nSELECT * FROM crm_fields WHERE crm_configuration_id = 209 and object_type = 'opportunity';\nSELECT * FROM crm_field_data WHERE crm_field_id = 98809;\n\nselect * from users where status = 1 AND timezone = 'MDT';\n\nselect * from opportunities where id = 3769814;\nselect * from deal_risks where opportunity_id = 3769814;\n\nselect cp.* from crm_profiles cp\njoin users u on cp.user_id = u.id\njoin crm_configurations crm on cp.crm_configuration_id = crm.id\nwhere crm.provider = 'hubspot' AND u.status = 1 AND log_notes != 'none';\n\nselect * from crm_fields where id = 154575;\n\nselect * from team_features where feature = 'SUPPORTS_SYNC_MISSING_CALL_DISPOSITIONS';\nSELECT * FROM teams WHERE id = 176; # crm 148\nselect * from activities where crm_configuration_id = 148 and provider = 'hubspot' order by id desc;\n\nselect * from activity_providers where provider = 'amazon-connect';\n\nselect * from crm_fields cf\njoin crm_configurations crm on crm.id = cf.crm_configuration_id\nwhere crm.provider = 'hubspot' and cf.object_type IN ('account', 'contact');\n\n# *********************************************************************************************\nSELECT * FROM users WHERE id IN (15415, 15418);\nSELECT * FROM groups WHERE id IN (1805,1806);\nSELECT * FROM playbooks WHERE id = 1860;\nSELECT * FROM playbook_categories WHERE id = 38634;\nSELECT * FROM crm_fields WHERE id = 189962;\n\nSELECT * FROM teams WHERE name = 'Pulsar Group'; # 472, 380, 15138 raza.gilani@vuelio.com\n\nSELECT * FROM crm_profiles WHERE user_id = 15415;\nSELECT * FROM social_accounts WHERE sociable_id = 15415 and provider = 'salesforce';\n\nselect * from sidekick_settings where team_id = 472;\n\nSELECT * FROM activities WHERE uuid_to_bin('452c58c7-b87c-4fdd-953e-d7af185e9588') = uuid; # 28617536, user: 15418\nSELECT * FROM activities WHERE uuid_to_bin('399114ee-d3a8-458c-bff5-5f654658db0a') = uuid; # 28344407, user: 15415\nSELECT * FROM activities WHERE uuid_to_bin('f0aa567f-0ab1-4bbb-96aa-37dcf184676b') = uuid; # 28580288, user: 15415\nSELECT * FROM activities WHERE uuid_to_bin('50c086b1-2770-4bca-b5ae-6bac22ec426b') = uuid; # 28566069, user: 15415\n\n# *********************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%TeamTailor%'; # 109, 218, 13969, salesforce-integrations@teamtailor.com\nselect * from crm_configurations where id = 218;\nSELECT * FROM activities WHERE uuid_to_bin('e39b5857-7fdb-4f5a-951a-8d3ca69bb1b0') = uuid; # 28338765\nSELECT * FROM users WHERE id IN (13232, 13230);\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 109\nand sa.provider = 'salesforce';\n\n0057R00000EPL5HQAX Inez Ekblad\n\n1091cb81-5ea1-4951-a0ed-f00b568f0140 Triman Kaur\n\nSELECT * FROM crm_profiles WHERE user_id IN (13232, 13230);\n\n############################################################################################\nSELECT * FROM activities WHERE uuid_to_bin('675eeaeb-5681-42db-90bc-54c07a604408') = uuid; # 28655939 00UVg00000FLvnSMAT\nSELECT * FROM crm_field_data WHERE activity_id = 28655939;\nSELECT * FROM crm_fields WHERE id IN (94491,94493,94498);\nSELECT * FROM users WHERE id = 13658;\nSELECT * FROM teams WHERE id = 109;\nSELECT * FROM crm_configurations WHERE id = 218;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 109\nand sa.provider = 'salesforce';\n\n# ********************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Strengthscope%'; # 481, 390, 15420, katy.holden@strengthscope.comk\nSELECT * FROM stages WHERE crm_configuration_id = 390;\nselect * from business_processes where team_id = 481 and crm_configuration_id = 390;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 481\nand sa.provider = 'salesforce';\n\n\nSELECT * FROM users WHERE id = 15780; # team 462\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 462\nand sa.provider = 'hubspot';\n\n\nselect * from teams where id = 495;\nSELECT * FROM users WHERE id = 15794;\nselect * from social_accounts where sociable_id = 15794;\n\n# ********************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Flight%'; # 427, 333, 13752\nSELECT * FROM accounts WHERE team_id = 427 and crm_provider_id = '668731000183444517';\n\n# ********************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Group GTI%'; # 495, 407, 15794\nSELECT * FROM activities WHERE crm_configuration_id = 407\nand status = 'completed' and type = 'conference'\norder by id desc;\n\nselect ru.*, pr.*, p.* from users u join role_user ru on ru.user_id = u.id\njoin permission_role pr on pr.role_id = ru.role_id\n join permissions p on p.id = pr.permission_id\nwhere team_id = 495 and p.name IN ('dial');\n\nselect * from permission_role;\n\nselect * from activities where crm_configuration_id = 407 and status = 'completed' order by id desc;\nSELECT * FROM activities WHERE id = 29512773;\nSELECT * FROM activities WHERE id IN (29042721,28991325,29002874);\n\nSELECT al.* from activity_summary_logs al join activities a on a.id = al.activity_id\nwhere a.crm_configuration_id = 407\n# and a.id IN (29042721,28991325,29002874);\n\nSELECT * FROM users WHERE id = 15794;\nSELECT * FROM users WHERE team_id = 495;\nSELECT * FROM social_accounts WHERE sociable_id = 15794;\nSELECT * FROM opportunities WHERE team_id = 495 and name like '%OC:%';\nSELECT * FROM contacts WHERE team_id = 495;\nSELECT * FROM leads WHERE team_id = 495;\nSELECT * FROM accounts WHERE team_id = 495;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 407;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 407;\nSELECT * FROM crm_configurations WHERE id = 407;\nSELECT * FROM opportunities WHERE team_id = 495 and close_date BETWEEN '2025-06-01' AND '2025-07-01'\nand user_id IS NOT NULL and is_closed = 1 and is_won = 1;\n\n# ********************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Hamilton Court FX LLP%'; # 249, 187, 10103\nSELECT * FROM activities WHERE uuid_to_bin('4659c2bb-9a49-484e-9327-a3d66f1e028c') = uuid; # 28951064\nSELECT * FROM crm_fields WHERE crm_configuration_id = 187 and object_type IN ('tasks', 'event');\n\n# *********************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Checkstep%'; # 325, 256, 11753\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 325\nand sa.provider = 'hubspot';\n\nSELECT * FROM activities WHERE uuid_to_bin('7be372e2-1916-4d79-a2f3-ca3db1346db3') = uuid; # 28611085\nSELECT * FROM activities WHERE uuid_to_bin('980f0336-840b-4185-a5a9-30cf8b0749a8') = uuid; # 28719733\nSELECT * FROM activity_summary_logs where activity_id = 28719733;\n\n# *************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Learning%'; # 260, 356, 9444\nSELECT * FROM activity_summary_logs where sent_at BETWEEN '2025-06-09 11:38:00' AND '2025-06-09 11:40:00';\nSELECT * FROM leads WHERE crm_configuration_id = 356 and crm_provider_id = '230045001502770504'; # 823630\nselect * from activities where crm_configuration_id = 356 and lead_id = 841732;\n\nSELECT * from activity_summary_logs al join activities a on a.id = al.activity_id\nwhere a.crm_configuration_id = 356;\n\nselect * from activities where crm_configuration_id = 356\nand actual_end_time between '2025-06-09 11:00:00' and '2025-06-09 12:00:00'\norder by id desc;\n\nselect * from accounts where crm_configuration_id = 356 and crm_provider_id = '230045001514403366' order by id desc;\nselect * from leads where crm_configuration_id = 356 and crm_provider_id = '230045001514275654' order by id desc;\nselect * from contacts where crm_configuration_id = 356 and crm_provider_id = '230045001514403366' order by id desc;\nselect * from opportunities where crm_configuration_id = 356 and crm_provider_id = '230045001514403366' order by id desc;\n\nselect * from team_features where team_id = 260;\nselect * from features where id IN (1,2,4,6,18,19,20,9,10,3,23,24,25,26,27);\n\nSELECT * FROM activities WHERE uuid_to_bin('7be372e2-1916-4d79-a2f3-ca3db1346db3') = uuid;\n\nselect * from crm_fields;\nselect * from crm_layout_entities;\n\nSELECT * FROM teams WHERE name LIKE '%Optable%';\n\n# *************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Teamtailor%'; # 109, 218, 13969\nSELECT * FROM crm_configurations WHERE id = 218;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 109\nand sa.provider = 'salesforce';\nSELECT * FROM activities WHERE uuid_to_bin('675eeaeb-5681-42db-90bc-54c07a604408') = uuid; # 28655939\nSELECT * FROM crm_field_data WHERE activity_id = 28655939;\nSELECT * FROM crm_fields WHERE id in (94491,94493,94498);\n\nselect * from teams where crm_id IS NULL;\n\nSELECT * FROM activities WHERE uuid_to_bin('71aa8a0c-9652-4ff6-bee7-d98ae60abef6') = uuid;\n\n# *************************************************************************************************\nselect * from team_domains where team_id = 399;\nSELECT * FROM teams WHERE name LIKE '%Rydoo%'; # 399, 318, 13207\n\nselect * from calendar_events where id = 5163781;\nSELECT * FROM activities WHERE uuid_to_bin('be2cbc52-7fda-46a0-9ae0-25d9553eafc0') = uuid; # 29443896\nSELECT * FROM participants WHERE activity_id = 29443896;\nselect * from contacts where crm_configuration_id = 318 and email = 'marianne.westeng@strawberry.no';\nselect * from leads where crm_configuration_id = 318 and email = 'marianne.westeng@strawberry.no';\n\nselect * from activities where user_id = 14937 order by created_at ;\n\nselect * from users where id = 14937;\n\nselect * from contacts where crm_configuration_id = 318 and email LIKE '%@strawberry.se';\nselect * from opportunities where crm_configuration_id = 318 and crm_provider_id = '006Sf00000D1WOAIA3';\n\nselect * from activities a join participants p on a.id = p.activity_id\nwhere crm_configuration_id = 318 and a.updated_at > '2025-06-23T08:18:43Z';\n\n# *************************************************************************************************\nSELECT * FROM opportunities WHERE team_id = 379 and crm_provider_id = '39334518886';\nSELECT * FROM opportunities WHERE team_id = 379 order by id desc;\nSELECT * FROM teams WHERE id = 379;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 379 and sociable_id = 13852\nand sa.provider = 'hubspot';\n\nSELECT * FROM crm_configurations WHERE id = 307;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 307;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1027;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 307\n and id IN (144750,144855,145158,155227);\n\nSELECT * FROM activities;\n\n\nselect * from activities\nwhere created_at > '2025-07-01 00:00:00'\n# and created_at < '2025-08-01 00:00:00'\nand type not in ('email-outbound', 'email-inbound')\nand account_id is null\nand contact_id is null\nand lead_id is null\nand opportunity_id is not null\n;\nSELECT * FROM activities WHERE id IN (25344155, 25344296, 25501909, 28692187);\nSELECT * FROM crm_configurations WHERE id in (335,301,200);\n\nselect * from crm_fields where crm_configuration_id = 230 and crm_provider_id = 'Age2__c';\n\nSELECT * FROM teams WHERE name LIKE '%Resights%';\nselect * from crm_fields where crm_configuration_id = 1 and object_type = 'opportunity';\n\nselect * from crm_configurations where provider = 'bullhorn'; # 344\nselect * from teams where id IN (442);\n\nselect * from activities\nwhere crm_configuration_id = 177\nand provider = 'amazon-connect'\n order by id desc;\n# and source <> 'gong';\n\nselect * from activity_providers where provider = 'amazon-connect';\n\nSELECT * FROM activities WHERE uuid_to_bin('cec1993b-a7e5-4164-b74d-d680ea51d2f2') = uuid;\n\n\nselect * from crm_configurations where store_transcript = 1;\nSELECT * FROM teams WHERE id IN (80);\n\n# *************************************************************************************************\nSELECT * FROM teams WHERE name LIKE '%Sedna%'; # 277, 213, 12594\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 277\nand sa.provider = 'salesforce';\n\nselect * from activities where crm_configuration_id = 213 and account_id = 2511502;\n\nselect * from crm_configurations where id = 213;\n\nSELECT * FROM activities WHERE uuid_to_bin('35aa790a-8569-4544-8268-66f9a4a26804') = uuid; # 33981604\nSELECT * FROM participants WHERE activity_id = 33981604;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 337 and object_type = 'task';\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 431\nand sa.provider = 'salesforce';\nSELECT * FROM activities WHERE uuid_to_bin('b5476c7d-19a8-491b-869d-676ea1e857b6') = uuid; # 33997223\nselect * from activity_summary_logs where activity_id = 33997223;\nselect * from activity_notes where activity_id = 33997223;\n\n# ***********************************\nSELECT * FROM teams WHERE name LIKE '%Abode%';\n\n\nselect * from features;\nselect * from teams t\nwhere t.status = 'active'\nand id NOT IN (select team_id from team_features where feature_id = 9)\n;\n\n\nselect * from playbook_layouts where playbook_id = 1725;\nSELECT * FROM activities WHERE uuid_to_bin('65cc283c-4849-49e6-927f-4c281c8fea19') = uuid; # 34297473\nselect * from teams where id = 318;\nselect * from crm_configurations where team_id = 318;\nselect * from playbooks where team_id = 318;\nSELECT * FROM crm_layouts where crm_configuration_id = 381;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1259;\nSELECT * FROM crm_fields WHERE id IN (192938,192936,192939);\n\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1266;\nSELECT * FROM crm_fields WHERE id IN (192980,192991,192997,192998,193064,193067);\n\nSELECT * FROM activities WHERE uuid_to_bin('a902289b-285c-48eb-9cc2-6ad6c5d938f5') = uuid; # 34297533\n\n\n\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 927;\nSELECT * FROM crm_fields WHERE id IN (131668,131669,131670,131671,131676,131797);\n\nSELECT * FROM teams WHERE name LIKE '%Peripass%'; # 351, 281, 12124\nselect * from crm_layouts where crm_configuration_id = 281;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 927;\nselect * from crm_fields where crm_configuration_id = 281 and id in (131668,131669,131670,131671,131676,131797);\nselect * from opportunities where crm_configuration_id = 281;\n\nSELECT * FROM activities WHERE id IN (34211315, 34130075);\nSELECT * FROM crm_field_data WHERE object_id IN (34211315, 34130075);\n\nselect cf.crm_configuration_id, cle.crm_layout_id, cle.id, cf.id from crm_field_data cfd\njoin crm_layout_entities cle on cle.id = cfd.crm_layout_entity_id\njoin crm_fields cf on cle.crm_field_id = cf.id\nwhere cf.deleted_at IS NOT NULL\nGROUP BY cle.id, cf.id;\n\nselect * from crm_layouts where id IN (355);\nselect u.email, t.crm_id, t.* from teams t\njoin users u on u.id = t.owner_id\nwhere crm_id IN (97);\n\nSELECT * FROM crm_fields WHERE id = 96492;\n\nselect * from permissions;\nselect * from permission_role where permission_id = 247;\nselect * from roles;\n\nselect * from migrations;\n# *****************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('291e3c21-11cc-4728-aee7-6e4bedf86d72') = uuid; # 34262174\nSELECT * FROM crm_configurations WHERE id = 301;\nSELECT * FROM teams WHERE id = 343;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 343\nand sa.provider = 'hubspot';\n\nselect * from participants where activity_id = 34262174;\n\nselect * from contacts where crm_configuration_id = 301 and id = 6976326;\nselect * from accounts where crm_configuration_id = 301 and id IN (4647626, 4815829); # 30761335403\n\nselect * from activity_summary_logs where activity_id = 34262174;\n\nselect * from users where status = 1 AND timezone = 'EST';\n\n# ****************************************************************************\nSELECT * FROM users WHERE id = 13869;\nSELECT * FROM crm_configurations WHERE id = 320;\nSELECT * FROM teams WHERE id = 401;\n\nSELECT * FROM activities WHERE uuid_to_bin('2228c16f-10be-48d5-90d4-67385219dc01') = uuid; # 29670601\n\nSELECT * FROM accounts WHERE id = 7761483;\nSELECT * FROM opportunities WHERE id = 6051814;\n\nSELECT * FROM teams WHERE name LIKE '%Seedlegals%';\n\n;select * from opportunities where updated_at > '2025-10-11' AND crm_provider_id = '34713761166';\n\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 177;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 577;\nSELECT * FROM crm_fields WHERE id IN (68458,68459,68480,68497,68524,68530,68554,68618,68662,68781,68810,68898,68981,69049,97467);\n\nSELECT t.id, crm.id, t.name, crm.sync_objects, crm.provider, crm.last_synced_at FROM crm_configurations crm join teams t on t.crm_id = crm.id\nwhere t.status = 'active' AND crm.provider = 'hubspot' AND crm.last_synced_at < '2025-10-22 00:00:00';\n\nSELECT * FROM activities WHERE uuid_to_bin('fa09449f-cba9-496a-b8f3-865cd3c72351') = uuid;\nSELECT * FROM crm_configurations where id = 184;\nSELECT * FROM teams WHERE id = 246;\nSELECT * FROM social_accounts WHERE sociable_id = 9259 and provider = 'hubspot';\n\nSELECT * FROM users WHERE email LIKE '%rhian.old@bud.co.uk%'; # 17700\nSELECT * FROM teams WHERE id = 551;\n\nSELECT * FROM crm_configurations WHERE id = 471;\nSELECT * FROM activities WHERE crm_configuration_id = 471 and crm_provider_id IS NOT NULL;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 471;\nSELECT * FROM crm_fields WHERE id = 307260;\nSELECT * FROM crm_field_values WHERE crm_field_id = 307260;\n\nselect * from crm_layouts where crm_configuration_id = 471;\n\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1547;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1548;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 551 and sa.provider = 'hubspot';\n\nSELECT * FROM teams WHERE name LIKE '%$PCS%';\n\n# ********************************************************************************************************\nselect * from crm_configurations crm\njoin teams t on t.crm_id = crm.id\nwhere t.status = 'active'\nand crm.provider = 'hubspot';\n\n# $slug = 'HUBSPOT_WEBHOOK_SYNC';\n# $team = Jiminny\\Models\\Team::find(2);\n# $feature = Feature::query()->where('slug', $slug)->first();\n# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);\n\n# hubspot_webhook_metrics\n\nselect * from crm_configurations where id = 331; # 416\nSELECT * FROM teams WHERE id = 416;\nSELECT * FROM opportunities WHERE team_id = 190;\n\nSELECT * FROM teams WHERE name LIKE '%Lead Forensics%';\nSELECT sa.id,\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 190 and sa.provider = 'hubspot';\n\n\n\nSELECT * FROM teams WHERE name LIKE '%Rapaport%'; # 431, 337\nSELECT * FROM teams where id = 431;\nSELECT * FROM crm_configurations where team_id = 431;\nSELECT * FROM activity_providers where team_id = 431;\nSELECT * FROM activities where crm_configuration_id = 337 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\nSELECT sa.id,\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 431 and sa.provider = 'salesforce';\n\nSELECT * FROM teams WHERE name LIKE '%BiP%'; # 401, 320\nSELECT * FROM teams where id = 401;\nSELECT * FROM crm_configurations where team_id = 401;\nSELECT * FROM activity_providers where team_id = 401;\nSELECT * FROM activities where crm_configuration_id = 320 and type IN ('softphone', 'softphone-outbound')\nand provider NOT IN ('hubspot', 'aircall')\n# and telephony_provider_id = '019c1131-a22f-4792-b9ea-20adf6a02ed0'\norder by id desc;\nSELECT sa.id,\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 401 and sa.provider = 'salesforce';\n\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 307; # 379 - Story Terrace Inc , portalId: 3921157\nSELECT * FROM contacts WHERE team_id = 379 and updated_at > '2026-01-31 11:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 379 and updated_at > '2026-02-01 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 379 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 379 and sa.provider = 'hubspot';\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 485; # 563 - LATUS Group (ad94d501-5d09-44fd-878f-ca3a9f8865c3) , portalId: 3904501\nSELECT * FROM opportunities WHERE team_id = 563 and updated_at > '2026-02-02 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 563 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 338; # 432 - Formalize , portalId: 9214205\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 432 and sa.provider = 'hubspot';\nSELECT * FROM opportunities WHERE team_id = 432 and updated_at > '2026-02-02 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 432 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 436; # 519 - Moxso , portalId: 25531989\nSELECT * FROM opportunities WHERE team_id = 519 and updated_at > '2026-02-02 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 519 and updated_at > '2026-02-04 11:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 96; # 119 - Nourish Care , portalId: 26617984\nSELECT * FROM opportunities WHERE team_id = 119 and updated_at > '2026-02-02 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 119 and updated_at > '2026-02-04 11:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 331; # 416 - The National College , portalId: 7213852\nSELECT * FROM opportunities WHERE team_id = 416 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 416 and updated_at > '2026-02-04 11:00:00' order by updated_at desc;\n\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 308; # 380 - Foodles , portalId: 7723616\nSELECT * FROM opportunities WHERE team_id = 380 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 380 and updated_at > '2026-02-06 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 379; # 471 - imat-uve , portalId: 9177354\nSELECT * FROM opportunities WHERE team_id = 471 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 471 and updated_at > '2026-02-06 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 465; # 545 - Spotler , portalId: 144759271\nSELECT * FROM opportunities WHERE team_id = 545 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 545 and updated_at > '2026-02-06 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 455; # 537 - indevis , portalId: 25666868\nSELECT * FROM opportunities WHERE team_id = 537 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 537 and updated_at > '2026-02-06 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 200; # 265 - Jobadder , portalId: 6426676\nSELECT * FROM opportunities WHERE team_id = 265 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 265 and updated_at > '2026-02-06 10:30:00' order by updated_at desc;\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 335; # 429 - Eletive , portalId: 6110563\nSELECT * FROM opportunities WHERE team_id = 429 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 429 and updated_at > '2026-02-09 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 363; # 456 - Global Group , portalId: 8901981\nSELECT * FROM opportunities WHERE team_id = 456 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 456 and updated_at > '2026-02-09 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 297; # 369 - Unbiased , portalId: 9229005\nSELECT * FROM opportunities WHERE team_id = 369 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 369 and updated_at > '2026-02-09 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 353; # 449 - Fuuse , portalId: 25781745\nSELECT * FROM opportunities WHERE team_id = 449 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 449 and updated_at > '2026-02-09 10:30:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 487; # 566 - Nimbus , portalId: 39982590\nSELECT * FROM opportunities WHERE team_id = 566 and updated_at > '2026-02-04 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 566 and updated_at > '2026-02-09 10:30:00' order by updated_at desc;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 487;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1630;\nselect * from crm_fields where crm_configuration_id = 487 and\n(uuid_to_bin('4c6b2971-64d4-45b8-b377-427be758b5a5') = uuid or uuid_to_bin('59e368d8-65a0-4b77-b611-db37c99fbe68') = uuid);\nSELECT * FROM crm_field_values WHERE crm_field_id = 375177;\n# ********************************************************************\nSELECT * FROM crm_configurations where id = 420; # 506 - voiio , portalId: 145629154\nSELECT * FROM opportunities WHERE team_id = 506 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 506 and updated_at > '2026-02-10 15:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 479; # 558 - Momice , portalId: 535962\nSELECT * FROM opportunities WHERE team_id = 558 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 558 and updated_at > '2026-02-10 15:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 59; # 80 - Storyclash GmbH , portalId: 4268479\nSELECT * FROM opportunities WHERE team_id = 80 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 80 and updated_at > '2026-02-10 15:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 175; # 203 - Team iAM , portalId: 5534732\nSELECT * FROM opportunities WHERE team_id = 203 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 203 and updated_at > '2026-02-10 15:00:00' order by updated_at desc;\n\nSELECT * FROM crm_configurations where id = 368; # 460 - OneTouch Health , portalId: 5534732183355\nSELECT * FROM opportunities WHERE team_id = 460 and updated_at > '2026-02-10 00:00:00' order by updated_at desc;\nSELECT * FROM opportunities WHERE team_id = 460 and updated_at > '2026-02-10 15:00:00' order by updated_at desc;\n\n\n\nselect * from users where id = 29643;\nSELECT * FROM crm_field_values WHERE crm_field_id = 375177;\n# ********************************************************************\nSELECT * FROM teams WHERE name LIKE '%Buynomics%'; # 462, 482, 14910\nSELECT * FROM activities WHERE crm_configuration_id = 482\nand type NOT IN ('email-inbound', 'email-outbound')\n# and description like '%The call focused on understanding Welch%'\norder by id desc;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 462 and sa.provider = 'salesforce';\n\nselect * from contacts where crm_configuration_id = 482 and name = 'Cyndall Hill'; # 15504749\nselect * from contacts where id = 10891096; # 482\nSELECT * FROM activities WHERE crm_configuration_id = 482\nand type NOT IN ('email-inbound', 'email-outbound')\nand contact_id = 15504749\norder by id desc;\n\nselect * from activities where id = 36793003; # 96cc7bc1-8622-4d27-92f4-baf664fc1a56, 00UOf00000PDdOXMA1\nselect * from transcription where id = 7646782;\nselect * from ai_prompts where transcription_id = 7646782;\n\n# ********************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('7a8471a3-847e-4822-802b-ddf426bbc252') = uuid; # 37370018\nSELECT * FROM activity_summary_logs WHERE activity_id = 37370018;\nSELECT * FROM teams WHERE id = 555;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 555 and sa.provider = 'hubspot';\n\n# ********************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('7c17b8aa-09df-4f85-a0f7-51f47afd712d') = uuid; # 37395250\nSELECT * FROM activities WHERE uuid_to_bin('14d60388-260d-494b-aa0d-63fdb1c78026') = uuid; # 37395250\n\nSELECT a.* FROM activities a JOIN crm_configurations c on c.id = a.crm_configuration_id\nwhere a.type IN ('softphone', 'softphone-outbound') and c.provider = 'hubspot'\nand a.provider NOT IN ('hubspot')\n# and a.provider IN ('salesloft')\n# and c.id NOT IN (70)\n# and a.duration > 30\n# and actual_start_time > '2026-02-05 00:00:00'\norder by a.id desc;\n\nSELECT * FROM activities WHERE id = 37549787;\nSELECT * FROM crm_profiles WHERE user_id = 17613;\n\nSELECT * FROM crm_configurations WHERE id = 70;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 93 and sa.provider = 'hubspot';\n\nSELECT asf.activity_search_id, asf.id, asf.value\nFROM activity_search_filters asf\nWHERE asf.filter = 'group_id'\nAND asf.value IN (\n SELECT CONCAT(\n HEX(SUBSTR(uuid, 5, 4)), '-',\n HEX(SUBSTR(uuid, 3, 2)), '-',\n HEX(SUBSTR(uuid, 1, 2)), '-',\n HEX(SUBSTR(uuid, 9, 2)), '-',\n HEX(SUBSTR(uuid, 11))\n )\n FROM groups\n WHERE deleted_at IS NOT NULL\n);\n\nSELECT * FROM crm_configurations WHERE id = 373; # KPSBremen.de 465 # - no social account\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 465 and sa.provider = 'hubspot';\n\nselect * from crm_configurations where id = 494;\n\nSELECT * FROM teams WHERE name LIKE '%splose%'; # 572, 495, 18708\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 572 and sa.provider = 'pipedrive';\n\nselect * from opportunities where team_id = 572\n# and name like '%Onebright%'\n# and is_closed = 1 and is_won = 0\n order by id desc;\n\n\nselect * from users where deleted_at is null and status = 2;\n\nselect * from contacts where id = 17900517;\nselect * from accounts where id = 10109838;\nselect * from opportunities where id = 6955880;\n\nselect * from opportunity_contacts where opportunity_id = 6955880;\nselect * from opportunity_contacts where contact_id = 17900517;\n\nselect * from contact_roles cr join crm_configurations crm on cr.crm_configuration_id = crm.id\nwhere crm.provider != 'salesforce';\n\nSELECT * FROM activities WHERE uuid_to_bin('adcb8331-5988-4353-834e-383a355abba2') = uuid; # 38056424, crm 104659682404\nselect * from teams where id = 456;\nSELECT * FROM crm_configurations WHERE id = 363;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 456 and sa.provider = 'hubspot';\n\nselect * from crm_layouts where crm_configuration_id = 363;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id IN (1203, 1204, 1635);\nSELECT * FROM crm_fields WHERE id IN (181536, 181538, 213455);\n\nSELECT * FROM teams WHERE name LIKE '%Electric%'; # 342, 272, 12767\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 342 and sa.provider = 'pipedrive';\nSELECT * FROM opportunities WHERE crm_configuration_id = 272 and name like 'NORTHUMBRIA POL%'; # and updated_at > '2025-07-01 00:00:00';\nSELECT * FROM opportunities WHERE crm_configuration_id = 272 order by remotely_created_at asc; # and updated_at > '2025-07-01 00:00:00';\nSELECT * FROM opportunities WHERE crm_configuration_id = 272 and updated_at > '2026-01-01 00:00:00';\nSELECT * FROM crm_fields WHERE crm_configuration_id = 272 and object_type = 'opportunity';\nSELECT * FROM crm_field_values WHERE crm_field_id = 127164;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 342 and sa.provider = 'pipedrive';\n\nSELECT * FROM teams WHERE id = 472;\nSELECT * FROM crm_configurations WHERE id = 380;\nselect * from activities where id = 38285673; # 38285673\nSELECT * FROM users WHERE id = 16942;\nSELECT * FROM groups WHERE id = 1964;\nSELECT * FROM playbooks WHERE id = 2033;\n\nselect * from teams where created_at > '2026-03-09';\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 499; # 1065\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1678;\n\nSELECT * FROM teams WHERE id = 575;\nselect * from opportunities where team_id = 575;\n\nSELECT * FROM activities WHERE uuid_to_bin('96b1261f-2357-49f9-ab38-23ce12008ea0') = uuid;\n\nselect * from contacts c\nwhere c.crm_configuration_id = 370 order by c.updated_at desc;\n\nSELECT * FROM participants where activity_id = 38833541;\nSELECT * FROM participants where activity_id = 39216301;\nSELECT * FROM activity_summary_logs where activity_id = 39216301;\nSELECT * FROM activities WHERE uuid_to_bin('c7d99fbe-1fb1-41f2-8f4d-52e2bf70e1e9') = uuid; # 38833541, crm 478116564181\nSELECT * FROM activities WHERE uuid_to_bin('2e6ff4d3-9faa-447a-a8c1-9acde4d885ae') = uuid; # 39216301, crm 480171536586\nselect * from crm_profiles where crm_configuration_id = 319 and crm_provider_id = 525785080;\nselect * from opportunities where crm_configuration_id = 319 and crm_provider_id = 410150124747;\nselect * from accounts where crm_configuration_id = 319 and crm_provider_id = 47150650569;\nselect * from contacts where crm_configuration_id = 319 and crm_provider_id IN ('665587441856', '742723347700');\n# owner 13236 525785080\n# contact 1 16779180 665587441856 - activity - Alex Howes alex@supportroom.com created 2026-01-26\n# contact 2 19247563 742723347700 - ash@supportroom.com 2026-03-24\n# company 4176133 47150650569\n# deal 7100953 410150124747\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 400 and sa.provider = 'hubspot';\n\nselect * from features;\nselect * from team_features where feature_id = 40;\n\nselect * from teams where id = 556; # owner: 18101, crm: 477\nselect * from crm_configurations where id = 477;\nSELECT * FROM users WHERE id = 18101;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 556 and sa.provider = 'integration-app';\n\nselect * from opportunities where id = 7594349;\nselect * from opportunity_stages where opportunity_id = 7594349 order by created_at desc;\nselect * from business_processes where id = 6024;\nselect * from business_process_stages where stage_id = 16352;\nselect * from business_process_stages where business_process_id = 6024;\nselect * from stages where team_id = 459;\nselect * from teams where id = 459;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 459 and sa.provider = 'hubspot';\n\nSELECT os.stage_id, s.crm_provider_id, s.name, COUNT(*) as cnt\nFROM opportunity_stages os\nJOIN stages s ON s.id = os.stage_id\nWHERE os.opportunity_id = 7594349\nGROUP BY os.stage_id, s.crm_provider_id, s.name\nORDER BY cnt DESC;\n\nSELECT s.id, s.crm_provider_id, s.name, s.team_id, s.crm_configuration_id\nFROM stages s\nJOIN business_process_stages bps ON bps.stage_id = s.id\nWHERE bps.business_process_id = 6024\nAND s.crm_provider_id = 'contractsent';\n\nselect * from stages where id IN (16352,20612,18281,7344,16378,16309,5036,15223,14535,6293,12098,11607)\n\nSELECT * FROM teams WHERE name LIKE '%Pulsar Group%'; # 472, 380, 15138, raza.gilani@vuelio.com\nselect * from playbooks where team_id = 472; # event 226147\nSELECT * FROM playbook_categories WHERE playbook_id = 2288;\nSELECT * FROM crm_fields WHERE id = 226147;\nSELECT * FROM crm_field_values WHERE crm_field_id = 226147;\n\nSELECT * FROM crm_configurations WHERE id = 380;\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 472 and sa.provider = 'salesforce';","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-7588596953593251659
|
2146738724037637229
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
3
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Services\Kiosk\AutomatedReports;
use Carbon\CarbonImmutable;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityActualDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityUpdatedDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\DealInsights\ClosingPeriodFilter;
use Jiminny\Component\ActivitySearch\FilterDefinitionCollection;
use Jiminny\Component\ActivitySearch\Service\ActivitySearch;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\Activity\SearchFilter;
use Jiminny\Models\User;
use Jiminny\Repositories\ElasticActivityRepository;
use Jiminny\Services\Kiosk\AutomatedReports\AskJiminnyReportActivityService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\VO\Repository\OnDemandActivitySearch\Criteria;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
class AskJiminnyReportActivityServiceTest extends TestCase
{
private ActivitySearch&MockObject $activitySearch;
private ElasticActivityRepository&MockObject $elasticRepository;
private LoggerInterface&MockObject $logger;
private AskJiminnyReportActivityService $service;
protected function setUp(): void
{
$this->activitySearch = $this->createMock(ActivitySearch::class);
$this->elasticRepository = $this->createMock(ElasticActivityRepository::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->service = new AskJiminnyReportActivityService(
$this->activitySearch,
$this->elasticRepository,
$this->logger,
);
}
private function makeFilter(string $key, ?string $value): SearchFilter&MockObject
{
$filter = $this->createMock(SearchFilter::class);
$filter->method('getFilterProperty')->willReturn($key);
$filter->method('getFilterValue')->willReturn($value);
return $filter;
}
private function makeUser(): User&MockObject
{
$tz = new \DateTimeZone('UTC');
$user = $this->createMock(User::class);
$user->method('getTimezone')->willReturn($tz);
$user->method('getId')->willReturn(1);
$user->method('getUuid')->willReturn('user-uuid');
return $user;
}
private function makeSavedSearch(array $filters): Search&MockObject
{
$savedSearch = $this->createMock(Search::class);
$savedSearch->method('getId')->willReturn(42);
$savedSearch->method('getFilters')->willReturn(new \Illuminate\Support\LazyCollection($filters));
return $savedSearch;
}
public function testGetActivityIdsForSavedSearchReturnsIds(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->expects($this->once())
->method('getArrayFilterKeys')
->with($user)
->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->expects($this->once())
->method('onDemandSearchIdsOnly')
->willReturn(['id-1', 'id-2', 'id-3']);
$this->logger->expects($this->once())
->method('info')
->with('[AskJiminnyReport] Fetched activity IDs for saved search');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1', 'id-2', 'id-3'], $result);
}
public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->expects($this->once())->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEmpty($result);
}
public function testGetActivityIdsFiltersOutDateFilters(): void
{
$user = $this->makeUser();
$nonDateFilter = $this->makeFilter('owner_id', '123');
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');
$updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');
$updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');
$savedSearch = $this->makeSavedSearch([
$nonDateFilter,
$startDateFilter,
$endDateFilter,
$updatedFromFilter,
$updatedToFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
}
public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void
{
$user = $this->makeUser();
$closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');
$closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');
$regularFilter = $this->makeFilter('rep_id', '99');
$savedSearch = $this->makeSavedSearch([
$closingStartFilter,
$closingEndFilter,
$regularFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesArrayFilters(): void
{
$user = $this->makeUser();
$filter1 = $this->makeFilter('outcome', 'positive');
$filter2 = $this->makeFilter('outcome', 'negative');
$savedSearch = $this->makeSavedSearch([$filter1, $filter2]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesScalarFilters(): void
{
$user = $this->makeUser();
$filter = $this->makeFilter('direction', 'inbound');
$savedSearch = $this->makeSavedSearch([$filter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-5'], $result);
}
public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
$this->assertFalse($capturedCriteria->isFirstRequest());
}
public function testGetActivityIdsLogsWithCorrectContext(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);
$this->logger->expects($this->once())
->method('info')
->with(
'[AskJiminnyReport] Fetched activity IDs for saved search',
$this->callback(fn ($context) => $context['saved_search_id'] === 42
&& $context['user_id'] === 1
&& $context['activity_count'] === 2)
);
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
}
public static function frequencyDateRangeProvider(): array
{
$now = CarbonImmutable::parse('2025-06-16 12:00:00');
return [
'daily' => [
AutomatedReportsService::FREQUENCY_DAILY,
$now->subDay()->startOfDay()->format('Y-m-d H:i:s'),
$now->subDay()->endOfDay()->format('Y-m-d H:i:s'),
],
'weekly' => [
AutomatedReportsService::FREQUENCY_WEEKLY,
$now->subWeek()->startOfWeek()->format('Y-m-d H:i:s'),
$now->subWeek()->endOfWeek()->format('Y-m-d H:i:s'),
],
'monthly' => [
AutomatedReportsService::FREQUENCY_MONTHLY,
$now->subMonthNoOverflow()->startOfMonth()->format('Y-m-d H:i:s'),
$now->subMonthNoOverflow()->endOfMonth()->format('Y-m-d H:i:s'),
],
'quarterly' => [
AutomatedReportsService::FREQUENCY_QUARTERLY,
$now->subQuarterNoOverflow()->startOfQuarter()->format('Y-m-d H:i:s'),
$now->subQuarterNoOverflow()->endOfQuarter()->format('Y-m-d H:i:s'),
],
];
}
/**
* @dataProvider frequencyDateRangeProvider
*/
public function testGetActivityIdsInjectsDateRangeForFrequency(
string $frequency,
string $expectedStartDate,
string $expectedEndDate,
): void {
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);
$this->assertNotNull($capturedCriteria);
$this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void
{
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');
$savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);
$this->assertNotNull($capturedCriteria);
$this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
27
9
23
3
105
Previous Highlighted Error
Next Highlighted Error
SELECT * FROM team_features where team_id = 1;
SELECT * FROM teams WHERE name LIKE '%Vixio%'; # 340,270,11922
SELECT * FROM users WHERE team_id = 340; # 12015
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 340
and sa.provider = 'salesforce';
# and sa.provider = 'salesloft';
select * from crm_fields where crm_configuration_id = 270 and object_type = 'event';
# 125558 - Event Type - Event_Type__c
# 125552 - Event Status - Event_Status__c
SELECT * FROM sidekick_settings WHERE team_id = 340;
SELECT * FROM crm_field_values WHERE crm_field_id in (125552);
select * from activities where crm_configuration_id = 270
and type = 'conference' and crm_provider_id IS NOT NULL
and actual_start_time > '2024-09-16 09:00:00' order by scheduled_start_time;
SELECT * FROM activities WHERE id = 20871677;
SELECT * FROM crm_field_data WHERE activity_id = 20871677;
select * from crm_layouts where crm_configuration_id = 270;
select * from crm_layout_entities where crm_layout_id in (886,887);
SELECT * FROM crm_configurations WHERE id = 270;
select * from playbooks where team_id = 340; # 1514
select * from groups where team_id = 340;
SELECT * FROM crm_fields WHERE id IN (125393, 125401);
select g.name as 'team name', p.name as 'playbook name', f.label as 'activity type field' from groups g
join playbooks p on g.playbook_id = p.id
join crm_fields f on p.activity_field_id = f.id
where g.team_id = 340;
SELECT * FROM activities WHERE uuid_to_bin('0c180357-67d2-419e-a8c3-b832a3490770') = uuid; # 20448716
select * from crm_field_data where object_id = 20448716;
select * from activities where crm_configuration_id = 270 and provider = 'salesloft' order by id desc;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%CybSafe%'; # 343,273,12008
select * from opportunities where team_id = 343;
select * from opportunities where team_id = 343 and crm_provider_id = '18099102526';
select * from opportunities where team_id = 343 and account_id = 945217482;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 343
and sa.provider = 'hubspot';
select * from accounts where team_id = 343 order by name asc;
select * from stages where crm_configuration_id = 273 and type = 'opportunity';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Voyado%'; # 353,283,12143
SELECT * FROM activities WHERE crm_configuration_id = 283 and account_id = 3777844 order by id desc;
SELECT * FROM accounts WHERE team_id = 353 AND name LIKE '%Salesloft%';
SELECT * FROM activities WHERE id = 20717903;
select * from participants where activity_id IN (20929172,20928605,20928468,20926272,20926271,20926270,20926269,20916499,20916454,20916436,20916435,20900015,20900014,20900013,20897312,20897243,20897241,20897237,20897232,20897229,20893648,20893231,20893230,20893229,20893228,20889784,20885039,20885038,20885037,20885036,20885035,20882728,20882708,20882703,20882702,20869828,20869811,20869806,20869801,20869799,20869798,20869796,20869795,20869794,20869761,20869760,20869759,20868688,20868687,20850340,20847195,20841710,20833967,20827021,20825307,20825305,20825297,20824615,20824400,20823927,20821760,20795588,20794233,20794057,20793710,20785811,20781789,20781394,20781307,20762651,20758453,20758282,20757323,20756643,20756636,20756629,20756627,20756606,20756605,20756604,20756603,20756602,20756600,20756599,20756598,20756595,20756594,20756589,20756587,20756577,20756573,20748918,20748386,20748385,20748384,20748383,20748382,20748381,20748380,20748379,20748377,20748375,20748373,20743301,20717905,20717904,20717903,20717901,20717899);
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 353
and sa.provider = 'salesforce';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%modern world business solutions%'; # 345,275,12016, [EMAIL]
SELECT * FROM activities WHERE uuid_to_bin('3921d399-3fef-4609-a291-b0097a166d43') = uuid;
# id: 20940638, user: 12022, contact: 5305871
SELECT * FROM activity_summary_logs WHERE activity_id = 20940638;
select * from contacts where team_id = 345 and crm_provider_id = '30891432415' order by name asc; # 5305871
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 345
and sa.provider = 'hubspot';
select * from users where team_id = 345 and id = 12022;
SELECT * FROM crm_profiles WHERE user_id = 12022;
SELECT * FROM participants WHERE activity_id = 20940638;
SELECT * FROM users u
JOIN crm_profiles cp ON u.id = cp.user_id
WHERE u.team_id = 345;
select * from contacts where team_id = 345 and crm_provider_id = '30880813535' order by name desc; # 5305871
select * from team_features where team_id = 345;
SELECT * FROM activities WHERE uuid_to_bin('11701e2d-2f82-4dab-a616-1db4fad238df') = uuid; # 21115197
SELECT * FROM participants WHERE activity_id = 20897406;
SELECT * FROM activities WHERE uuid_to_bin('63ba55cd-1abc-447d-83da-0137000005b7') = uuid; # 20953912
SELECT * FROM activities WHERE crm_configuration_id = 275 and provider = 'ringcentral' and title like '%1252629100%';
SELECT * FROM activities WHERE id = 20946641;
SELECT * FROM crm_profiles WHERE user_id = 10211;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Lunio%'; # 120,97,10984, [EMAIL]
SELECT * FROM opportunities WHERE crm_configuration_id = 97 and crm_provider_id = '006N1000006c5PpIAI';
select * from stages where crm_configuration_id = 97 and type = 'opportunity';
select * from opportunities where team_id = 120;
select * from crm_configurations crm join teams t on crm.id = t.crm_id
where 1=1
AND t.current_billing_plan IS NOT NULL
AND crm.auto_sync_activity = 0
and crm.provider = 'hubspot';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Exclaimer%'; # 270,205,10053,[EMAIL]
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 270
and sa.provider = 'salesforce';
SELECT * FROM activities WHERE uuid_to_bin('b54df794-2a9a-4957-8d80-09a600ead5f8') = uuid; # 21637956
SELECT * FROM crm_profiles WHERE user_id = 11446;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Cygnetise%'; # 372,300,12554, [EMAIL]
select * from playbooks where team_id = 372;
select * from crm_fields where crm_configuration_id = 300 and object_type = 'event'; # 141340
SELECT * FROM crm_field_values WHERE crm_field_id = 141340;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 372
and sa.provider = 'salesforce';
select * from crm_profiles where crm_configuration_id = 300;
SELECT * FROM crm_configurations WHERE team_id = 372;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Planday%'; # 291,242,11501,[EMAIL]
SELECT * FROM opportunities WHERE team_id = 291 and crm_provider_id = '006bG000005DO86QAG'; # 3207756
select * from crm_field_data where object_id = 3207756;
SELECT * FROM crm_fields WHERE id = 111834;
select f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value
FROM crm_fields f
JOIN crm_field_data fd ON f.id = fd.crm_field_id
WHERE f.crm_configuration_id = 242
AND f.object_type = 'opportunity'
AND fd.object_id IN (3207756)
ORDER BY fd.object_id, fd.updated_at;
SELECT * FROM crm_configurations WHERE auto_connect = 1;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Tour%'; # 187,209,8150,[EMAIL]
select * from group_deal_risk_types drgt join groups g on drgt.group_id = g.id
where g.team_id = 187;
select * from `groups` where team_id = 187;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 187
and sa.provider = 'salesforce';
# Destination - 98870 - Destination__c
# Stage - 79014 - StageName
# Land Arrangement - 98856 - Land_Arrangement__c
# Flight - 98848 - Flight__c
# Last activity date - 98812 - LastActivityDate
# Last modified date - 98809 - LastModifiedDate
# Last inbound mail timestamp - 99151 - Last_Inbound_Mail_Timestamp__c
# next call - 98864 - Next_Call__c
select * from crm_fields where crm_configuration_id = 209 and object_type = 'opportunity';
SELECT * FROM crm_layouts WHERE crm_configuration_id = 209;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 682;
select * from opportunities where team_id = 187 and name LIKE'%Muriel Sal%';
select * from opportunities where team_id = 187 and user_id = 9951 and is_closed = 0;
select * from activities where opportunity_id = 3538248;
SELECT * FROM crm_profiles WHERE user_id = 8150;
select * from deal_risks where opportunity_id = 3538248;
select * from teams where crm_id IS NULL;
SELECT opp.id AS opportunity_id,
u.group_id AS group_id,
MAX(
CASE
WHEN a.type IN ("sms-inbound", "sms-outbound") THEN a.created_at
ELSE a.actual_end_time
END) as last_date
FROM opportunities opp
left join activities a on a.opportunity_id = opp.id
inner join users u on opp.user_id = u.id
where opp.user_id IN (9951)
AND opp.is_closed = 0
and a.status IN ('completed', 'received', 'delivered') OR a.status IS NULL
group by opp.id;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Cybsafe%'; # 343,301,12008,[EMAIL]
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 343
and sa.provider = 'hubspot';
SELECT * FROM crm_profiles WHERE crm_configuration_id = 301;
SELECT * FROM contacts WHERE id = 6612363;
SELECT * FROM accounts WHERE id = 4235676;
SELECT * FROM opportunities WHERE crm_configuration_id = 301 and crm_provider_id = 32983784868;
select * from opportunity_stages where opportunity_id = 4503759;
# SELECT * FROM opportunities WHERE id = 4569937;
select * from activities where crm_configuration_id = 301;
SELECT * FROM activities WHERE uuid_to_bin('d3b2b28b-c3d0-4c2d-8ed0-eef42855278a') = uuid; # 26330370
SELECT * FROM participants WHERE activity_id = 26330370;
SELECT * FROM teams WHERE id = 375;
select * from playbooks where team_id = 375;
select * from stages where crm_configuration_id = 301 and type = 'opportunity';
select * from teams;
select * from contact_roles;
SELECT * FROM opportunities WHERE team_id = 343 and user_id = 12871 and close_date >= '2024-11-01';
select * from users u join crm_profiles cp on cp.user_id = u.id where u.team_id = 343;
SELECT * FROM crm_field_data WHERE object_id = 3771706;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 343
and sa.provider = 'hubspot';
SELECT * FROM crm_fields WHERE crm_configuration_id = 301 and object_type = 'opportunity'
and crm_provider_id LIKE "%traffic_light%";
SELECT * FROM crm_field_values WHERE crm_field_id IN (144020,144048,144111,144113,144126,144481,144508,144531);
SELECT fd.* FROM opportunities o
JOIN crm_field_data fd ON o.id = fd.object_id
WHERE o.team_id = 343
# and o.user_id IS NOT NULL
and fd.crm_field_id IN (144020,144048,144111,144113,144126,144481,144508,144531)
and fd.value != ''
order by value desc
# group by o.id
;
SELECT * FROM opportunities WHERE id = 3769843;
SELECT * FROM teams WHERE name LIKE '%Tour%'; # 187,209,8150, [EMAIL]
SELECT * FROM crm_layouts WHERE crm_configuration_id = 209;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 682;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Funding Circle%'; # 220,177,8603,[EMAIL]
SELECT * FROM activities WHERE uuid_to_bin('7a40e99b-3b37-4bb1-b983-325b81801c01') = uuid; # 23139839
SELECT * FROM opportunities WHERE id = 3855992;
SELECT * FROM users WHERE name LIKE '%Angus Pollard%'; # 8988
SELECT * FROM teams WHERE name LIKE '%Story Terrace%'; # 379, 307, 12894
SELECT * FROM crm_fields WHERE crm_configuration_id = 307 and object_type != 'opportunity';
select * from contacts where team_id = 379 and name like '%bebro%'; # 5874411, crm: 77229348507
SELECT * FROM crm_field_data WHERE object_id = 5874411;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 379
and sa.provider = 'hubspot';
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%mentio%'; # 117, 94, 6371, [EMAIL]
SELECT * FROM activities WHERE uuid_to_bin('82939311-1af0-4506-8546-21e8d1fdf2c1') = uuid;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Tourlane%'; # 187, 209, 8150, [EMAIL]
SELECT * FROM opportunities WHERE team_id = 187 and crm_provider_id = '006Se000008xfvNIAQ'; # 3537793
select * from generic_ai_prompts where subject_id = 3537793;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Lunio%'; # 120, 97, 10984, [EMAIL]
SELECT * FROM crm_configurations WHERE id = 97;
SELECT * FROM crm_layouts WHERE crm_configuration_id = 97;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 355;
SELECT * FROM crm_fields WHERE id = 32682;
select cfd.value, o.* from opportunities o
join crm_field_data cfd on o.id = cfd.object_id and cfd.crm_field_id = 32682
where team_id = 120
and cfd.value != ''
;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 120
and sa.provider = 'salesforce';
select * from opportunities where team_id = 120 and crm_provider_id = '006N1000007X8MAIA0';
SELECT * FROM crm_field_data WHERE object_id = 2313439;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE id = 410;
SELECT * FROM teams WHERE name LIKE '%Local Business Oxford%';
select * from scorecards where team_id = 410;
select * from scorecard_rules;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Funding%'; # 220, 177, 8603, [EMAIL]
select * from activities a
join opportunities o on a.opportunity_id = o.id
join users u on o.user_id = u.id
where a.crm_configuration_id = 177 and a.type LIKE '%email-out%'
# and a.actual_end_time > '2024-12-16 00:00:00'
# and o.remotely_created_at > '2024-12-01 00:00:00'
# and u.group_id = 1014
and u.id = 9021
order by a.id desc;
SELECT * FROM opportunities WHERE id in (3981384,4017346);
SELECT * FROM users WHERE team_id = 220 and id IN (8775, 11435);
select * from users where id = 9021;
select * from inboxes where user_id = 9021;
select * from inbox_emails where inbox_id = 1349 and email_date > '2024-12-18 00:00:00';
select * from email_messages where team_id = 220
and orig_date > '2024-12-16 00:00:00' and orig_date < '2024-12-19 00:00:00'
and subject LIKE '%Personal%'
# and 'from' = '[EMAIL]'
;
select * from activities a
join opportunities o on a.opportunity_id = o.id
where a.user_id = 9021 and a.type LIKE '%email-out%'
and a.actual_end_time > '2024-12-18 00:00:00'
and o.user_id IS NOT NULL
and o.remotely_created_at > '2024-12-01 00:00:00'
order by a.id desc;
SELECT * FROM opportunities WHERE team_id = 220 and name LIKE '%Right Car move Limited%' and id = 3966852;
select * from activities where crm_configuration_id = 177 and type LIKE '%email%' and opportunity_id = 3966852 order by id desc;
select * from team_settings where name IN ('useCloseDate');
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Hurree%'; # 104, 81, 6175, [EMAIL]
SELECT * FROM opportunities WHERE team_id = 104 and name = 'PropOp';
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 104
and sa.provider = 'hubspot';
select * from crm_configurations where last_synced_at > '2025-01-19 01:00:00'
select * from teams where crm_id IS NULL;
select t.name as 'team', u.name as 'owner', u.email, u.phone
from teams t
join activity_providers ap on t.id = ap.team_id
join users u on t.owner_id = u.id
where 1=1
and t.status = 'active'
and ap.is_enabled = 1
# and u.status = 1
and ap.provider = 'ms-teams';
select * from crm_configurations where provider = 'bullhorn'; # 344
SELECT * FROM teams WHERE id = 442; # 14293
select * from users where team_id = 442;
select * from social_accounts sa where sa.sociable_id = 14293;
select * from invitations where team_id = 442;
# [PASSWORD_DOTS]
SELECT * FROM users WHERE email LIKE '%[EMAIL]%'; # 14022
SELECT * FROM teams WHERE id = 429;
select * from opportunities where team_id = 429 and crm_provider_id IN (16157415775, 22246219645);
select * from activities where opportunity_id in (4340436,4353519);
select * from transcription where activity_id IN (25630961,25381771);
select * from generic_ai_prompts where subject_id IN (4353519);
SELECT
a.id as activity_id,
a.opportunity_id,
a.type as activity_type,
a.language,
CONCAT(a.title, a.description) AS mail_content,
e.from AS mail_from,
e.to AS mail_to,
e.subject AS mail_subject,
e.body AS mail_body,
p.type as prompt_type,
p.status as prompt_status,
p.content AS prompt_content,
a.actual_start_time as created_at
FROM activities a
LEFT JOIN ai_prompts p ON a.transcription_id = p.transcription_id AND p.deleted_at IS NULL
LEFT JOIN email_messages e ON a.id = e.activity_id
WHERE a.actual_start_time > '2024-01-01 00:00:00'
AND a.opportunity_id IN (4353519)
AND a.status IN ('completed', 'received', 'delivered')
AND a.deleted_at IS NULL
AND a.type NOT IN ('sms-inbound', 'sms-outbound')
ORDER BY a.opportunity_id ASC, a.id ASC;
SELECT * FROM users WHERE name LIKE '%George Fierstone%'; # 14293
SELECT * FROM teams WHERE id = 442;
SELECT * FROM crm_configurations WHERE id = 344;
select * from team_features where team_id = 442;
select * from groups where team_id = 442;
select * from playbooks where team_id = 442;
select * from playbook_categories where playbook_id = 1729;
select * from crm_fields where crm_configuration_id = 344 and id = 172024;
SELECT * FROM crm_field_values WHERE crm_field_id = 172024;
select * from crm_layouts where crm_configuration_id = 344;
select * from playbook_layouts where playbook_id = 1729;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Learning%'; # 260, 221, 9444
select s.*
# , s.sent_at, u.name, a.*
from activity_summary_logs s
inner join activities a on a.id = s.activity_id
inner join users u on u.id = a.user_id
where a.crm_configuration_id = 356
and s.sent_at > date_sub(now(), interval 60 day)
order by a.actual_end_time desc;
select * from activities a
# inner join activity_summary_logs s on s.activity_id = a.id
where a.crm_configuration_id = 356 and a.actual_end_time > date_sub(now(), interval 60 day)
# and a.crm_provider_id is not null
# and provider <> 'ringcentral'
and status = 'completed'
order by a.actual_end_time desc;
select * from teams order by id desc; # 17328, 32, 17830, [EMAIL]
SELECT * FROM users;
SELECT * FROM users where team_id = 260 and status = 1; # 201 - 150 active
SELECT * FROM teams WHERE id = 260;
select * from team_settings where team_id = 260;
select * from crm_configurations where team_id = 260;
SELECT * FROM crm_layouts WHERE crm_configuration_id = 356;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 1184;
select * from accounts where crm_configuration_id = 221 order by id desc; # 7000
select * from leads where crm_configuration_id = 221 order by id desc; # 0
select * from contacts where crm_configuration_id = 221 order by id desc; # 200 000
select * from opportunities where crm_configuration_id = 221 order by id desc; # 0
select * from crm_profiles where crm_configuration_id = 221 order by id desc; # 23
select * from crm_fields where crm_configuration_id = 221;
select * from crm_field_values where crm_field_id = 5302 order by id desc;
select * from crm_layouts where crm_configuration_id = 221 order by id desc;
select * from stages where crm_configuration_id = 221 order by id desc;
select * from accounts where crm_configuration_id = 356 order by id desc; # 7000
select * from leads where crm_configuration_id = 356 order by id desc; # 0
select * from contacts where crm_configuration_id = 356 order by id desc; # 200 000
select * from opportunities where crm_configuration_id = 356 order by id desc; # 0
select * from crm_profiles where crm_configuration_id = 356 order by id desc; # 23
select * from crm_fields where crm_configuration_id = 356;
select * from crm_field_values where crm_field_id = 5302 order by id desc;
select * from crm_layouts where crm_configuration_id = 356 order by id desc;
select * from stages where crm_configuration_id = 356 order by id desc;
select * from playbooks where team_id = 260 order by id desc; # 4 (2 deleted)
select * from groups where team_id = 260 order by id desc; # 27 groups, (2 deleted)
select * from playbook_layouts where playbook_id IN (1410,1409,1276,1254); # 4
select ce.* from calendars c
join users u on c.user_id = u.id
join calendar_events ce on c.id = ce.calendar_id
where u.team_id = 260
and (ce.start_time > '2025-02-21 00:00:00')
;
# calendar events 1207
#
select * from opportunities where team_id = 260;
SELECT * FROM crm_field_data WHERE object_id = 4696496;
select * from activities where crm_configuration_id = 356 and crm_provider_id IS NOT NULL;
select * from activities where crm_configuration_id IN (221) and provider NOT IN ('ms-teams', 'uploader', 'zoom-bot')
# and type = 'conference' and status = 'scheduled' and activities.is_internal = 0
and created_at > '2024-03-01 00:00:00'
order by id desc; # 880 000, ringcentral, avaya
SELECT * FROM participants WHERE activity_id = 26371744;
# all activities 942 000 +
# conference 7385 - scheduled 984 - external 343
select * from activities where id = 26321812;
select * from participants where activity_id = 26321812;
select * from participants where activity_id in (26414510,26414514,26414516,26414604,26414653,26414655);
select * from leads where id in (720428,689175,731546,645866,621037);
select * from users where id = 13841;
select * from opportunities where user_id = 9541;
select * from stages where id = 15900;
select * from accounts where
# id IN (4160055,5053725,4965303,4896434)
id in (4584518,3249934,3218025,3891133,3399450,4172999,4485161,3101785,4587203,3070816,2870343,2870341,3563940,4550846,3424464,3249963,2870342)
;
select * from activities where id = 26654935;
SELECT * FROM opportunities WHERE id = 4803458;
SELECT * FROM opportunities where team_id = 260 and user_id = 13841 AND stage_id = 15900;
SELECT id, uuid, provider, type, lead_id, account_id, contact_id, opportunity_id, stage_id, status, recording_state, title, actual_start_time, actual_end_time
FROM activities WHERE user_id = 13841 AND opportunity_id IN (4729783, 4731717, 4731726, 4732064, 4732849, 4803458, 4813213);
SELECT DISTINCT
o.id, o.stage_id, s.name, a.title,
a.*
FROM activities a
# INNER JOIN tracks t ON a.id = t.activity_id
INNER JOIN users u ON a.user_id = u.id
INNER JOIN teams team ON u.team_id = team.id
INNER JOIN groups g ON u.group_id = g.id
INNER JOIN opportunities o ON a.opportunity_id = o.id
INNER JOIN stages s ON o.stage_id = s.id
WHERE
a.crm_configuration_id = 356
AND a.status IN ('completed', 'failed')
AND a.recording_state != 'stopped'
# and a.user_id = 13841
AND u.uuid = uuid_to_bin('6f40e4b8-c340-4059-b4ac-1728e87ea99e')
AND team.uuid = uuid_to_bin('a607fba7-452e-4683-b2af-00d6cb52c93c')
AND g.uuid = uuid_to_bin('b5d69e40-24a0-4c16-810b-5fa462299f94')
AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')
# AND t.type IN ('audio', 'video')
AND (
(a.actual_start_time BETWEEN '2025-03-13 00:00:00' AND '2025-03-18 07:59:59')
OR
(
a.actual_start_time IS NULL
AND a.type IN ('sms-outbound', 'sms-inbound')
AND a.created_at BETWEEN '2025-03-13 00:00:00' AND '2025-03-18 07:59:59'
)
)
AND (
a.is_private = 0
OR (
a.is_private = 1
AND u.uuid = uuid_to_bin('6f40e4b8-c340-4059-b4ac-1728e87ea99e')
)
)
AND (
# s.id = 15900
s.uuid = uuid_to_bin('04ca1c26-c666-4268-a129-419c0acffd73')
OR s.uuid IS NULL -- Include records without opportunity stage
)
ORDER BY a.actual_end_time DESC;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Lead Forensics%'; # 190, 162, 8474, [EMAIL]
SELECT * FROM users WHERE team_id = 190;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 190
and sa.provider = 'hubspot';
select * from role_user where user_id = 8474;
select * from crm_configurations where provider = 'bullhorn';
SELECT * FROM opportunities WHERE uuid_to_bin('94578249-65ec-4205-90f2-7d1a7d5ab64a') = uuid;
SELECT * FROM users WHERE uuid_to_bin('26dbadeb-926f-4150-b11b-771b9d4c2f9a') = uuid;
SELECT * FROM opportunities WHERE id = 4732493;
select * from activities where opportunity_id = 4732493;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE id = 443; # 358, 14315, [EMAIL]
SELECT * FROM opportunities WHERE team_id = 443;
SELECT a.id, a.type, a.user_id, a.status, a.deleted_at, u.name, u.email, u.team_id as activity_team_id, u.status, u.deleted_at, t.name, t.status, s.team_id as stage_team_id
FROM activities AS a
JOIN stages AS s ON a.stage_id = s.id
JOIN users AS u ON u.id = a.user_id
JOIN teams AS t ON t.id = s.team_id
WHERE u.team_id <> s.team_id and t.id > 135;
SELECT
crm_configuration_id,
crm_provider_id,
COUNT(*) as duplicate_count,
GROUP_CONCAT(id) as stage_ids,
GROUP_CONCAT(name) as stage_names
FROM stages
GROUP BY crm_configuration_id, crm_provider_id
HAVING COUNT(*) > 1
ORDER BY duplicate_count DESC;
select * from stages where id IN (14898,14907);
select * from business_processes;
SELECT *
FROM crm_configurations
WHERE team_id IN (
SELECT team_id
FROM crm_configurations
GROUP BY team_id
HAVING COUNT(*) > 1
)
ORDER BY team_id;
SELECT *
FROM teams
WHERE crm_id IN (
SELECT crm_id
FROM teams
GROUP BY crm_id
HAVING COUNT(*) > 1
)
ORDER BY crm_id;
# [PASSWORD_DOTS]
select * from crm_configurations where provider = 'integration-app';
SELECT * FROM teams WHERE id = 443; # Correre Naturale 358 14315 [EMAIL]
select * from activities where crm_configuration_id = 358 order by actual_end_time desc;
select id, uuid, actual_end_time, crm_provider_id, is_internal, playbook_category_id, type, user_id, lead_id, contact_id, account_id, opportunity_id, status, title from activities where crm_configuration_id = 358 order by actual_end_time desc;
select * from team_features where team_id = 358;
select * from activity_summary_logs;
select * from teams where id = 406;
# [PASSWORD_DOTS]
SELECT * FROM teams WHERE name LIKE '%Sportfive%'; # 267, 202, 14637, [EMAIL]
select * from activities where crm_configuration_id = 202 order by actual_end_time desc;
SELECT * FROM users where id = 14637;
SELECT * FROM teams where id = 267;
SELECT * FROM groups where id = 1118;
select g.name, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled_start_time, a.scheduled_end_time, a.actual_start_time, a.actual_end_time from activities a
inner join users u on u.id = a.user_id
inner join groups g on g.id = u.group_id
where a.crm_configuration_id = 202
and a.is_internal = 0
and (a.scheduled_start_time between '2025-03-19 00:00:00' and '2025-03-21 00:00:00')
and a.type = 'conference'
and a.status != 'completed'
and a.external_id is not null
order by a.scheduled_start_time desc;
SELECT * FROM activities
WHERE crm_configuration_id = 202
AND status IN ('completed', 'failed')
AND recording_state != 'stopped'
AND type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')
AND (is_private = 0 OR user_id = 14637)
AND (
(
actual_start_time BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'
) OR (
actual_start_time IS NULL
AND type IN ('sms-outbound', 'sms-inbound')
AND created_at BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'
)
)
AND NOT EXISTS (
SELECT 1
FROM tracks
WHERE
tracks.activity_id = activities.id
AND tracks.type IN ('audio', 'video')
)
ORDER BY actual_end_time DESC;
SELECT DISTINCT
a.*
FROM activities a
INNER JOIN tracks t ON a.id = t.activity_id
INNER JOIN users u ON a.user_id = u.id
INNER JOIN teams team ON u.team_id = team.id
WHERE
a.crm_configuration_id = 202
AND a.status IN ('completed', 'failed')
AND a.recording_state != 'stopped'
# and a.user_id = 14637
AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')
# AND t.type IN ('audio', 'video')
AND (
(a.actual_start_time BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59')
OR
(
a.actual_start_time IS NULL
AND a.type IN ('sms-outbound', 'sms-inbound')
AND a.created_at BETWEEN '2025-03-12 12:00:00' AND '2025-03-24 11:59:59'
)
)
AND (
a.is_private = 0
OR (
a.is_private = 1
AND a.user_id = 14637
)
)
ORDER BY a.actual_end_time DESC
;
SELECT DISTINCT a.*
FROM activities a
INNER JOIN users u ON a.user_id = u.id
INNER JOIN teams t ON u.team_id = t.id
# INNER JOIN tracks tr ON a.id = tr.activity_id
# INNER JOIN groups g ON u.group_id = g.id
WHERE 1=1
AND t.id = 267
# AND t.uuid = uuid_to_bin('aed4927b-f1ea-499e-94c3-83762fd233e8')
AND a.status IN ('completed', 'failed')
AND a.recording_state != 'stopped'
AND a.type IN ('softphone', 'softphone-inbound', 'conference', 'sms-inbound', 'sms-outbound')
# AND tr.type NOT IN ('audio', 'video')
AND (
a.is_private = 0
OR a.user_id = 14637
)
AND (
(a.actual_start_time BETWEEN '2025-03-19 00:00:00' AND '2025-03-21 23:59:59')
OR (
a.actual_start_time IS NULL
AND a.type IN ('sms-outbound', 'sms-inbound')
AND a.created_at BETWEEN '2025-03-19 00:00:00' AND '2025-03-21 23:59:59'
)
)
# and NOT EXISTS (
# SELECT 1
# FROM tracks t
# WHERE t.activity_id = a.id
# AND t.type IN ('audio', 'video')
# )
ORDER BY a.actual_end_time DESC;
SELECT * FROM tracks WHERE activity_id = 26485995;
select a.is_private, a.title, uuid_from_bin(a.uuid), a.external_id, a.status, a.recording_state, a.recording_reason_code, a.scheduled...
|
NULL
|
|
55618
|
NULL
|
0
|
2026-04-20T09:58:37.268287+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776679117268_m1.jpg...
|
PhpStorm
|
faVsco.js – BaseService.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#11976 on JY-20553-debug- Project: faVsco.js, menu
#11976 on JY-20553-debug-crm-sync-delays, menu
Start Listening for PHP Debug Connections
RequestGenerateAskJiminnyReportJobTest
Run 'RequestGenerateAskJiminnyReportJobTest'
Debug 'RequestGenerateAskJiminnyReportJobTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
1
19
2
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm;
use Illuminate\Support\Collection;
use Jiminny\Component\Transcription\Service\TranscriptionService;
use Jiminny\Contracts\Services\Crm\ClientInterface;
use Jiminny\Contracts\Services\Crm\ConnectionStateInterface;
use Jiminny\Contracts\Services\Crm\Provider\HubspotInterface;
use Jiminny\Contracts\Services\Crm\ServiceInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SupportsObjectTypeParseInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Exceptions\HttpBadRequestException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Integrations\PlaybookResolver;
use Jiminny\Jobs\Crm\SyncFieldMetadata;
use Jiminny\Models;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Crm\Layout;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\Crm\Helpers\ConnectionStateTrait;
use Jiminny\Services\Crm\Helpers\OpportunitySyncableFieldsTrait;
use Jiminny\Services\TeamService;
use Psr\Log\LoggerInterface;
use Sentry\State\Scope;
abstract class BaseService implements
ServiceInterface,
SettingsInterface,
SyncCrmEntitiesInterface,
ConnectionStateInterface
{
use ConnectionStateTrait;
use OpportunitySyncableFieldsTrait;
public const string OBJECT_LEAD = 'lead';
public const string OBJECT_ACCOUNT = 'account';
public const string OBJECT_CONTACT = 'contact';
public const string OBJECT_OPPORTUNITY = 'opportunity';
public const string OBJECT_TASK = 'task';
public const string OBJECT_EVENT = 'event';
public const int SOFT_DELETE_CHUNK = 100;
public const int HARD_DELETE_CHUNK = 1000;
public ?Configuration $config;
public ?Profile $profile;
public ?Team $team = null;
/**
* @var ClientInterface
*/
protected $client;
/**
* @var TeamService
*/
protected TeamService $teamService;
/**
* @var int
*/
protected int $limit;
/**
* @var int
*/
protected int $offset;
/**
* Transcription Service instance.
*
* @var TranscriptionService
*/
protected TranscriptionService $transcriptionService;
protected LoggerInterface $logger;
/**
* Cache for opportunity fields to avoid N+1 queries during batch imports.
* Key: crm_provider_id, Value: Field model with entities relation.
* Cleared when configuration changes.
*
* @var Collection<string, Field>|null
*/
private ?Collection $cachedOpportunityFields = null;
public function __construct()
{
$this->teamService = app(TeamService::class);
$this->transcriptionService = app(TranscriptionService::class);
$this->logger = app(LoggerInterface::class);
}
/**
* @param User $user
*
* @throws SocialAccountTokenInvalidException
*/
public function setUser(User $user): void
{
$this->configureSentryScope($user);
$this->team = $user->team;
$this->teamService->setTeam($user->team);
$this->setConfiguration($user->team->crm);
// Reset state.
$this->profile = $user->crmProfile;
/**
* DO NOT DELETE THIS `clearTokens` CALL
* The purpose of purging tokens is to fix a problem in importing calendar events.
* Calendar Import doesn't always respect "SocialAccountInvalidTokenException" exception
* and may try to recycle old SF instance, with wrong credentials (by ignoring the exception).
*
* This code guarantees the CRM Service is unusable, unless always provided with a valid social account.
*/
if (method_exists($this->client, 'clearTokens')) {
$this->client->clearTokens();
}
$account = $this->getOAuthAccount($user);
$this->validateUserAccountExists($user, $account);
if (method_exists($this->client, 'setOAuthAccount')) {
$this->client->setOAuthAccount($account);
}
if (method_exists($this->client, 'setLogger')) {
$this->client->setLogger($this->logger);
}
if ($this->profile === null) {
// Try to fetch their profile, maybe it was not yet imported?
$cacheKey = sprintf('crm_profile_sync-%s', $user->getId());
$lock = \Cache::lock($cacheKey, 300);
if ($lock->get()) {
$this->profile = $this->getProfile($user);
}
}
// The CRM Service is properly bootstrapped, and supports remote operations
$this->connect();
}
protected function configureSentryScope(User $user): void
{
\Sentry\configureScope(function (Scope $scope) use ($user): void {
$scope->setTag('team_id', (string) $user->getTeamId());
$scope->setUser([
'id' => $user->getId(),
'email' => $user->getEmailAddress(),
]);
});
}
/**
* @param User $user
*
* @return Profile|null
*/
protected function getProfile(User $user): ?Profile
{
return $this->syncProfiles($user);
}
public function getConfiguration(): Configuration
{
return $this->config;
}
public function setConfiguration(Configuration $config): void
{
$this->config = $config;
$this->client->setConfiguration($config);
// Clear field cache when configuration changes to ensure fresh data for new team/config
$this->cachedOpportunityFields = null;
if ($this->team === null) {
$this->team = $config->team;
}
}
public function setPage(int $limit, int $offset): void
{
$this->limit = $limit;
$this->offset = $offset;
}
abstract protected function getOAuthAccount(User $user): ?SocialAccount;
abstract protected function getDefaultFollowupLayoutFields(string $activityType): array;
abstract protected function getFieldTypes(): array;
abstract protected function getFields(string $fieldType): array;
public function syncFields(): void
{
foreach ($this->getFieldTypes() as $fieldType) {
$currentFields = $this->getFields($fieldType);
// TODO: only sync the field once a day if we don't use it in any layout. If we do, sync hourly?
foreach ($currentFields as $field) {
/** @var Models\Crm\Field $field */
$field = $this->config->fields()->updateOrCreate([
'crm_provider_id' => mb_strimwidth($field['name'], 0, 128),
'object_type' => $fieldType,
], [
'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),
]);
try {
$this->syncField($field);
if ($field->type === Models\Crm\Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
} catch (HttpNotFoundException $e) {
$this->logger->error('[sync-fields] Field not found', [
'provider' => $this->getDisplayName(),
'crm_field' => $field->crm_provider_id,
'object_type' => $field->object_type,
'team_id' => $this->team->id,
]);
} catch (HttpBadRequestException $e) {
$this->logger->error('[sync-fields] Field not supported', [
'provider' => $this->getDisplayName(),
'crm_field' => $field->crm_provider_id,
'object_type' => $field->object_type,
'team_id' => $this->team->id,
]);
}
}
}
}
/**
* @param string $objectId
* @param ?string $objectType
*
* @return array
*/
public function parseRecords(string $objectId, ?string $objectType = null): array
{
if ($objectType === null && $this instanceof SupportsObjectTypeParseInterface) {
$objectType = $this->parseObjectType($objectId);
}
$lead = null;
$contact = null;
$opportunity = null;
$account = null;
$stage = null;
$countryCode = null;
// Gather the prospect data to store on activity/participant.
switch ($objectType) {
case self::OBJECT_LEAD:
/** @var ?Lead $lead */
$lead = $this->config->leads()->where('crm_provider_id', $objectId)->first();
if ($lead === null) {
$lead = $this->syncLead($objectId);
}
if ($lead?->country_code) {
$countryCode = $lead->country_code;
}
$stage = $lead?->stage;
break;
case self::OBJECT_ACCOUNT:
$account = $this->config->accounts()->where('crm_provider_id', $objectId)->first();
if ($account === null) {
$account = $this->syncAccount($objectId);
}
if ($account->country_code) {
$countryCode = $account->country_code;
}
break;
case self::OBJECT_CONTACT:
$contact = $this->config->contacts()->where('crm_provider_id', $objectId)->first();
if ($contact === null) {
$contact = $this->syncContact($objectId);
}
if ($contact?->country_code) {
$countryCode = $contact->country_code;
}
$account = $contact?->account;
break;
case self::OBJECT_OPPORTUNITY:
$opportunity = $this->config->opportunities()->where('crm_provider_id', $objectId)->first();
if ($opportunity === null) {
$opportunity = $this->syncOpportunity($objectId);
}
if ($opportunity !== null) {
$stage = $opportunity->stage;
$account = $opportunity->account;
if ($account->country_code) {
$countryCode = $account->country_code;
}
}
break;
}
return [
$lead,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
/**
* @param null|string $name
*
* @return null|string
*/
public function convertCountryNameToCode(?string $name): ?string
{
return app(CountryCodeResolver::class)->resolveCountryCode($name);
}
/**
* @param PlaybookCategory $category
*
* @return bool
*/
public function matchesCrmType(PlaybookCategory $category): bool
{
if ($category->playbook === null) {
return false;
}
if ($category->getPlaybook()->getActivityField() === null) {
return false;
}
$fieldValue = $category
->playbook
->activityField
->values()
->where('label', $category->name);
// Check the field values for a matching option.
return $fieldValue->exists();
}
/**
* @param PlaybookCategory $category
*
* @return FieldValue|null
*/
public function getCrmType(PlaybookCategory $category): ?FieldValue
{
$fieldValue = $category
->playbook
->activityField
->values()
->where('label', $category->name);
return $fieldValue->first();
}
/**
* @return int|float|string
*/
public function getMinimumApiVersion(): int|float|string
{
return $this->client->getMinimumApiVersion();
}
/**
* @param string $accountId
*
* @return bool
*/
protected function hasAccount(string $accountId): bool
{
return $this->config->accounts()->where('crm_provider_id', $accountId)->exists();
}
/**
* @param string $opportunityId
*
* @return bool
*/
protected function hasOpportunity(string $opportunityId): bool
{
return $this->config->opportunities()->where('crm_provider_id', $opportunityId)->exists();
}
/**
* @param string $contactId
*
* @return bool
*/
protected function hasContact(string $contactId): bool
{
return $this->config->contacts()->where('crm_provider_id', $contactId)->exists();
}
/**
* @param string $leadId
*
* @return bool
*/
protected function hasLead(string $leadId): bool
{
return $this->config->leads()->where('crm_provider_id', $leadId)->exists();
}
public function fetchAndAssociateRelatedActivity(Activity $activity): ?Activity
{
return null;
}
public function getJobDelay(): int
{
return 0;
}
public function getPlaybookFromActivity(Activity $activity): ?Playbook
{
if ($activity->hasActivityType() && $activity->getActivityType()->hasPlaybook()) {
return $activity->getActivityType()->getPlaybook();
}
return $this->getPlaybook($activity->getUser());
}
/**
* Gets the playbook for the user
*/
protected function getPlaybook(User $user): ?Playbook
{
$playbookResolver = app(PlaybookResolver::class);
return $playbookResolver->resolvePlaybookByUser($user);
}
/**
* @param Models\Playbook $playbook
* @param string $categoryName
*
* @return Models\PlaybookCategory|null
*/
protected function getPlaybookCategory(Models\Playbook $playbook, string $categoryName): ?Models\PlaybookCategory
{
return $playbook->categories()
->where('name', trim($categoryName))
->latest()
->first();
}
public function buildLayout(Layout $layout, ?string $activityType): void
{
if ($activityType) {
// Base section. Currently, the fields within are hard coded so this is empty for now.
/** @var Models\Crm\LayoutEntity $activitySection */
$activitySection = $layout->entities()->create([
'label' => 'activity-summary',
'description' => 'Activity Summary',
'sequence' => 0,
]);
if ($this instanceof HubspotInterface) {
$activityFields = $this->getDefaultActivityLayoutFields($activityType, $layout->type);
foreach ($activityFields as $i => $field) {
$layout->entities()->create([
'parent_entity_id' => $activitySection->getId(),
'crm_field_id' => $field->getId(),
'sequence' => $i,
]);
}
}
// Follow-up section. These are all dynamic fields.
$sectionTitle = ($layout->type === Layout::TYPE_CONFERENCE_SUMMARY ? 'Next Steps...' : 'Follow up?');
/** @var Models\Crm\LayoutEntity $followupSection */
$followupSection = $layout->entities()->create([
'label' => 'follow-up',
'description' => $sectionTitle,
'sequence' => 1,
]);
$followupFields = $this->getDefaultFollowupLayoutFields($activityType);
foreach ($followupFields as $i => $field) {
$layout->entities()->create([
'parent_entity_id' => $followupSection->getId(),
'crm_field_id' => $field->getId(),
'sequence' => $i,
]);
}
} elseif ($layout->type == Layout::TYPE_DEAL_INSIGHTS) {
$this->populateLayoutEntities($layout);
}
}
protected function populateLayoutEntities(Layout $layout): void
{
$dealFields = $this->getDefaultDealLayoutFields();
foreach ($dealFields as $i => $field) {
$readOnly = $field->getType() === Field::TYPE_CURRENCY
|| $this->isBusinessTypeField($field);
$layout->entities()->updateOrCreate([
'crm_field_id' => $field->id,
], [
'sequence' => $i,
'read_only' => $readOnly,
]);
}
}
public function prepareValueForUpdate(array $params): array
{
$fieldName = $params['fieldName'];
$fieldValue = $params['fieldValue'];
return [$fieldName => $fieldValue];
}
protected function getDefaultDealLayoutFields(): array
{
$fieldData = $this->getDealInsightsFields();
$fields = [];
foreach ($fieldData as $data) {
/** @var Field $field */
$field = $this->config->fields()->updateOrCreate([
'crm_provider_id' => $data['crm_provider_id'],
'object_type' => $data['object_type'],
], ['label' => $data['crm_provider_id']]);
try {
dispatch_sync(new SyncFieldMetadata($this->config->team, $field));
$field->refresh();
} catch (\Throwable $throwable) {
\Sentry::captureException($throwable);
}
$fields[] = $field;
}
return $fields;
}
public function importOpportunityCrmFieldData(array $crmData, array $crmFields, int $opportunityId): void
{
// Pre-fetch all opportunity fields once per batch to avoid N+1 queries.
// During webhook floods, this reduces DB queries from O(fields × deals) to O(1) for field lookups.
$fieldsMap = $this->getOpportunityFieldsMap();
foreach ($crmFields as $fieldName) {
$field = $fieldsMap->get($fieldName);
if (! $field instanceof Field) {
$this->logger->warning('Field not found', [
'field' => $fieldName,
'opportunity_id' => $opportunityId,
]);
continue;
}
// A CRM field data will be synced only if the field exists as part of at least one layout,
// i.e. an entity related to the field exists.
$entity = $field->entities->first();
if (! $entity instanceof Models\Crm\LayoutEntity) {
continue;
}
$fieldValue = $crmData[$fieldName] ?? '';
if (is_object($fieldValue)) {
$this->logger->warning('Field value is an object', [
'field' => $fieldName,
]);
continue;
}
$value = $this->normalizeValue($field->type, $fieldValue, true);
FieldData::updateOrCreate([
'crm_layout_entity_id' => $entity->id,
'crm_field_id' => $field->id,
'object_type' => 'opportunity',
'object_id' => $opportunityId,
], ['value' => $value]);
}
}
/**
* Get cached opportunity fields map for efficient lookups during batch imports.
*
* This method fetches all opportunity fields with their entities relation ONCE
* and caches them for the lifetime of this service instance. This eliminates
* the N+1 query problem where each field was fetched individually per deal.
*
* Performance impact:
* - Before: 10 fields × 100 deals = 1,000 field queries per batch
* - After: 1 query per batch (regardless of deal count)
*
* @return Collection<string, Field> Fields keyed by crm_provider_id
*/
private function getOpportunityFieldsMap(): Collection
{
if ($this->cachedOpportunityFields === null) {
$this->cachedOpportunityFields = $this->config->fields()
->with('entities')
->where('object_type', '=', self::OBJECT_OPPORTUNITY)
->get()
->keyBy('crm_provider_id');
}
return $this->cachedOpportunityFields;
}
/**
* @param array<mixed> $crmData
* @param Collection $crmFields
* @param int $objectId
*
* @return void
*/
public function importCrmFieldData(array $crmData, Collection $crmFields, int $objectId): void
{
/** @var Field $crmField */
foreach ($crmFields as $crmField) {
// If the field name does not match one we are interested in, skip.
if (array_key_exists($crmField->crm_provider_id, $crmData) === false) {
continue;
}
/** @var string $fieldValue */
$fieldValue = $crmData[$crmField->crm_provider_id];
$value = $this->normalizeValue($crmField->type, $fieldValue, true);
FieldData::updateOrCreate([
'crm_field_id' => $crmField->id,
'object_type' => $crmField->object_type,
'object_id' => $objectId,
], ['value' => $value]);
}
}
protected function getTeam(): Team
{
if (! $this->team instanceof Team) {
throw new LogicException('Expecting team model instance');
}
return $this->team;
}
public function isBusinessTypeField(Field $field): bool
{
return in_array($field->crm_provider_id, Field::BUSINESS_TYPE_FIELDS)
&& $field->object_type === Field::OBJECT_OPPORTUNITY;
}
/**
* @return mixed[]
*/
public function fetchRelatedActivity(Activity $activity): array
{
return [];
}
/**
* @throws SocialAccountTokenInvalidException
*/
private function validateUserAccountExists(User $user, ?SocialAccount $account = null): void
{
if ($account instanceof SocialAccount && $account->state === SocialAccount::STATE_CONNECTED) {
return;
}
$this->logger->warning(
sprintf('[%s] Account not connected for user', $this->getDisplayName()),
[
'userId' => $user->getIdString(),
'account' => $account,
]
);
// If their profile was never setup in the first place
if ($this->profile === null) {
// Create a dummy in-memory profile just to be able to run
$this->profile = new Profile();
}
if (! $account instanceof SocialAccount) {
throw new SocialAccountTokenInvalidException(
sprintf(
'Social account for %s cannot be found. Please login to Jiminny to connect.',
$this->getDisplayName()
)
);
}
throw new SocialAccountTokenInvalidException(
sprintf(
'Your %s account has become disconnected. Please login to Jiminny to reconnect.',
$this->getDisplayName()
)
);
}
public function listSupportedObjectTypes(): array
{
return $this->getFieldTypes();
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
6
1
6
Previous Highlighted Error
Next Highlighted Error
# [PASSWORD_DOTS] HS [PASSWORD_DOTS]
select * from teams where id = 2; # 2
select * from features; # 2
select * from team_features where team_id = 2; # 2
select * from crm_configurations where id = 2; # 2
select * from users where team_id = 2; #
select * from playbooks where team_id = 2; # event 38
select * from playbook_categories where playbook_id = 38; #
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;
https://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624
https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0
SELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;
# 609126 softphone tr. 11241
SELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;
# 608874 conference tr. 11226 crmId: 103422236596
select * from ai_prompts where transcription_id IN (11241, 11226);
select * from activity_summary_logs where activity_id = 608874;
select * from sidekick_settings;
select * from default_activity_types;
select * from crm_field_data where activity_id = 1223;
select * from crm_layouts where crm_configuration_id = 2;
SELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);
select * from crm_fields where crm_configuration_id = 11 and object_type = 'event';
SELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);
SELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;
SELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u
on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 2 and sa.provider = 'hubspot';
select * from opportunities where team_id = 2
and crm_provider_id IN ('51317301383');
select * from contacts where id = 85;
select * from opportunities where team_id = 2 order by id desc;
select * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112
select * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112
select * from opportunity_contacts where opportunity_id = 5117;
select * from crm_field_data where object_id = 1365;
SELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);
select * from features;
select * from team_features where team_id IN (1);
select * from team_features where feature_id IN (36);
SHOW CREATE TABLE opportunity_contacts;
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';
# $slug = 'HUBSPOT_WEBHOOK_SYNC';
# $team = Jiminny\Models\Team::find(2);
# $feature = Feature::query()->where('slug', $slug)->first();
# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);
# hubspot_webhook_metrics
select * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365
SELECT * FROM opportunity_contacts WHERE opportunity_id = '414';
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';
select * from contacts where id in (414, 464);
select * from activities where crm_configuration_id = 2;
select settings from crm_configurations where id = 11;
select * from teams; # 1, 2
select * from users;
select * from crm_configurations where id = 39;
select * from team_features where team_id = 2;
select * from features;
# SELECT * FROM opportunities WHERE crm_configuration_id = 2
# order by id desc;
# and crm_provider_id = '49908861993';
select * from activity_providers where id IN (443, 202, 203, 227);
select * from activity_imports where id = 795889;
select c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id
where c.provider = 'hubspot';
select * from crm_configurations crm JOIN teams t on crm.team_id = t.id
where provider = 'hubspot';
SELECT * FROM teams WHERE id = 31;
SELECT * FROM users WHERE id = 257;
SELECT * FROM opportunities WHERE team_id = 2;
select * from opportunity_contacts where opportunity_id = 5124;
select * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)
select * from activities where crm_configuration_id = 13;
SELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141
select id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;
SELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;
SELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;
SELECT * FROM contacts WHERE team_id = 2 order by id desc;
select * from opportunity_contacts where contact_id = 6223;
SELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;
select * from crm_profiles where crm_configuration_id = 2;
select * from activities where account_id = 46;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11976 on JY-20553-debug-crm-sync-delays, menu","depth":5,"help_text":"Pull request #11976 exists for current branch JY-20553-debug-crm-sync-delays","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"RequestGenerateAskJiminnyReportJobTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'RequestGenerateAskJiminnyReportJobTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'RequestGenerateAskJiminnyReportJobTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"19","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Crm;\n\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Component\\Transcription\\Service\\TranscriptionService;\nuse Jiminny\\Contracts\\Services\\Crm\\ClientInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\ConnectionStateInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\HubspotInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SupportsObjectTypeParseInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Exceptions\\HttpBadRequestException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Integrations\\PlaybookResolver;\nuse Jiminny\\Jobs\\Crm\\SyncFieldMetadata;\nuse Jiminny\\Models;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Crm\\Layout;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Crm\\Helpers\\ConnectionStateTrait;\nuse Jiminny\\Services\\Crm\\Helpers\\OpportunitySyncableFieldsTrait;\nuse Jiminny\\Services\\TeamService;\nuse Psr\\Log\\LoggerInterface;\nuse Sentry\\State\\Scope;\n\nabstract class BaseService implements\n ServiceInterface,\n SettingsInterface,\n SyncCrmEntitiesInterface,\n ConnectionStateInterface\n{\n use ConnectionStateTrait;\n use OpportunitySyncableFieldsTrait;\n\n public const string OBJECT_LEAD = 'lead';\n public const string OBJECT_ACCOUNT = 'account';\n public const string OBJECT_CONTACT = 'contact';\n public const string OBJECT_OPPORTUNITY = 'opportunity';\n public const string OBJECT_TASK = 'task';\n public const string OBJECT_EVENT = 'event';\n\n public const int SOFT_DELETE_CHUNK = 100;\n public const int HARD_DELETE_CHUNK = 1000;\n\n public ?Configuration $config;\n\n public ?Profile $profile;\n\n public ?Team $team = null;\n\n /**\n * @var ClientInterface\n */\n protected $client;\n\n /**\n * @var TeamService\n */\n protected TeamService $teamService;\n\n /**\n * @var int\n */\n protected int $limit;\n\n /**\n * @var int\n */\n protected int $offset;\n\n /**\n * Transcription Service instance.\n *\n * @var TranscriptionService\n */\n protected TranscriptionService $transcriptionService;\n\n protected LoggerInterface $logger;\n\n /**\n * Cache for opportunity fields to avoid N+1 queries during batch imports.\n * Key: crm_provider_id, Value: Field model with entities relation.\n * Cleared when configuration changes.\n *\n * @var Collection<string, Field>|null\n */\n private ?Collection $cachedOpportunityFields = null;\n\n public function __construct()\n {\n $this->teamService = app(TeamService::class);\n $this->transcriptionService = app(TranscriptionService::class);\n $this->logger = app(LoggerInterface::class);\n }\n\n /**\n * @param User $user\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function setUser(User $user): void\n {\n $this->configureSentryScope($user);\n\n $this->team = $user->team;\n $this->teamService->setTeam($user->team);\n $this->setConfiguration($user->team->crm);\n\n // Reset state.\n $this->profile = $user->crmProfile;\n\n /**\n * DO NOT DELETE THIS `clearTokens` CALL\n * The purpose of purging tokens is to fix a problem in importing calendar events.\n * Calendar Import doesn't always respect \"SocialAccountInvalidTokenException\" exception\n * and may try to recycle old SF instance, with wrong credentials (by ignoring the exception).\n *\n * This code guarantees the CRM Service is unusable, unless always provided with a valid social account.\n */\n if (method_exists($this->client, 'clearTokens')) {\n $this->client->clearTokens();\n }\n\n $account = $this->getOAuthAccount($user);\n\n $this->validateUserAccountExists($user, $account);\n\n if (method_exists($this->client, 'setOAuthAccount')) {\n $this->client->setOAuthAccount($account);\n }\n if (method_exists($this->client, 'setLogger')) {\n $this->client->setLogger($this->logger);\n }\n\n if ($this->profile === null) {\n // Try to fetch their profile, maybe it was not yet imported?\n $cacheKey = sprintf('crm_profile_sync-%s', $user->getId());\n $lock = \\Cache::lock($cacheKey, 300);\n if ($lock->get()) {\n $this->profile = $this->getProfile($user);\n }\n }\n\n // The CRM Service is properly bootstrapped, and supports remote operations\n $this->connect();\n }\n\n protected function configureSentryScope(User $user): void\n {\n \\Sentry\\configureScope(function (Scope $scope) use ($user): void {\n $scope->setTag('team_id', (string) $user->getTeamId());\n $scope->setUser([\n 'id' => $user->getId(),\n 'email' => $user->getEmailAddress(),\n ]);\n });\n }\n\n /**\n * @param User $user\n *\n * @return Profile|null\n */\n protected function getProfile(User $user): ?Profile\n {\n return $this->syncProfiles($user);\n }\n\n public function getConfiguration(): Configuration\n {\n return $this->config;\n }\n\n public function setConfiguration(Configuration $config): void\n {\n $this->config = $config;\n $this->client->setConfiguration($config);\n\n // Clear field cache when configuration changes to ensure fresh data for new team/config\n $this->cachedOpportunityFields = null;\n\n if ($this->team === null) {\n $this->team = $config->team;\n }\n }\n\n public function setPage(int $limit, int $offset): void\n {\n $this->limit = $limit;\n $this->offset = $offset;\n }\n\n abstract protected function getOAuthAccount(User $user): ?SocialAccount;\n abstract protected function getDefaultFollowupLayoutFields(string $activityType): array;\n abstract protected function getFieldTypes(): array;\n abstract protected function getFields(string $fieldType): array;\n\n public function syncFields(): void\n {\n foreach ($this->getFieldTypes() as $fieldType) {\n $currentFields = $this->getFields($fieldType);\n\n // TODO: only sync the field once a day if we don't use it in any layout. If we do, sync hourly?\n foreach ($currentFields as $field) {\n /** @var Models\\Crm\\Field $field */\n $field = $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => mb_strimwidth($field['name'], 0, 128),\n 'object_type' => $fieldType,\n ], [\n 'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),\n ]);\n\n try {\n $this->syncField($field);\n\n if ($field->type === Models\\Crm\\Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n } catch (HttpNotFoundException $e) {\n $this->logger->error('[sync-fields] Field not found', [\n 'provider' => $this->getDisplayName(),\n 'crm_field' => $field->crm_provider_id,\n 'object_type' => $field->object_type,\n 'team_id' => $this->team->id,\n ]);\n } catch (HttpBadRequestException $e) {\n $this->logger->error('[sync-fields] Field not supported', [\n 'provider' => $this->getDisplayName(),\n 'crm_field' => $field->crm_provider_id,\n 'object_type' => $field->object_type,\n 'team_id' => $this->team->id,\n ]);\n }\n }\n }\n }\n\n /**\n * @param string $objectId\n * @param ?string $objectType\n *\n * @return array\n */\n public function parseRecords(string $objectId, ?string $objectType = null): array\n {\n if ($objectType === null && $this instanceof SupportsObjectTypeParseInterface) {\n $objectType = $this->parseObjectType($objectId);\n }\n\n $lead = null;\n $contact = null;\n $opportunity = null;\n $account = null;\n $stage = null;\n $countryCode = null;\n\n // Gather the prospect data to store on activity/participant.\n switch ($objectType) {\n case self::OBJECT_LEAD:\n /** @var ?Lead $lead */\n $lead = $this->config->leads()->where('crm_provider_id', $objectId)->first();\n\n if ($lead === null) {\n $lead = $this->syncLead($objectId);\n }\n\n if ($lead?->country_code) {\n $countryCode = $lead->country_code;\n }\n\n $stage = $lead?->stage;\n\n break;\n\n case self::OBJECT_ACCOUNT:\n $account = $this->config->accounts()->where('crm_provider_id', $objectId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($objectId);\n }\n\n if ($account->country_code) {\n $countryCode = $account->country_code;\n }\n\n break;\n\n case self::OBJECT_CONTACT:\n $contact = $this->config->contacts()->where('crm_provider_id', $objectId)->first();\n\n if ($contact === null) {\n $contact = $this->syncContact($objectId);\n }\n\n if ($contact?->country_code) {\n $countryCode = $contact->country_code;\n }\n\n $account = $contact?->account;\n\n break;\n\n case self::OBJECT_OPPORTUNITY:\n $opportunity = $this->config->opportunities()->where('crm_provider_id', $objectId)->first();\n\n if ($opportunity === null) {\n $opportunity = $this->syncOpportunity($objectId);\n }\n\n if ($opportunity !== null) {\n $stage = $opportunity->stage;\n\n $account = $opportunity->account;\n\n if ($account->country_code) {\n $countryCode = $account->country_code;\n }\n }\n\n break;\n }\n\n return [\n $lead,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n /**\n * @param null|string $name\n *\n * @return null|string\n */\n public function convertCountryNameToCode(?string $name): ?string\n {\n return app(CountryCodeResolver::class)->resolveCountryCode($name);\n }\n\n /**\n * @param PlaybookCategory $category\n *\n * @return bool\n */\n public function matchesCrmType(PlaybookCategory $category): bool\n {\n if ($category->playbook === null) {\n return false;\n }\n\n if ($category->getPlaybook()->getActivityField() === null) {\n return false;\n }\n\n $fieldValue = $category\n ->playbook\n ->activityField\n ->values()\n ->where('label', $category->name);\n\n // Check the field values for a matching option.\n return $fieldValue->exists();\n }\n\n /**\n * @param PlaybookCategory $category\n *\n * @return FieldValue|null\n */\n public function getCrmType(PlaybookCategory $category): ?FieldValue\n {\n $fieldValue = $category\n ->playbook\n ->activityField\n ->values()\n ->where('label', $category->name);\n\n return $fieldValue->first();\n }\n\n\n /**\n * @return int|float|string\n */\n public function getMinimumApiVersion(): int|float|string\n {\n return $this->client->getMinimumApiVersion();\n }\n\n /**\n * @param string $accountId\n *\n * @return bool\n */\n protected function hasAccount(string $accountId): bool\n {\n return $this->config->accounts()->where('crm_provider_id', $accountId)->exists();\n }\n\n /**\n * @param string $opportunityId\n *\n * @return bool\n */\n protected function hasOpportunity(string $opportunityId): bool\n {\n return $this->config->opportunities()->where('crm_provider_id', $opportunityId)->exists();\n }\n\n /**\n * @param string $contactId\n *\n * @return bool\n */\n protected function hasContact(string $contactId): bool\n {\n return $this->config->contacts()->where('crm_provider_id', $contactId)->exists();\n }\n\n /**\n * @param string $leadId\n *\n * @return bool\n */\n protected function hasLead(string $leadId): bool\n {\n return $this->config->leads()->where('crm_provider_id', $leadId)->exists();\n }\n\n public function fetchAndAssociateRelatedActivity(Activity $activity): ?Activity\n {\n return null;\n }\n\n public function getJobDelay(): int\n {\n return 0;\n }\n\n public function getPlaybookFromActivity(Activity $activity): ?Playbook\n {\n if ($activity->hasActivityType() && $activity->getActivityType()->hasPlaybook()) {\n return $activity->getActivityType()->getPlaybook();\n }\n\n return $this->getPlaybook($activity->getUser());\n }\n\n /**\n * Gets the playbook for the user\n */\n protected function getPlaybook(User $user): ?Playbook\n {\n $playbookResolver = app(PlaybookResolver::class);\n\n return $playbookResolver->resolvePlaybookByUser($user);\n }\n\n /**\n * @param Models\\Playbook $playbook\n * @param string $categoryName\n *\n * @return Models\\PlaybookCategory|null\n */\n protected function getPlaybookCategory(Models\\Playbook $playbook, string $categoryName): ?Models\\PlaybookCategory\n {\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->latest()\n ->first();\n }\n\n public function buildLayout(Layout $layout, ?string $activityType): void\n {\n if ($activityType) {\n // Base section. Currently, the fields within are hard coded so this is empty for now.\n /** @var Models\\Crm\\LayoutEntity $activitySection */\n $activitySection = $layout->entities()->create([\n 'label' => 'activity-summary',\n 'description' => 'Activity Summary',\n 'sequence' => 0,\n ]);\n\n if ($this instanceof HubspotInterface) {\n $activityFields = $this->getDefaultActivityLayoutFields($activityType, $layout->type);\n\n foreach ($activityFields as $i => $field) {\n $layout->entities()->create([\n 'parent_entity_id' => $activitySection->getId(),\n 'crm_field_id' => $field->getId(),\n 'sequence' => $i,\n ]);\n }\n }\n\n // Follow-up section. These are all dynamic fields.\n $sectionTitle = ($layout->type === Layout::TYPE_CONFERENCE_SUMMARY ? 'Next Steps...' : 'Follow up?');\n /** @var Models\\Crm\\LayoutEntity $followupSection */\n $followupSection = $layout->entities()->create([\n 'label' => 'follow-up',\n 'description' => $sectionTitle,\n 'sequence' => 1,\n ]);\n\n $followupFields = $this->getDefaultFollowupLayoutFields($activityType);\n\n foreach ($followupFields as $i => $field) {\n $layout->entities()->create([\n 'parent_entity_id' => $followupSection->getId(),\n 'crm_field_id' => $field->getId(),\n 'sequence' => $i,\n ]);\n }\n } elseif ($layout->type == Layout::TYPE_DEAL_INSIGHTS) {\n $this->populateLayoutEntities($layout);\n }\n }\n\n protected function populateLayoutEntities(Layout $layout): void\n {\n $dealFields = $this->getDefaultDealLayoutFields();\n\n foreach ($dealFields as $i => $field) {\n $readOnly = $field->getType() === Field::TYPE_CURRENCY\n || $this->isBusinessTypeField($field);\n\n $layout->entities()->updateOrCreate([\n 'crm_field_id' => $field->id,\n ], [\n 'sequence' => $i,\n 'read_only' => $readOnly,\n ]);\n }\n }\n\n public function prepareValueForUpdate(array $params): array\n {\n $fieldName = $params['fieldName'];\n $fieldValue = $params['fieldValue'];\n\n return [$fieldName => $fieldValue];\n }\n\n protected function getDefaultDealLayoutFields(): array\n {\n $fieldData = $this->getDealInsightsFields();\n\n $fields = [];\n foreach ($fieldData as $data) {\n /** @var Field $field */\n $field = $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => $data['crm_provider_id'],\n 'object_type' => $data['object_type'],\n ], ['label' => $data['crm_provider_id']]);\n\n try {\n dispatch_sync(new SyncFieldMetadata($this->config->team, $field));\n $field->refresh();\n } catch (\\Throwable $throwable) {\n \\Sentry::captureException($throwable);\n }\n\n $fields[] = $field;\n }\n\n return $fields;\n }\n\n public function importOpportunityCrmFieldData(array $crmData, array $crmFields, int $opportunityId): void\n {\n // Pre-fetch all opportunity fields once per batch to avoid N+1 queries.\n // During webhook floods, this reduces DB queries from O(fields × deals) to O(1) for field lookups.\n $fieldsMap = $this->getOpportunityFieldsMap();\n\n foreach ($crmFields as $fieldName) {\n $field = $fieldsMap->get($fieldName);\n\n if (! $field instanceof Field) {\n $this->logger->warning('Field not found', [\n 'field' => $fieldName,\n 'opportunity_id' => $opportunityId,\n ]);\n\n continue;\n }\n\n // A CRM field data will be synced only if the field exists as part of at least one layout,\n // i.e. an entity related to the field exists.\n $entity = $field->entities->first();\n if (! $entity instanceof Models\\Crm\\LayoutEntity) {\n continue;\n }\n\n $fieldValue = $crmData[$fieldName] ?? '';\n\n if (is_object($fieldValue)) {\n $this->logger->warning('Field value is an object', [\n 'field' => $fieldName,\n ]);\n\n continue;\n }\n\n $value = $this->normalizeValue($field->type, $fieldValue, true);\n\n FieldData::updateOrCreate([\n 'crm_layout_entity_id' => $entity->id,\n 'crm_field_id' => $field->id,\n 'object_type' => 'opportunity',\n 'object_id' => $opportunityId,\n ], ['value' => $value]);\n }\n }\n\n /**\n * Get cached opportunity fields map for efficient lookups during batch imports.\n *\n * This method fetches all opportunity fields with their entities relation ONCE\n * and caches them for the lifetime of this service instance. This eliminates\n * the N+1 query problem where each field was fetched individually per deal.\n *\n * Performance impact:\n * - Before: 10 fields × 100 deals = 1,000 field queries per batch\n * - After: 1 query per batch (regardless of deal count)\n *\n * @return Collection<string, Field> Fields keyed by crm_provider_id\n */\n private function getOpportunityFieldsMap(): Collection\n {\n if ($this->cachedOpportunityFields === null) {\n $this->cachedOpportunityFields = $this->config->fields()\n ->with('entities')\n ->where('object_type', '=', self::OBJECT_OPPORTUNITY)\n ->get()\n ->keyBy('crm_provider_id');\n }\n\n return $this->cachedOpportunityFields;\n }\n\n /**\n * @param array<mixed> $crmData\n * @param Collection $crmFields\n * @param int $objectId\n *\n * @return void\n */\n public function importCrmFieldData(array $crmData, Collection $crmFields, int $objectId): void\n {\n /** @var Field $crmField */\n foreach ($crmFields as $crmField) {\n // If the field name does not match one we are interested in, skip.\n if (array_key_exists($crmField->crm_provider_id, $crmData) === false) {\n continue;\n }\n\n /** @var string $fieldValue */\n $fieldValue = $crmData[$crmField->crm_provider_id];\n\n $value = $this->normalizeValue($crmField->type, $fieldValue, true);\n\n FieldData::updateOrCreate([\n 'crm_field_id' => $crmField->id,\n 'object_type' => $crmField->object_type,\n 'object_id' => $objectId,\n ], ['value' => $value]);\n }\n }\n\n protected function getTeam(): Team\n {\n if (! $this->team instanceof Team) {\n throw new LogicException('Expecting team model instance');\n }\n\n return $this->team;\n }\n\n public function isBusinessTypeField(Field $field): bool\n {\n return in_array($field->crm_provider_id, Field::BUSINESS_TYPE_FIELDS)\n && $field->object_type === Field::OBJECT_OPPORTUNITY;\n }\n\n /**\n * @return mixed[]\n */\n public function fetchRelatedActivity(Activity $activity): array\n {\n return [];\n }\n\n /**\n * @throws SocialAccountTokenInvalidException\n */\n private function validateUserAccountExists(User $user, ?SocialAccount $account = null): void\n {\n if ($account instanceof SocialAccount && $account->state === SocialAccount::STATE_CONNECTED) {\n return;\n }\n\n $this->logger->warning(\n sprintf('[%s] Account not connected for user', $this->getDisplayName()),\n [\n 'userId' => $user->getIdString(),\n 'account' => $account,\n ]\n );\n\n // If their profile was never setup in the first place\n if ($this->profile === null) {\n // Create a dummy in-memory profile just to be able to run\n $this->profile = new Profile();\n }\n\n if (! $account instanceof SocialAccount) {\n throw new SocialAccountTokenInvalidException(\n sprintf(\n 'Social account for %s cannot be found. Please login to Jiminny to connect.',\n $this->getDisplayName()\n )\n );\n }\n\n throw new SocialAccountTokenInvalidException(\n sprintf(\n 'Your %s account has become disconnected. Please login to Jiminny to reconnect.',\n $this->getDisplayName()\n )\n );\n }\n\n public function listSupportedObjectTypes(): array\n {\n return $this->getFieldTypes();\n }\n}","depth":4,"value":"<?php\n\nnamespace Jiminny\\Services\\Crm;\n\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Component\\Transcription\\Service\\TranscriptionService;\nuse Jiminny\\Contracts\\Services\\Crm\\ClientInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\ConnectionStateInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\HubspotInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SupportsObjectTypeParseInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Exceptions\\HttpBadRequestException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Integrations\\PlaybookResolver;\nuse Jiminny\\Jobs\\Crm\\SyncFieldMetadata;\nuse Jiminny\\Models;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Crm\\Layout;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Crm\\Helpers\\ConnectionStateTrait;\nuse Jiminny\\Services\\Crm\\Helpers\\OpportunitySyncableFieldsTrait;\nuse Jiminny\\Services\\TeamService;\nuse Psr\\Log\\LoggerInterface;\nuse Sentry\\State\\Scope;\n\nabstract class BaseService implements\n ServiceInterface,\n SettingsInterface,\n SyncCrmEntitiesInterface,\n ConnectionStateInterface\n{\n use ConnectionStateTrait;\n use OpportunitySyncableFieldsTrait;\n\n public const string OBJECT_LEAD = 'lead';\n public const string OBJECT_ACCOUNT = 'account';\n public const string OBJECT_CONTACT = 'contact';\n public const string OBJECT_OPPORTUNITY = 'opportunity';\n public const string OBJECT_TASK = 'task';\n public const string OBJECT_EVENT = 'event';\n\n public const int SOFT_DELETE_CHUNK = 100;\n public const int HARD_DELETE_CHUNK = 1000;\n\n public ?Configuration $config;\n\n public ?Profile $profile;\n\n public ?Team $team = null;\n\n /**\n * @var ClientInterface\n */\n protected $client;\n\n /**\n * @var TeamService\n */\n protected TeamService $teamService;\n\n /**\n * @var int\n */\n protected int $limit;\n\n /**\n * @var int\n */\n protected int $offset;\n\n /**\n * Transcription Service instance.\n *\n * @var TranscriptionService\n */\n protected TranscriptionService $transcriptionService;\n\n protected LoggerInterface $logger;\n\n /**\n * Cache for opportunity fields to avoid N+1 queries during batch imports.\n * Key: crm_provider_id, Value: Field model with entities relation.\n * Cleared when configuration changes.\n *\n * @var Collection<string, Field>|null\n */\n private ?Collection $cachedOpportunityFields = null;\n\n public function __construct()\n {\n $this->teamService = app(TeamService::class);\n $this->transcriptionService = app(TranscriptionService::class);\n $this->logger = app(LoggerInterface::class);\n }\n\n /**\n * @param User $user\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function setUser(User $user): void\n {\n $this->configureSentryScope($user);\n\n $this->team = $user->team;\n $this->teamService->setTeam($user->team);\n $this->setConfiguration($user->team->crm);\n\n // Reset state.\n $this->profile = $user->crmProfile;\n\n /**\n * DO NOT DELETE THIS `clearTokens` CALL\n * The purpose of purging tokens is to fix a problem in importing calendar events.\n * Calendar Import doesn't always respect \"SocialAccountInvalidTokenException\" exception\n * and may try to recycle old SF instance, with wrong credentials (by ignoring the exception).\n *\n * This code guarantees the CRM Service is unusable, unless always provided with a valid social account.\n */\n if (method_exists($this->client, 'clearTokens')) {\n $this->client->clearTokens();\n }\n\n $account = $this->getOAuthAccount($user);\n\n $this->validateUserAccountExists($user, $account);\n\n if (method_exists($this->client, 'setOAuthAccount')) {\n $this->client->setOAuthAccount($account);\n }\n if (method_exists($this->client, 'setLogger')) {\n $this->client->setLogger($this->logger);\n }\n\n if ($this->profile === null) {\n // Try to fetch their profile, maybe it was not yet imported?\n $cacheKey = sprintf('crm_profile_sync-%s', $user->getId());\n $lock = \\Cache::lock($cacheKey, 300);\n if ($lock->get()) {\n $this->profile = $this->getProfile($user);\n }\n }\n\n // The CRM Service is properly bootstrapped, and supports remote operations\n $this->connect();\n }\n\n protected function configureSentryScope(User $user): void\n {\n \\Sentry\\configureScope(function (Scope $scope) use ($user): void {\n $scope->setTag('team_id', (string) $user->getTeamId());\n $scope->setUser([\n 'id' => $user->getId(),\n 'email' => $user->getEmailAddress(),\n ]);\n });\n }\n\n /**\n * @param User $user\n *\n * @return Profile|null\n */\n protected function getProfile(User $user): ?Profile\n {\n return $this->syncProfiles($user);\n }\n\n public function getConfiguration(): Configuration\n {\n return $this->config;\n }\n\n public function setConfiguration(Configuration $config): void\n {\n $this->config = $config;\n $this->client->setConfiguration($config);\n\n // Clear field cache when configuration changes to ensure fresh data for new team/config\n $this->cachedOpportunityFields = null;\n\n if ($this->team === null) {\n $this->team = $config->team;\n }\n }\n\n public function setPage(int $limit, int $offset): void\n {\n $this->limit = $limit;\n $this->offset = $offset;\n }\n\n abstract protected function getOAuthAccount(User $user): ?SocialAccount;\n abstract protected function getDefaultFollowupLayoutFields(string $activityType): array;\n abstract protected function getFieldTypes(): array;\n abstract protected function getFields(string $fieldType): array;\n\n public function syncFields(): void\n {\n foreach ($this->getFieldTypes() as $fieldType) {\n $currentFields = $this->getFields($fieldType);\n\n // TODO: only sync the field once a day if we don't use it in any layout. If we do, sync hourly?\n foreach ($currentFields as $field) {\n /** @var Models\\Crm\\Field $field */\n $field = $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => mb_strimwidth($field['name'], 0, 128),\n 'object_type' => $fieldType,\n ], [\n 'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),\n ]);\n\n try {\n $this->syncField($field);\n\n if ($field->type === Models\\Crm\\Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n } catch (HttpNotFoundException $e) {\n $this->logger->error('[sync-fields] Field not found', [\n 'provider' => $this->getDisplayName(),\n 'crm_field' => $field->crm_provider_id,\n 'object_type' => $field->object_type,\n 'team_id' => $this->team->id,\n ]);\n } catch (HttpBadRequestException $e) {\n $this->logger->error('[sync-fields] Field not supported', [\n 'provider' => $this->getDisplayName(),\n 'crm_field' => $field->crm_provider_id,\n 'object_type' => $field->object_type,\n 'team_id' => $this->team->id,\n ]);\n }\n }\n }\n }\n\n /**\n * @param string $objectId\n * @param ?string $objectType\n *\n * @return array\n */\n public function parseRecords(string $objectId, ?string $objectType = null): array\n {\n if ($objectType === null && $this instanceof SupportsObjectTypeParseInterface) {\n $objectType = $this->parseObjectType($objectId);\n }\n\n $lead = null;\n $contact = null;\n $opportunity = null;\n $account = null;\n $stage = null;\n $countryCode = null;\n\n // Gather the prospect data to store on activity/participant.\n switch ($objectType) {\n case self::OBJECT_LEAD:\n /** @var ?Lead $lead */\n $lead = $this->config->leads()->where('crm_provider_id', $objectId)->first();\n\n if ($lead === null) {\n $lead = $this->syncLead($objectId);\n }\n\n if ($lead?->country_code) {\n $countryCode = $lead->country_code;\n }\n\n $stage = $lead?->stage;\n\n break;\n\n case self::OBJECT_ACCOUNT:\n $account = $this->config->accounts()->where('crm_provider_id', $objectId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($objectId);\n }\n\n if ($account->country_code) {\n $countryCode = $account->country_code;\n }\n\n break;\n\n case self::OBJECT_CONTACT:\n $contact = $this->config->contacts()->where('crm_provider_id', $objectId)->first();\n\n if ($contact === null) {\n $contact = $this->syncContact($objectId);\n }\n\n if ($contact?->country_code) {\n $countryCode = $contact->country_code;\n }\n\n $account = $contact?->account;\n\n break;\n\n case self::OBJECT_OPPORTUNITY:\n $opportunity = $this->config->opportunities()->where('crm_provider_id', $objectId)->first();\n\n if ($opportunity === null) {\n $opportunity = $this->syncOpportunity($objectId);\n }\n\n if ($opportunity !== null) {\n $stage = $opportunity->stage;\n\n $account = $opportunity->account;\n\n if ($account->country_code) {\n $countryCode = $account->country_code;\n }\n }\n\n break;\n }\n\n return [\n $lead,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n /**\n * @param null|string $name\n *\n * @return null|string\n */\n public function convertCountryNameToCode(?string $name): ?string\n {\n return app(CountryCodeResolver::class)->resolveCountryCode($name);\n }\n\n /**\n * @param PlaybookCategory $category\n *\n * @return bool\n */\n public function matchesCrmType(PlaybookCategory $category): bool\n {\n if ($category->playbook === null) {\n return false;\n }\n\n if ($category->getPlaybook()->getActivityField() === null) {\n return false;\n }\n\n $fieldValue = $category\n ->playbook\n ->activityField\n ->values()\n ->where('label', $category->name);\n\n // Check the field values for a matching option.\n return $fieldValue->exists();\n }\n\n /**\n * @param PlaybookCategory $category\n *\n * @return FieldValue|null\n */\n public function getCrmType(PlaybookCategory $category): ?FieldValue\n {\n $fieldValue = $category\n ->playbook\n ->activityField\n ->values()\n ->where('label', $category->name);\n\n return $fieldValue->first();\n }\n\n\n /**\n * @return int|float|string\n */\n public function getMinimumApiVersion(): int|float|string\n {\n return $this->client->getMinimumApiVersion();\n }\n\n /**\n * @param string $accountId\n *\n * @return bool\n */\n protected function hasAccount(string $accountId): bool\n {\n return $this->config->accounts()->where('crm_provider_id', $accountId)->exists();\n }\n\n /**\n * @param string $opportunityId\n *\n * @return bool\n */\n protected function hasOpportunity(string $opportunityId): bool\n {\n return $this->config->opportunities()->where('crm_provider_id', $opportunityId)->exists();\n }\n\n /**\n * @param string $contactId\n *\n * @return bool\n */\n protected function hasContact(string $contactId): bool\n {\n return $this->config->contacts()->where('crm_provider_id', $contactId)->exists();\n }\n\n /**\n * @param string $leadId\n *\n * @return bool\n */\n protected function hasLead(string $leadId): bool\n {\n return $this->config->leads()->where('crm_provider_id', $leadId)->exists();\n }\n\n public function fetchAndAssociateRelatedActivity(Activity $activity): ?Activity\n {\n return null;\n }\n\n public function getJobDelay(): int\n {\n return 0;\n }\n\n public function getPlaybookFromActivity(Activity $activity): ?Playbook\n {\n if ($activity->hasActivityType() && $activity->getActivityType()->hasPlaybook()) {\n return $activity->getActivityType()->getPlaybook();\n }\n\n return $this->getPlaybook($activity->getUser());\n }\n\n /**\n * Gets the playbook for the user\n */\n protected function getPlaybook(User $user): ?Playbook\n {\n $playbookResolver = app(PlaybookResolver::class);\n\n return $playbookResolver->resolvePlaybookByUser($user);\n }\n\n /**\n * @param Models\\Playbook $playbook\n * @param string $categoryName\n *\n * @return Models\\PlaybookCategory|null\n */\n protected function getPlaybookCategory(Models\\Playbook $playbook, string $categoryName): ?Models\\PlaybookCategory\n {\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->latest()\n ->first();\n }\n\n public function buildLayout(Layout $layout, ?string $activityType): void\n {\n if ($activityType) {\n // Base section. Currently, the fields within are hard coded so this is empty for now.\n /** @var Models\\Crm\\LayoutEntity $activitySection */\n $activitySection = $layout->entities()->create([\n 'label' => 'activity-summary',\n 'description' => 'Activity Summary',\n 'sequence' => 0,\n ]);\n\n if ($this instanceof HubspotInterface) {\n $activityFields = $this->getDefaultActivityLayoutFields($activityType, $layout->type);\n\n foreach ($activityFields as $i => $field) {\n $layout->entities()->create([\n 'parent_entity_id' => $activitySection->getId(),\n 'crm_field_id' => $field->getId(),\n 'sequence' => $i,\n ]);\n }\n }\n\n // Follow-up section. These are all dynamic fields.\n $sectionTitle = ($layout->type === Layout::TYPE_CONFERENCE_SUMMARY ? 'Next Steps...' : 'Follow up?');\n /** @var Models\\Crm\\LayoutEntity $followupSection */\n $followupSection = $layout->entities()->create([\n 'label' => 'follow-up',\n 'description' => $sectionTitle,\n 'sequence' => 1,\n ]);\n\n $followupFields = $this->getDefaultFollowupLayoutFields($activityType);\n\n foreach ($followupFields as $i => $field) {\n $layout->entities()->create([\n 'parent_entity_id' => $followupSection->getId(),\n 'crm_field_id' => $field->getId(),\n 'sequence' => $i,\n ]);\n }\n } elseif ($layout->type == Layout::TYPE_DEAL_INSIGHTS) {\n $this->populateLayoutEntities($layout);\n }\n }\n\n protected function populateLayoutEntities(Layout $layout): void\n {\n $dealFields = $this->getDefaultDealLayoutFields();\n\n foreach ($dealFields as $i => $field) {\n $readOnly = $field->getType() === Field::TYPE_CURRENCY\n || $this->isBusinessTypeField($field);\n\n $layout->entities()->updateOrCreate([\n 'crm_field_id' => $field->id,\n ], [\n 'sequence' => $i,\n 'read_only' => $readOnly,\n ]);\n }\n }\n\n public function prepareValueForUpdate(array $params): array\n {\n $fieldName = $params['fieldName'];\n $fieldValue = $params['fieldValue'];\n\n return [$fieldName => $fieldValue];\n }\n\n protected function getDefaultDealLayoutFields(): array\n {\n $fieldData = $this->getDealInsightsFields();\n\n $fields = [];\n foreach ($fieldData as $data) {\n /** @var Field $field */\n $field = $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => $data['crm_provider_id'],\n 'object_type' => $data['object_type'],\n ], ['label' => $data['crm_provider_id']]);\n\n try {\n dispatch_sync(new SyncFieldMetadata($this->config->team, $field));\n $field->refresh();\n } catch (\\Throwable $throwable) {\n \\Sentry::captureException($throwable);\n }\n\n $fields[] = $field;\n }\n\n return $fields;\n }\n\n public function importOpportunityCrmFieldData(array $crmData, array $crmFields, int $opportunityId): void\n {\n // Pre-fetch all opportunity fields once per batch to avoid N+1 queries.\n // During webhook floods, this reduces DB queries from O(fields × deals) to O(1) for field lookups.\n $fieldsMap = $this->getOpportunityFieldsMap();\n\n foreach ($crmFields as $fieldName) {\n $field = $fieldsMap->get($fieldName);\n\n if (! $field instanceof Field) {\n $this->logger->warning('Field not found', [\n 'field' => $fieldName,\n 'opportunity_id' => $opportunityId,\n ]);\n\n continue;\n }\n\n // A CRM field data will be synced only if the field exists as part of at least one layout,\n // i.e. an entity related to the field exists.\n $entity = $field->entities->first();\n if (! $entity instanceof Models\\Crm\\LayoutEntity) {\n continue;\n }\n\n $fieldValue = $crmData[$fieldName] ?? '';\n\n if (is_object($fieldValue)) {\n $this->logger->warning('Field value is an object', [\n 'field' => $fieldName,\n ]);\n\n continue;\n }\n\n $value = $this->normalizeValue($field->type, $fieldValue, true);\n\n FieldData::updateOrCreate([\n 'crm_layout_entity_id' => $entity->id,\n 'crm_field_id' => $field->id,\n 'object_type' => 'opportunity',\n 'object_id' => $opportunityId,\n ], ['value' => $value]);\n }\n }\n\n /**\n * Get cached opportunity fields map for efficient lookups during batch imports.\n *\n * This method fetches all opportunity fields with their entities relation ONCE\n * and caches them for the lifetime of this service instance. This eliminates\n * the N+1 query problem where each field was fetched individually per deal.\n *\n * Performance impact:\n * - Before: 10 fields × 100 deals = 1,000 field queries per batch\n * - After: 1 query per batch (regardless of deal count)\n *\n * @return Collection<string, Field> Fields keyed by crm_provider_id\n */\n private function getOpportunityFieldsMap(): Collection\n {\n if ($this->cachedOpportunityFields === null) {\n $this->cachedOpportunityFields = $this->config->fields()\n ->with('entities')\n ->where('object_type', '=', self::OBJECT_OPPORTUNITY)\n ->get()\n ->keyBy('crm_provider_id');\n }\n\n return $this->cachedOpportunityFields;\n }\n\n /**\n * @param array<mixed> $crmData\n * @param Collection $crmFields\n * @param int $objectId\n *\n * @return void\n */\n public function importCrmFieldData(array $crmData, Collection $crmFields, int $objectId): void\n {\n /** @var Field $crmField */\n foreach ($crmFields as $crmField) {\n // If the field name does not match one we are interested in, skip.\n if (array_key_exists($crmField->crm_provider_id, $crmData) === false) {\n continue;\n }\n\n /** @var string $fieldValue */\n $fieldValue = $crmData[$crmField->crm_provider_id];\n\n $value = $this->normalizeValue($crmField->type, $fieldValue, true);\n\n FieldData::updateOrCreate([\n 'crm_field_id' => $crmField->id,\n 'object_type' => $crmField->object_type,\n 'object_id' => $objectId,\n ], ['value' => $value]);\n }\n }\n\n protected function getTeam(): Team\n {\n if (! $this->team instanceof Team) {\n throw new LogicException('Expecting team model instance');\n }\n\n return $this->team;\n }\n\n public function isBusinessTypeField(Field $field): bool\n {\n return in_array($field->crm_provider_id, Field::BUSINESS_TYPE_FIELDS)\n && $field->object_type === Field::OBJECT_OPPORTUNITY;\n }\n\n /**\n * @return mixed[]\n */\n public function fetchRelatedActivity(Activity $activity): array\n {\n return [];\n }\n\n /**\n * @throws SocialAccountTokenInvalidException\n */\n private function validateUserAccountExists(User $user, ?SocialAccount $account = null): void\n {\n if ($account instanceof SocialAccount && $account->state === SocialAccount::STATE_CONNECTED) {\n return;\n }\n\n $this->logger->warning(\n sprintf('[%s] Account not connected for user', $this->getDisplayName()),\n [\n 'userId' => $user->getIdString(),\n 'account' => $account,\n ]\n );\n\n // If their profile was never setup in the first place\n if ($this->profile === null) {\n // Create a dummy in-memory profile just to be able to run\n $this->profile = new Profile();\n }\n\n if (! $account instanceof SocialAccount) {\n throw new SocialAccountTokenInvalidException(\n sprintf(\n 'Social account for %s cannot be found. Please login to Jiminny to connect.',\n $this->getDisplayName()\n )\n );\n }\n\n throw new SocialAccountTokenInvalidException(\n sprintf(\n 'Your %s account has become disconnected. Please login to Jiminny to reconnect.',\n $this->getDisplayName()\n )\n );\n }\n\n public function listSupportedObjectTypes(): array\n {\n return $this->getFieldTypes();\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"6","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"# **************************** HS **************************************\n\nselect * from teams where id = 2; # 2\nselect * from features; # 2\nselect * from team_features where team_id = 2; # 2\nselect * from crm_configurations where id = 2; # 2\nselect * from users where team_id = 2; #\nselect * from playbooks where team_id = 2; # event 38\nselect * from playbook_categories where playbook_id = 38; #\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;\nhttps://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624\n https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0\n\nSELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;\n# 609126 softphone tr. 11241\n\nSELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;\n# 608874 conference tr. 11226 crmId: 103422236596\n\nselect * from ai_prompts where transcription_id IN (11241, 11226);\nselect * from activity_summary_logs where activity_id = 608874;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nselect * from crm_field_data where activity_id = 1223;\n\nselect * from crm_layouts where crm_configuration_id = 2;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);\nselect * from crm_fields where crm_configuration_id = 11 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);\n\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u\n on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 2 and sa.provider = 'hubspot';\n\nselect * from opportunities where team_id = 2\nand crm_provider_id IN ('51317301383');\n\nselect * from contacts where id = 85;\n\nselect * from opportunities where team_id = 2 order by id desc;\nselect * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112\nselect * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112\nselect * from opportunity_contacts where opportunity_id = 5117;\nselect * from crm_field_data where object_id = 1365;\nSELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);\n\nselect * from features;\nselect * from team_features where team_id IN (1);\nselect * from team_features where feature_id IN (36);\n\nSHOW CREATE TABLE opportunity_contacts;\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';\n\n# $slug = 'HUBSPOT_WEBHOOK_SYNC';\n# $team = Jiminny\\Models\\Team::find(2);\n# $feature = Feature::query()->where('slug', $slug)->first();\n# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);\n\n# hubspot_webhook_metrics\n\nselect * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365\nSELECT * FROM opportunity_contacts WHERE opportunity_id = '414';\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';\nselect * from contacts where id in (414, 464);\n\nselect * from activities where crm_configuration_id = 2;\n\nselect settings from crm_configurations where id = 11;\n\nselect * from teams; # 1, 2\nselect * from users;\nselect * from crm_configurations where id = 39;\nselect * from team_features where team_id = 2;\nselect * from features;\n# SELECT * FROM opportunities WHERE crm_configuration_id = 2\n# order by id desc;\n# and crm_provider_id = '49908861993';\n\n\nselect * from activity_providers where id IN (443, 202, 203, 227);\n\nselect * from activity_imports where id = 795889;\n\nselect c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id\nwhere c.provider = 'hubspot';\n\nselect * from crm_configurations crm JOIN teams t on crm.team_id = t.id\nwhere provider = 'hubspot';\nSELECT * FROM teams WHERE id = 31;\nSELECT * FROM users WHERE id = 257;\nSELECT * FROM opportunities WHERE team_id = 2;\n\nselect * from opportunity_contacts where opportunity_id = 5124;\nselect * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)\n\nselect * from activities where crm_configuration_id = 13;\n\nSELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141\n\n\nselect id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;\nSELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 order by id desc;\nselect * from opportunity_contacts where contact_id = 6223;\nSELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;\n\nselect * from crm_profiles where crm_configuration_id = 2;\n\nselect * from activities where account_id = 46;","depth":4,"value":"# **************************** HS **************************************\n\nselect * from teams where id = 2; # 2\nselect * from features; # 2\nselect * from team_features where team_id = 2; # 2\nselect * from crm_configurations where id = 2; # 2\nselect * from users where team_id = 2; #\nselect * from playbooks where team_id = 2; # event 38\nselect * from playbook_categories where playbook_id = 38; #\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;\nhttps://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624\n https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0\n\nSELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;\n# 609126 softphone tr. 11241\n\nSELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;\n# 608874 conference tr. 11226 crmId: 103422236596\n\nselect * from ai_prompts where transcription_id IN (11241, 11226);\nselect * from activity_summary_logs where activity_id = 608874;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nselect * from crm_field_data where activity_id = 1223;\n\nselect * from crm_layouts where crm_configuration_id = 2;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);\nselect * from crm_fields where crm_configuration_id = 11 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);\n\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u\n on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 2 and sa.provider = 'hubspot';\n\nselect * from opportunities where team_id = 2\nand crm_provider_id IN ('51317301383');\n\nselect * from contacts where id = 85;\n\nselect * from opportunities where team_id = 2 order by id desc;\nselect * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112\nselect * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112\nselect * from opportunity_contacts where opportunity_id = 5117;\nselect * from crm_field_data where object_id = 1365;\nSELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);\n\nselect * from features;\nselect * from team_features where team_id IN (1);\nselect * from team_features where feature_id IN (36);\n\nSHOW CREATE TABLE opportunity_contacts;\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';\n\n# $slug = 'HUBSPOT_WEBHOOK_SYNC';\n# $team = Jiminny\\Models\\Team::find(2);\n# $feature = Feature::query()->where('slug', $slug)->first();\n# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);\n\n# hubspot_webhook_metrics\n\nselect * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365\nSELECT * FROM opportunity_contacts WHERE opportunity_id = '414';\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';\nselect * from contacts where id in (414, 464);\n\nselect * from activities where crm_configuration_id = 2;\n\nselect settings from crm_configurations where id = 11;\n\nselect * from teams; # 1, 2\nselect * from users;\nselect * from crm_configurations where id = 39;\nselect * from team_features where team_id = 2;\nselect * from features;\n# SELECT * FROM opportunities WHERE crm_configuration_id = 2\n# order by id desc;\n# and crm_provider_id = '49908861993';\n\n\nselect * from activity_providers where id IN (443, 202, 203, 227);\n\nselect * from activity_imports where id = 795889;\n\nselect c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id\nwhere c.provider = 'hubspot';\n\nselect * from crm_configurations crm JOIN teams t on crm.team_id = t.id\nwhere provider = 'hubspot';\nSELECT * FROM teams WHERE id = 31;\nSELECT * FROM users WHERE id = 257;\nSELECT * FROM opportunities WHERE team_id = 2;\n\nselect * from opportunity_contacts where opportunity_id = 5124;\nselect * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)\n\nselect * from activities where crm_configuration_id = 13;\n\nSELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141\n\n\nselect id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;\nSELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 order by id desc;\nselect * from opportunity_contacts where contact_id = 6223;\nSELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;\n\nselect * from crm_profiles where crm_configuration_id = 2;\n\nselect * from activities where account_id = 46;","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-3901041415012267504
|
633758359911316605
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#11976 on JY-20553-debug- Project: faVsco.js, menu
#11976 on JY-20553-debug-crm-sync-delays, menu
Start Listening for PHP Debug Connections
RequestGenerateAskJiminnyReportJobTest
Run 'RequestGenerateAskJiminnyReportJobTest'
Debug 'RequestGenerateAskJiminnyReportJobTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
1
19
2
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm;
use Illuminate\Support\Collection;
use Jiminny\Component\Transcription\Service\TranscriptionService;
use Jiminny\Contracts\Services\Crm\ClientInterface;
use Jiminny\Contracts\Services\Crm\ConnectionStateInterface;
use Jiminny\Contracts\Services\Crm\Provider\HubspotInterface;
use Jiminny\Contracts\Services\Crm\ServiceInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SupportsObjectTypeParseInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Exceptions\HttpBadRequestException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Integrations\PlaybookResolver;
use Jiminny\Jobs\Crm\SyncFieldMetadata;
use Jiminny\Models;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Crm\Layout;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\Crm\Helpers\ConnectionStateTrait;
use Jiminny\Services\Crm\Helpers\OpportunitySyncableFieldsTrait;
use Jiminny\Services\TeamService;
use Psr\Log\LoggerInterface;
use Sentry\State\Scope;
abstract class BaseService implements
ServiceInterface,
SettingsInterface,
SyncCrmEntitiesInterface,
ConnectionStateInterface
{
use ConnectionStateTrait;
use OpportunitySyncableFieldsTrait;
public const string OBJECT_LEAD = 'lead';
public const string OBJECT_ACCOUNT = 'account';
public const string OBJECT_CONTACT = 'contact';
public const string OBJECT_OPPORTUNITY = 'opportunity';
public const string OBJECT_TASK = 'task';
public const string OBJECT_EVENT = 'event';
public const int SOFT_DELETE_CHUNK = 100;
public const int HARD_DELETE_CHUNK = 1000;
public ?Configuration $config;
public ?Profile $profile;
public ?Team $team = null;
/**
* @var ClientInterface
*/
protected $client;
/**
* @var TeamService
*/
protected TeamService $teamService;
/**
* @var int
*/
protected int $limit;
/**
* @var int
*/
protected int $offset;
/**
* Transcription Service instance.
*
* @var TranscriptionService
*/
protected TranscriptionService $transcriptionService;
protected LoggerInterface $logger;
/**
* Cache for opportunity fields to avoid N+1 queries during batch imports.
* Key: crm_provider_id, Value: Field model with entities relation.
* Cleared when configuration changes.
*
* @var Collection<string, Field>|null
*/
private ?Collection $cachedOpportunityFields = null;
public function __construct()
{
$this->teamService = app(TeamService::class);
$this->transcriptionService = app(TranscriptionService::class);
$this->logger = app(LoggerInterface::class);
}
/**
* @param User $user
*
* @throws SocialAccountTokenInvalidException
*/
public function setUser(User $user): void
{
$this->configureSentryScope($user);
$this->team = $user->team;
$this->teamService->setTeam($user->team);
$this->setConfiguration($user->team->crm);
// Reset state.
$this->profile = $user->crmProfile;
/**
* DO NOT DELETE THIS `clearTokens` CALL
* The purpose of purging tokens is to fix a problem in importing calendar events.
* Calendar Import doesn't always respect "SocialAccountInvalidTokenException" exception
* and may try to recycle old SF instance, with wrong credentials (by ignoring the exception).
*
* This code guarantees the CRM Service is unusable, unless always provided with a valid social account.
*/
if (method_exists($this->client, 'clearTokens')) {
$this->client->clearTokens();
}
$account = $this->getOAuthAccount($user);
$this->validateUserAccountExists($user, $account);
if (method_exists($this->client, 'setOAuthAccount')) {
$this->client->setOAuthAccount($account);
}
if (method_exists($this->client, 'setLogger')) {
$this->client->setLogger($this->logger);
}
if ($this->profile === null) {
// Try to fetch their profile, maybe it was not yet imported?
$cacheKey = sprintf('crm_profile_sync-%s', $user->getId());
$lock = \Cache::lock($cacheKey, 300);
if ($lock->get()) {
$this->profile = $this->getProfile($user);
}
}
// The CRM Service is properly bootstrapped, and supports remote operations
$this->connect();
}
protected function configureSentryScope(User $user): void
{
\Sentry\configureScope(function (Scope $scope) use ($user): void {
$scope->setTag('team_id', (string) $user->getTeamId());
$scope->setUser([
'id' => $user->getId(),
'email' => $user->getEmailAddress(),
]);
});
}
/**
* @param User $user
*
* @return Profile|null
*/
protected function getProfile(User $user): ?Profile
{
return $this->syncProfiles($user);
}
public function getConfiguration(): Configuration
{
return $this->config;
}
public function setConfiguration(Configuration $config): void
{
$this->config = $config;
$this->client->setConfiguration($config);
// Clear field cache when configuration changes to ensure fresh data for new team/config
$this->cachedOpportunityFields = null;
if ($this->team === null) {
$this->team = $config->team;
}
}
public function setPage(int $limit, int $offset): void
{
$this->limit = $limit;
$this->offset = $offset;
}
abstract protected function getOAuthAccount(User $user): ?SocialAccount;
abstract protected function getDefaultFollowupLayoutFields(string $activityType): array;
abstract protected function getFieldTypes(): array;
abstract protected function getFields(string $fieldType): array;
public function syncFields(): void
{
foreach ($this->getFieldTypes() as $fieldType) {
$currentFields = $this->getFields($fieldType);
// TODO: only sync the field once a day if we don't use it in any layout. If we do, sync hourly?
foreach ($currentFields as $field) {
/** @var Models\Crm\Field $field */
$field = $this->config->fields()->updateOrCreate([
'crm_provider_id' => mb_strimwidth($field['name'], 0, 128),
'object_type' => $fieldType,
], [
'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),
]);
try {
$this->syncField($field);
if ($field->type === Models\Crm\Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
} catch (HttpNotFoundException $e) {
$this->logger->error('[sync-fields] Field not found', [
'provider' => $this->getDisplayName(),
'crm_field' => $field->crm_provider_id,
'object_type' => $field->object_type,
'team_id' => $this->team->id,
]);
} catch (HttpBadRequestException $e) {
$this->logger->error('[sync-fields] Field not supported', [
'provider' => $this->getDisplayName(),
'crm_field' => $field->crm_provider_id,
'object_type' => $field->object_type,
'team_id' => $this->team->id,
]);
}
}
}
}
/**
* @param string $objectId
* @param ?string $objectType
*
* @return array
*/
public function parseRecords(string $objectId, ?string $objectType = null): array
{
if ($objectType === null && $this instanceof SupportsObjectTypeParseInterface) {
$objectType = $this->parseObjectType($objectId);
}
$lead = null;
$contact = null;
$opportunity = null;
$account = null;
$stage = null;
$countryCode = null;
// Gather the prospect data to store on activity/participant.
switch ($objectType) {
case self::OBJECT_LEAD:
/** @var ?Lead $lead */
$lead = $this->config->leads()->where('crm_provider_id', $objectId)->first();
if ($lead === null) {
$lead = $this->syncLead($objectId);
}
if ($lead?->country_code) {
$countryCode = $lead->country_code;
}
$stage = $lead?->stage;
break;
case self::OBJECT_ACCOUNT:
$account = $this->config->accounts()->where('crm_provider_id', $objectId)->first();
if ($account === null) {
$account = $this->syncAccount($objectId);
}
if ($account->country_code) {
$countryCode = $account->country_code;
}
break;
case self::OBJECT_CONTACT:
$contact = $this->config->contacts()->where('crm_provider_id', $objectId)->first();
if ($contact === null) {
$contact = $this->syncContact($objectId);
}
if ($contact?->country_code) {
$countryCode = $contact->country_code;
}
$account = $contact?->account;
break;
case self::OBJECT_OPPORTUNITY:
$opportunity = $this->config->opportunities()->where('crm_provider_id', $objectId)->first();
if ($opportunity === null) {
$opportunity = $this->syncOpportunity($objectId);
}
if ($opportunity !== null) {
$stage = $opportunity->stage;
$account = $opportunity->account;
if ($account->country_code) {
$countryCode = $account->country_code;
}
}
break;
}
return [
$lead,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
/**
* @param null|string $name
*
* @return null|string
*/
public function convertCountryNameToCode(?string $name): ?string
{
return app(CountryCodeResolver::class)->resolveCountryCode($name);
}
/**
* @param PlaybookCategory $category
*
* @return bool
*/
public function matchesCrmType(PlaybookCategory $category): bool
{
if ($category->playbook === null) {
return false;
}
if ($category->getPlaybook()->getActivityField() === null) {
return false;
}
$fieldValue = $category
->playbook
->activityField
->values()
->where('label', $category->name);
// Check the field values for a matching option.
return $fieldValue->exists();
}
/**
* @param PlaybookCategory $category
*
* @return FieldValue|null
*/
public function getCrmType(PlaybookCategory $category): ?FieldValue
{
$fieldValue = $category
->playbook
->activityField
->values()
->where('label', $category->name);
return $fieldValue->first();
}
/**
* @return int|float|string
*/
public function getMinimumApiVersion(): int|float|string
{
return $this->client->getMinimumApiVersion();
}
/**
* @param string $accountId
*
* @return bool
*/
protected function hasAccount(string $accountId): bool
{
return $this->config->accounts()->where('crm_provider_id', $accountId)->exists();
}
/**
* @param string $opportunityId
*
* @return bool
*/
protected function hasOpportunity(string $opportunityId): bool
{
return $this->config->opportunities()->where('crm_provider_id', $opportunityId)->exists();
}
/**
* @param string $contactId
*
* @return bool
*/
protected function hasContact(string $contactId): bool
{
return $this->config->contacts()->where('crm_provider_id', $contactId)->exists();
}
/**
* @param string $leadId
*
* @return bool
*/
protected function hasLead(string $leadId): bool
{
return $this->config->leads()->where('crm_provider_id', $leadId)->exists();
}
public function fetchAndAssociateRelatedActivity(Activity $activity): ?Activity
{
return null;
}
public function getJobDelay(): int
{
return 0;
}
public function getPlaybookFromActivity(Activity $activity): ?Playbook
{
if ($activity->hasActivityType() && $activity->getActivityType()->hasPlaybook()) {
return $activity->getActivityType()->getPlaybook();
}
return $this->getPlaybook($activity->getUser());
}
/**
* Gets the playbook for the user
*/
protected function getPlaybook(User $user): ?Playbook
{
$playbookResolver = app(PlaybookResolver::class);
return $playbookResolver->resolvePlaybookByUser($user);
}
/**
* @param Models\Playbook $playbook
* @param string $categoryName
*
* @return Models\PlaybookCategory|null
*/
protected function getPlaybookCategory(Models\Playbook $playbook, string $categoryName): ?Models\PlaybookCategory
{
return $playbook->categories()
->where('name', trim($categoryName))
->latest()
->first();
}
public function buildLayout(Layout $layout, ?string $activityType): void
{
if ($activityType) {
// Base section. Currently, the fields within are hard coded so this is empty for now.
/** @var Models\Crm\LayoutEntity $activitySection */
$activitySection = $layout->entities()->create([
'label' => 'activity-summary',
'description' => 'Activity Summary',
'sequence' => 0,
]);
if ($this instanceof HubspotInterface) {
$activityFields = $this->getDefaultActivityLayoutFields($activityType, $layout->type);
foreach ($activityFields as $i => $field) {
$layout->entities()->create([
'parent_entity_id' => $activitySection->getId(),
'crm_field_id' => $field->getId(),
'sequence' => $i,
]);
}
}
// Follow-up section. These are all dynamic fields.
$sectionTitle = ($layout->type === Layout::TYPE_CONFERENCE_SUMMARY ? 'Next Steps...' : 'Follow up?');
/** @var Models\Crm\LayoutEntity $followupSection */
$followupSection = $layout->entities()->create([
'label' => 'follow-up',
'description' => $sectionTitle,
'sequence' => 1,
]);
$followupFields = $this->getDefaultFollowupLayoutFields($activityType);
foreach ($followupFields as $i => $field) {
$layout->entities()->create([
'parent_entity_id' => $followupSection->getId(),
'crm_field_id' => $field->getId(),
'sequence' => $i,
]);
}
} elseif ($layout->type == Layout::TYPE_DEAL_INSIGHTS) {
$this->populateLayoutEntities($layout);
}
}
protected function populateLayoutEntities(Layout $layout): void
{
$dealFields = $this->getDefaultDealLayoutFields();
foreach ($dealFields as $i => $field) {
$readOnly = $field->getType() === Field::TYPE_CURRENCY
|| $this->isBusinessTypeField($field);
$layout->entities()->updateOrCreate([
'crm_field_id' => $field->id,
], [
'sequence' => $i,
'read_only' => $readOnly,
]);
}
}
public function prepareValueForUpdate(array $params): array
{
$fieldName = $params['fieldName'];
$fieldValue = $params['fieldValue'];
return [$fieldName => $fieldValue];
}
protected function getDefaultDealLayoutFields(): array
{
$fieldData = $this->getDealInsightsFields();
$fields = [];
foreach ($fieldData as $data) {
/** @var Field $field */
$field = $this->config->fields()->updateOrCreate([
'crm_provider_id' => $data['crm_provider_id'],
'object_type' => $data['object_type'],
], ['label' => $data['crm_provider_id']]);
try {
dispatch_sync(new SyncFieldMetadata($this->config->team, $field));
$field->refresh();
} catch (\Throwable $throwable) {
\Sentry::captureException($throwable);
}
$fields[] = $field;
}
return $fields;
}
public function importOpportunityCrmFieldData(array $crmData, array $crmFields, int $opportunityId): void
{
// Pre-fetch all opportunity fields once per batch to avoid N+1 queries.
// During webhook floods, this reduces DB queries from O(fields × deals) to O(1) for field lookups.
$fieldsMap = $this->getOpportunityFieldsMap();
foreach ($crmFields as $fieldName) {
$field = $fieldsMap->get($fieldName);
if (! $field instanceof Field) {
$this->logger->warning('Field not found', [
'field' => $fieldName,
'opportunity_id' => $opportunityId,
]);
continue;
}
// A CRM field data will be synced only if the field exists as part of at least one layout,
// i.e. an entity related to the field exists.
$entity = $field->entities->first();
if (! $entity instanceof Models\Crm\LayoutEntity) {
continue;
}
$fieldValue = $crmData[$fieldName] ?? '';
if (is_object($fieldValue)) {
$this->logger->warning('Field value is an object', [
'field' => $fieldName,
]);
continue;
}
$value = $this->normalizeValue($field->type, $fieldValue, true);
FieldData::updateOrCreate([
'crm_layout_entity_id' => $entity->id,
'crm_field_id' => $field->id,
'object_type' => 'opportunity',
'object_id' => $opportunityId,
], ['value' => $value]);
}
}
/**
* Get cached opportunity fields map for efficient lookups during batch imports.
*
* This method fetches all opportunity fields with their entities relation ONCE
* and caches them for the lifetime of this service instance. This eliminates
* the N+1 query problem where each field was fetched individually per deal.
*
* Performance impact:
* - Before: 10 fields × 100 deals = 1,000 field queries per batch
* - After: 1 query per batch (regardless of deal count)
*
* @return Collection<string, Field> Fields keyed by crm_provider_id
*/
private function getOpportunityFieldsMap(): Collection
{
if ($this->cachedOpportunityFields === null) {
$this->cachedOpportunityFields = $this->config->fields()
->with('entities')
->where('object_type', '=', self::OBJECT_OPPORTUNITY)
->get()
->keyBy('crm_provider_id');
}
return $this->cachedOpportunityFields;
}
/**
* @param array<mixed> $crmData
* @param Collection $crmFields
* @param int $objectId
*
* @return void
*/
public function importCrmFieldData(array $crmData, Collection $crmFields, int $objectId): void
{
/** @var Field $crmField */
foreach ($crmFields as $crmField) {
// If the field name does not match one we are interested in, skip.
if (array_key_exists($crmField->crm_provider_id, $crmData) === false) {
continue;
}
/** @var string $fieldValue */
$fieldValue = $crmData[$crmField->crm_provider_id];
$value = $this->normalizeValue($crmField->type, $fieldValue, true);
FieldData::updateOrCreate([
'crm_field_id' => $crmField->id,
'object_type' => $crmField->object_type,
'object_id' => $objectId,
], ['value' => $value]);
}
}
protected function getTeam(): Team
{
if (! $this->team instanceof Team) {
throw new LogicException('Expecting team model instance');
}
return $this->team;
}
public function isBusinessTypeField(Field $field): bool
{
return in_array($field->crm_provider_id, Field::BUSINESS_TYPE_FIELDS)
&& $field->object_type === Field::OBJECT_OPPORTUNITY;
}
/**
* @return mixed[]
*/
public function fetchRelatedActivity(Activity $activity): array
{
return [];
}
/**
* @throws SocialAccountTokenInvalidException
*/
private function validateUserAccountExists(User $user, ?SocialAccount $account = null): void
{
if ($account instanceof SocialAccount && $account->state === SocialAccount::STATE_CONNECTED) {
return;
}
$this->logger->warning(
sprintf('[%s] Account not connected for user', $this->getDisplayName()),
[
'userId' => $user->getIdString(),
'account' => $account,
]
);
// If their profile was never setup in the first place
if ($this->profile === null) {
// Create a dummy in-memory profile just to be able to run
$this->profile = new Profile();
}
if (! $account instanceof SocialAccount) {
throw new SocialAccountTokenInvalidException(
sprintf(
'Social account for %s cannot be found. Please login to Jiminny to connect.',
$this->getDisplayName()
)
);
}
throw new SocialAccountTokenInvalidException(
sprintf(
'Your %s account has become disconnected. Please login to Jiminny to reconnect.',
$this->getDisplayName()
)
);
}
public function listSupportedObjectTypes(): array
{
return $this->getFieldTypes();
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
6
1
6
Previous Highlighted Error
Next Highlighted Error
# [PASSWORD_DOTS] HS [PASSWORD_DOTS]
select * from teams where id = 2; # 2
select * from features; # 2
select * from team_features where team_id = 2; # 2
select * from crm_configurations where id = 2; # 2
select * from users where team_id = 2; #
select * from playbooks where team_id = 2; # event 38
select * from playbook_categories where playbook_id = 38; #
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;
https://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624
https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0
SELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;
# 609126 softphone tr. 11241
SELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;
# 608874 conference tr. 11226 crmId: 103422236596
select * from ai_prompts where transcription_id IN (11241, 11226);
select * from activity_summary_logs where activity_id = 608874;
select * from sidekick_settings;
select * from default_activity_types;
select * from crm_field_data where activity_id = 1223;
select * from crm_layouts where crm_configuration_id = 2;
SELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);
select * from crm_fields where crm_configuration_id = 11 and object_type = 'event';
SELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);
SELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;
SELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u
on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 2 and sa.provider = 'hubspot';
select * from opportunities where team_id = 2
and crm_provider_id IN ('51317301383');
select * from contacts where id = 85;
select * from opportunities where team_id = 2 order by id desc;
select * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112
select * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112
select * from opportunity_contacts where opportunity_id = 5117;
select * from crm_field_data where object_id = 1365;
SELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);
select * from features;
select * from team_features where team_id IN (1);
select * from team_features where feature_id IN (36);
SHOW CREATE TABLE opportunity_contacts;
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';
# $slug = 'HUBSPOT_WEBHOOK_SYNC';
# $team = Jiminny\Models\Team::find(2);
# $feature = Feature::query()->where('slug', $slug)->first();
# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);
# hubspot_webhook_metrics
select * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365
SELECT * FROM opportunity_contacts WHERE opportunity_id = '414';
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';
select * from contacts where id in (414, 464);
select * from activities where crm_configuration_id = 2;
select settings from crm_configurations where id = 11;
select * from teams; # 1, 2
select * from users;
select * from crm_configurations where id = 39;
select * from team_features where team_id = 2;
select * from features;
# SELECT * FROM opportunities WHERE crm_configuration_id = 2
# order by id desc;
# and crm_provider_id = '49908861993';
select * from activity_providers where id IN (443, 202, 203, 227);
select * from activity_imports where id = 795889;
select c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id
where c.provider = 'hubspot';
select * from crm_configurations crm JOIN teams t on crm.team_id = t.id
where provider = 'hubspot';
SELECT * FROM teams WHERE id = 31;
SELECT * FROM users WHERE id = 257;
SELECT * FROM opportunities WHERE team_id = 2;
select * from opportunity_contacts where opportunity_id = 5124;
select * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)
select * from activities where crm_configuration_id = 13;
SELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141
select id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;
SELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;
SELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;
SELECT * FROM contacts WHERE team_id = 2 order by id desc;
select * from opportunity_contacts where contact_id = 6223;
SELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;
select * from crm_profiles where crm_configuration_id = 2;
select * from activities where account_id = 46;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
55617
|
NULL
|
0
|
2026-04-20T09:58:37.178798+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776679117178_m2.jpg...
|
PhpStorm
|
faVsco.js – BaseService.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#11976 on JY-20553-debug- Project: faVsco.js, menu
#11976 on JY-20553-debug-crm-sync-delays, menu
Start Listening for PHP Debug Connections
RequestGenerateAskJiminnyReportJobTest
Run 'RequestGenerateAskJiminnyReportJobTest'
Debug 'RequestGenerateAskJiminnyReportJobTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
1
19
2
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm;
use Illuminate\Support\Collection;
use Jiminny\Component\Transcription\Service\TranscriptionService;
use Jiminny\Contracts\Services\Crm\ClientInterface;
use Jiminny\Contracts\Services\Crm\ConnectionStateInterface;
use Jiminny\Contracts\Services\Crm\Provider\HubspotInterface;
use Jiminny\Contracts\Services\Crm\ServiceInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SupportsObjectTypeParseInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Exceptions\HttpBadRequestException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Integrations\PlaybookResolver;
use Jiminny\Jobs\Crm\SyncFieldMetadata;
use Jiminny\Models;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Crm\Layout;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\Crm\Helpers\ConnectionStateTrait;
use Jiminny\Services\Crm\Helpers\OpportunitySyncableFieldsTrait;
use Jiminny\Services\TeamService;
use Psr\Log\LoggerInterface;
use Sentry\State\Scope;
abstract class BaseService implements
ServiceInterface,
SettingsInterface,
SyncCrmEntitiesInterface,
ConnectionStateInterface
{
use ConnectionStateTrait;
use OpportunitySyncableFieldsTrait;
public const string OBJECT_LEAD = 'lead';
public const string OBJECT_ACCOUNT = 'account';
public const string OBJECT_CONTACT = 'contact';
public const string OBJECT_OPPORTUNITY = 'opportunity';
public const string OBJECT_TASK = 'task';
public const string OBJECT_EVENT = 'event';
public const int SOFT_DELETE_CHUNK = 100;
public const int HARD_DELETE_CHUNK = 1000;
public ?Configuration $config;
public ?Profile $profile;
public ?Team $team = null;
/**
* @var ClientInterface
*/
protected $client;
/**
* @var TeamService
*/
protected TeamService $teamService;
/**
* @var int
*/
protected int $limit;
/**
* @var int
*/
protected int $offset;
/**
* Transcription Service instance.
*
* @var TranscriptionService
*/
protected TranscriptionService $transcriptionService;
protected LoggerInterface $logger;
/**
* Cache for opportunity fields to avoid N+1 queries during batch imports.
* Key: crm_provider_id, Value: Field model with entities relation.
* Cleared when configuration changes.
*
* @var Collection<string, Field>|null
*/
private ?Collection $cachedOpportunityFields = null;
public function __construct()
{
$this->teamService = app(TeamService::class);
$this->transcriptionService = app(TranscriptionService::class);
$this->logger = app(LoggerInterface::class);
}
/**
* @param User $user
*
* @throws SocialAccountTokenInvalidException
*/
public function setUser(User $user): void
{
$this->configureSentryScope($user);
$this->team = $user->team;
$this->teamService->setTeam($user->team);
$this->setConfiguration($user->team->crm);
// Reset state.
$this->profile = $user->crmProfile;
/**
* DO NOT DELETE THIS `clearTokens` CALL
* The purpose of purging tokens is to fix a problem in importing calendar events.
* Calendar Import doesn't always respect "SocialAccountInvalidTokenException" exception
* and may try to recycle old SF instance, with wrong credentials (by ignoring the exception).
*
* This code guarantees the CRM Service is unusable, unless always provided with a valid social account.
*/
if (method_exists($this->client, 'clearTokens')) {
$this->client->clearTokens();
}
$account = $this->getOAuthAccount($user);
$this->validateUserAccountExists($user, $account);
if (method_exists($this->client, 'setOAuthAccount')) {
$this->client->setOAuthAccount($account);
}
if (method_exists($this->client, 'setLogger')) {
$this->client->setLogger($this->logger);
}
if ($this->profile === null) {
// Try to fetch their profile, maybe it was not yet imported?
$cacheKey = sprintf('crm_profile_sync-%s', $user->getId());
$lock = \Cache::lock($cacheKey, 300);
if ($lock->get()) {
$this->profile = $this->getProfile($user);
}
}
// The CRM Service is properly bootstrapped, and supports remote operations
$this->connect();
}
protected function configureSentryScope(User $user): void
{
\Sentry\configureScope(function (Scope $scope) use ($user): void {
$scope->setTag('team_id', (string) $user->getTeamId());
$scope->setUser([
'id' => $user->getId(),
'email' => $user->getEmailAddress(),
]);
});
}
/**
* @param User $user
*
* @return Profile|null
*/
protected function getProfile(User $user): ?Profile
{
return $this->syncProfiles($user);
}
public function getConfiguration(): Configuration
{
return $this->config;
}
public function setConfiguration(Configuration $config): void
{
$this->config = $config;
$this->client->setConfiguration($config);
// Clear field cache when configuration changes to ensure fresh data for new team/config
$this->cachedOpportunityFields = null;
if ($this->team === null) {
$this->team = $config->team;
}
}
public function setPage(int $limit, int $offset): void
{
$this->limit = $limit;
$this->offset = $offset;
}
abstract protected function getOAuthAccount(User $user): ?SocialAccount;
abstract protected function getDefaultFollowupLayoutFields(string $activityType): array;
abstract protected function getFieldTypes(): array;
abstract protected function getFields(string $fieldType): array;
public function syncFields(): void
{
foreach ($this->getFieldTypes() as $fieldType) {
$currentFields = $this->getFields($fieldType);
// TODO: only sync the field once a day if we don't use it in any layout. If we do, sync hourly?
foreach ($currentFields as $field) {
/** @var Models\Crm\Field $field */
$field = $this->config->fields()->updateOrCreate([
'crm_provider_id' => mb_strimwidth($field['name'], 0, 128),
'object_type' => $fieldType,
], [
'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),
]);
try {
$this->syncField($field);
if ($field->type === Models\Crm\Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
} catch (HttpNotFoundException $e) {
$this->logger->error('[sync-fields] Field not found', [
'provider' => $this->getDisplayName(),
'crm_field' => $field->crm_provider_id,
'object_type' => $field->object_type,
'team_id' => $this->team->id,
]);
} catch (HttpBadRequestException $e) {
$this->logger->error('[sync-fields] Field not supported', [
'provider' => $this->getDisplayName(),
'crm_field' => $field->crm_provider_id,
'object_type' => $field->object_type,
'team_id' => $this->team->id,
]);
}
}
}
}
/**
* @param string $objectId
* @param ?string $objectType
*
* @return array
*/
public function parseRecords(string $objectId, ?string $objectType = null): array
{
if ($objectType === null && $this instanceof SupportsObjectTypeParseInterface) {
$objectType = $this->parseObjectType($objectId);
}
$lead = null;
$contact = null;
$opportunity = null;
$account = null;
$stage = null;
$countryCode = null;
// Gather the prospect data to store on activity/participant.
switch ($objectType) {
case self::OBJECT_LEAD:
/** @var ?Lead $lead */
$lead = $this->config->leads()->where('crm_provider_id', $objectId)->first();
if ($lead === null) {
$lead = $this->syncLead($objectId);
}
if ($lead?->country_code) {
$countryCode = $lead->country_code;
}
$stage = $lead?->stage;
break;
case self::OBJECT_ACCOUNT:
$account = $this->config->accounts()->where('crm_provider_id', $objectId)->first();
if ($account === null) {
$account = $this->syncAccount($objectId);
}
if ($account->country_code) {
$countryCode = $account->country_code;
}
break;
case self::OBJECT_CONTACT:
$contact = $this->config->contacts()->where('crm_provider_id', $objectId)->first();
if ($contact === null) {
$contact = $this->syncContact($objectId);
}
if ($contact?->country_code) {
$countryCode = $contact->country_code;
}
$account = $contact?->account;
break;
case self::OBJECT_OPPORTUNITY:
$opportunity = $this->config->opportunities()->where('crm_provider_id', $objectId)->first();
if ($opportunity === null) {
$opportunity = $this->syncOpportunity($objectId);
}
if ($opportunity !== null) {
$stage = $opportunity->stage;
$account = $opportunity->account;
if ($account->country_code) {
$countryCode = $account->country_code;
}
}
break;
}
return [
$lead,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
/**
* @param null|string $name
*
* @return null|string
*/
public function convertCountryNameToCode(?string $name): ?string
{
return app(CountryCodeResolver::class)->resolveCountryCode($name);
}
/**
* @param PlaybookCategory $category
*
* @return bool
*/
public function matchesCrmType(PlaybookCategory $category): bool
{
if ($category->playbook === null) {
return false;
}
if ($category->getPlaybook()->getActivityField() === null) {
return false;
}
$fieldValue = $category
->playbook
->activityField
->values()
->where('label', $category->name);
// Check the field values for a matching option.
return $fieldValue->exists();
}
/**
* @param PlaybookCategory $category
*
* @return FieldValue|null
*/
public function getCrmType(PlaybookCategory $category): ?FieldValue
{
$fieldValue = $category
->playbook
->activityField
->values()
->where('label', $category->name);
return $fieldValue->first();
}
/**
* @return int|float|string
*/
public function getMinimumApiVersion(): int|float|string
{
return $this->client->getMinimumApiVersion();
}
/**
* @param string $accountId
*
* @return bool
*/
protected function hasAccount(string $accountId): bool
{
return $this->config->accounts()->where('crm_provider_id', $accountId)->exists();
}
/**
* @param string $opportunityId
*
* @return bool
*/
protected function hasOpportunity(string $opportunityId): bool
{
return $this->config->opportunities()->where('crm_provider_id', $opportunityId)->exists();
}
/**
* @param string $contactId
*
* @return bool
*/
protected function hasContact(string $contactId): bool
{
return $this->config->contacts()->where('crm_provider_id', $contactId)->exists();
}
/**
* @param string $leadId
*
* @return bool
*/
protected function hasLead(string $leadId): bool
{
return $this->config->leads()->where('crm_provider_id', $leadId)->exists();
}
public function fetchAndAssociateRelatedActivity(Activity $activity): ?Activity
{
return null;
}
public function getJobDelay(): int
{
return 0;
}
public function getPlaybookFromActivity(Activity $activity): ?Playbook
{
if ($activity->hasActivityType() && $activity->getActivityType()->hasPlaybook()) {
return $activity->getActivityType()->getPlaybook();
}
return $this->getPlaybook($activity->getUser());
}
/**
* Gets the playbook for the user
*/
protected function getPlaybook(User $user): ?Playbook
{
$playbookResolver = app(PlaybookResolver::class);
return $playbookResolver->resolvePlaybookByUser($user);
}
/**
* @param Models\Playbook $playbook
* @param string $categoryName
*
* @return Models\PlaybookCategory|null
*/
protected function getPlaybookCategory(Models\Playbook $playbook, string $categoryName): ?Models\PlaybookCategory
{
return $playbook->categories()
->where('name', trim($categoryName))
->latest()
->first();
}
public function buildLayout(Layout $layout, ?string $activityType): void
{
if ($activityType) {
// Base section. Currently, the fields within are hard coded so this is empty for now.
/** @var Models\Crm\LayoutEntity $activitySection */
$activitySection = $layout->entities()->create([
'label' => 'activity-summary',
'description' => 'Activity Summary',
'sequence' => 0,
]);
if ($this instanceof HubspotInterface) {
$activityFields = $this->getDefaultActivityLayoutFields($activityType, $layout->type);
foreach ($activityFields as $i => $field) {
$layout->entities()->create([
'parent_entity_id' => $activitySection->getId(),
'crm_field_id' => $field->getId(),
'sequence' => $i,
]);
}
}
// Follow-up section. These are all dynamic fields.
$sectionTitle = ($layout->type === Layout::TYPE_CONFERENCE_SUMMARY ? 'Next Steps...' : 'Follow up?');
/** @var Models\Crm\LayoutEntity $followupSection */
$followupSection = $layout->entities()->create([
'label' => 'follow-up',
'description' => $sectionTitle,
'sequence' => 1,
]);
$followupFields = $this->getDefaultFollowupLayoutFields($activityType);
foreach ($followupFields as $i => $field) {
$layout->entities()->create([
'parent_entity_id' => $followupSection->getId(),
'crm_field_id' => $field->getId(),
'sequence' => $i,
]);
}
} elseif ($layout->type == Layout::TYPE_DEAL_INSIGHTS) {
$this->populateLayoutEntities($layout);
}
}
protected function populateLayoutEntities(Layout $layout): void
{
$dealFields = $this->getDefaultDealLayoutFields();
foreach ($dealFields as $i => $field) {
$readOnly = $field->getType() === Field::TYPE_CURRENCY
|| $this->isBusinessTypeField($field);
$layout->entities()->updateOrCreate([
'crm_field_id' => $field->id,
], [
'sequence' => $i,
'read_only' => $readOnly,
]);
}
}
public function prepareValueForUpdate(array $params): array
{
$fieldName = $params['fieldName'];
$fieldValue = $params['fieldValue'];
return [$fieldName => $fieldValue];
}
protected function getDefaultDealLayoutFields(): array
{
$fieldData = $this->getDealInsightsFields();
$fields = [];
foreach ($fieldData as $data) {
/** @var Field $field */
$field = $this->config->fields()->updateOrCreate([
'crm_provider_id' => $data['crm_provider_id'],
'object_type' => $data['object_type'],
], ['label' => $data['crm_provider_id']]);
try {
dispatch_sync(new SyncFieldMetadata($this->config->team, $field));
$field->refresh();
} catch (\Throwable $throwable) {
\Sentry::captureException($throwable);
}
$fields[] = $field;
}
return $fields;
}
public function importOpportunityCrmFieldData(array $crmData, array $crmFields, int $opportunityId): void
{
// Pre-fetch all opportunity fields once per batch to avoid N+1 queries.
// During webhook floods, this reduces DB queries from O(fields × deals) to O(1) for field lookups.
$fieldsMap = $this->getOpportunityFieldsMap();
foreach ($crmFields as $fieldName) {
$field = $fieldsMap->get($fieldName);
if (! $field instanceof Field) {
$this->logger->warning('Field not found', [
'field' => $fieldName,
'opportunity_id' => $opportunityId,
]);
continue;
}
// A CRM field data will be synced only if the field exists as part of at least one layout,
// i.e. an entity related to the field exists.
$entity = $field->entities->first();
if (! $entity instanceof Models\Crm\LayoutEntity) {
continue;
}
$fieldValue = $crmData[$fieldName] ?? '';
if (is_object($fieldValue)) {
$this->logger->warning('Field value is an object', [
'field' => $fieldName,
]);
continue;
}
$value = $this->normalizeValue($field->type, $fieldValue, true);
FieldData::updateOrCreate([
'crm_layout_entity_id' => $entity->id,
'crm_field_id' => $field->id,
'object_type' => 'opportunity',
'object_id' => $opportunityId,
], ['value' => $value]);
}
}
/**
* Get cached opportunity fields map for efficient lookups during batch imports.
*
* This method fetches all opportunity fields with their entities relation ONCE
* and caches them for the lifetime of this service instance. This eliminates
* the N+1 query problem where each field was fetched individually per deal.
*
* Performance impact:
* - Before: 10 fields × 100 deals = 1,000 field queries per batch
* - After: 1 query per batch (regardless of deal count)
*
* @return Collection<string, Field> Fields keyed by crm_provider_id
*/
private function getOpportunityFieldsMap(): Collection
{
if ($this->cachedOpportunityFields === null) {
$this->cachedOpportunityFields = $this->config->fields()
->with('entities')
->where('object_type', '=', self::OBJECT_OPPORTUNITY)
->get()
->keyBy('crm_provider_id');
}
return $this->cachedOpportunityFields;
}
/**
* @param array<mixed> $crmData
* @param Collection $crmFields
* @param int $objectId
*
* @return void
*/
public function importCrmFieldData(array $crmData, Collection $crmFields, int $objectId): void
{
/** @var Field $crmField */
foreach ($crmFields as $crmField) {
// If the field name does not match one we are interested in, skip.
if (array_key_exists($crmField->crm_provider_id, $crmData) === false) {
continue;
}
/** @var string $fieldValue */
$fieldValue = $crmData[$crmField->crm_provider_id];
$value = $this->normalizeValue($crmField->type, $fieldValue, true);
FieldData::updateOrCreate([
'crm_field_id' => $crmField->id,
'object_type' => $crmField->object_type,
'object_id' => $objectId,
], ['value' => $value]);
}
}
protected function getTeam(): Team
{
if (! $this->team instanceof Team) {
throw new LogicException('Expecting team model instance');
}
return $this->team;
}
public function isBusinessTypeField(Field $field): bool
{
return in_array($field->crm_provider_id, Field::BUSINESS_TYPE_FIELDS)
&& $field->object_type === Field::OBJECT_OPPORTUNITY;
}
/**
* @return mixed[]
*/
public function fetchRelatedActivity(Activity $activity): array
{
return [];
}
/**
* @throws SocialAccountTokenInvalidException
*/
private function validateUserAccountExists(User $user, ?SocialAccount $account = null): void
{
if ($account instanceof SocialAccount && $account->state === SocialAccount::STATE_CONNECTED) {
return;
}
$this->logger->warning(
sprintf('[%s] Account not connected for user', $this->getDisplayName()),
[
'userId' => $user->getIdString(),
'account' => $account,
]
);
// If their profile was never setup in the first place
if ($this->profile === null) {
// Create a dummy in-memory profile just to be able to run
$this->profile = new Profile();
}
if (! $account instanceof SocialAccount) {
throw new SocialAccountTokenInvalidException(
sprintf(
'Social account for %s cannot be found. Please login to Jiminny to connect.',
$this->getDisplayName()
)
);
}
throw new SocialAccountTokenInvalidException(
sprintf(
'Your %s account has become disconnected. Please login to Jiminny to reconnect.',
$this->getDisplayName()
)
);
}
public function listSupportedObjectTypes(): array
{
return $this->getFieldTypes();
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
6
1
6
Previous Highlighted Error
Next Highlighted Error
# [PASSWORD_DOTS] HS [PASSWORD_DOTS]
select * from teams where id = 2; # 2
select * from features; # 2
select * from team_features where team_id = 2; # 2
select * from crm_configurations where id = 2; # 2
select * from users where team_id = 2; #
select * from playbooks where team_id = 2; # event 38
select * from playbook_categories where playbook_id = 38; #
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;
https://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624
https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0
SELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;
# 609126 softphone tr. 11241
SELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;
# 608874 conference tr. 11226 crmId: 103422236596
select * from ai_prompts where transcription_id IN (11241, 11226);
select * from activity_summary_logs where activity_id = 608874;
select * from sidekick_settings;
select * from default_activity_types;
select * from crm_field_data where activity_id = 1223;
select * from crm_layouts where crm_configuration_id = 2;
SELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);
select * from crm_fields where crm_configuration_id = 11 and object_type = 'event';
SELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);
SELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;
SELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u
on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 2 and sa.provider = 'hubspot';
select * from opportunities where team_id = 2
and crm_provider_id IN ('51317301383');
select * from contacts where id = 85;
select * from opportunities where team_id = 2 order by id desc;
select * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112
select * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112
select * from opportunity_contacts where opportunity_id = 5117;
select * from crm_field_data where object_id = 1365;
SELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);
select * from features;
select * from team_features where team_id IN (1);
select * from team_features where feature_id IN (36);
SHOW CREATE TABLE opportunity_contacts;
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';
# $slug = 'HUBSPOT_WEBHOOK_SYNC';
# $team = Jiminny\Models\Team::find(2);
# $feature = Feature::query()->where('slug', $slug)->first();
# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);
# hubspot_webhook_metrics
select * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365
SELECT * FROM opportunity_contacts WHERE opportunity_id = '414';
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';
select * from contacts where id in (414, 464);
select * from activities where crm_configuration_id = 2;
select settings from crm_configurations where id = 11;
select * from teams; # 1, 2
select * from users;
select * from crm_configurations where id = 39;
select * from team_features where team_id = 2;
select * from features;
# SELECT * FROM opportunities WHERE crm_configuration_id = 2
# order by id desc;
# and crm_provider_id = '49908861993';
select * from activity_providers where id IN (443, 202, 203, 227);
select * from activity_imports where id = 795889;
select c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id
where c.provider = 'hubspot';
select * from crm_configurations crm JOIN teams t on crm.team_id = t.id
where provider = 'hubspot';
SELECT * FROM teams WHERE id = 31;
SELECT * FROM users WHERE id = 257;
SELECT * FROM opportunities WHERE team_id = 2;
select * from opportunity_contacts where opportunity_id = 5124;
select * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)
select * from activities where crm_configuration_id = 13;
SELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141
select id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;
SELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;
SELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;
SELECT * FROM contacts WHERE team_id = 2 order by id desc;
select * from opportunity_contacts where contact_id = 6223;
SELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;
select * from crm_profiles where crm_configuration_id = 2;
select * from activities where account_id = 46;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11976 on JY-20553-debug-crm-sync-delays, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.10837766,"height":0.025538707},"help_text":"Pull request #11976 exists for current branch JY-20553-debug-crm-sync-delays","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.7972075,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"RequestGenerateAskJiminnyReportJobTest","depth":6,"bounds":{"left":0.8125,"top":0.019952115,"width":0.10305851,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'RequestGenerateAskJiminnyReportJobTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'RequestGenerateAskJiminnyReportJobTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.48038563,"top":0.19952115,"width":0.00731383,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"19","depth":4,"bounds":{"left":0.48969415,"top":0.19952115,"width":0.009640957,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.5013298,"top":0.19952115,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.5109708,"top":0.19792499,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.51828456,"top":0.19792499,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Crm;\n\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Component\\Transcription\\Service\\TranscriptionService;\nuse Jiminny\\Contracts\\Services\\Crm\\ClientInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\ConnectionStateInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\HubspotInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SupportsObjectTypeParseInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Exceptions\\HttpBadRequestException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Integrations\\PlaybookResolver;\nuse Jiminny\\Jobs\\Crm\\SyncFieldMetadata;\nuse Jiminny\\Models;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Crm\\Layout;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Crm\\Helpers\\ConnectionStateTrait;\nuse Jiminny\\Services\\Crm\\Helpers\\OpportunitySyncableFieldsTrait;\nuse Jiminny\\Services\\TeamService;\nuse Psr\\Log\\LoggerInterface;\nuse Sentry\\State\\Scope;\n\nabstract class BaseService implements\n ServiceInterface,\n SettingsInterface,\n SyncCrmEntitiesInterface,\n ConnectionStateInterface\n{\n use ConnectionStateTrait;\n use OpportunitySyncableFieldsTrait;\n\n public const string OBJECT_LEAD = 'lead';\n public const string OBJECT_ACCOUNT = 'account';\n public const string OBJECT_CONTACT = 'contact';\n public const string OBJECT_OPPORTUNITY = 'opportunity';\n public const string OBJECT_TASK = 'task';\n public const string OBJECT_EVENT = 'event';\n\n public const int SOFT_DELETE_CHUNK = 100;\n public const int HARD_DELETE_CHUNK = 1000;\n\n public ?Configuration $config;\n\n public ?Profile $profile;\n\n public ?Team $team = null;\n\n /**\n * @var ClientInterface\n */\n protected $client;\n\n /**\n * @var TeamService\n */\n protected TeamService $teamService;\n\n /**\n * @var int\n */\n protected int $limit;\n\n /**\n * @var int\n */\n protected int $offset;\n\n /**\n * Transcription Service instance.\n *\n * @var TranscriptionService\n */\n protected TranscriptionService $transcriptionService;\n\n protected LoggerInterface $logger;\n\n /**\n * Cache for opportunity fields to avoid N+1 queries during batch imports.\n * Key: crm_provider_id, Value: Field model with entities relation.\n * Cleared when configuration changes.\n *\n * @var Collection<string, Field>|null\n */\n private ?Collection $cachedOpportunityFields = null;\n\n public function __construct()\n {\n $this->teamService = app(TeamService::class);\n $this->transcriptionService = app(TranscriptionService::class);\n $this->logger = app(LoggerInterface::class);\n }\n\n /**\n * @param User $user\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function setUser(User $user): void\n {\n $this->configureSentryScope($user);\n\n $this->team = $user->team;\n $this->teamService->setTeam($user->team);\n $this->setConfiguration($user->team->crm);\n\n // Reset state.\n $this->profile = $user->crmProfile;\n\n /**\n * DO NOT DELETE THIS `clearTokens` CALL\n * The purpose of purging tokens is to fix a problem in importing calendar events.\n * Calendar Import doesn't always respect \"SocialAccountInvalidTokenException\" exception\n * and may try to recycle old SF instance, with wrong credentials (by ignoring the exception).\n *\n * This code guarantees the CRM Service is unusable, unless always provided with a valid social account.\n */\n if (method_exists($this->client, 'clearTokens')) {\n $this->client->clearTokens();\n }\n\n $account = $this->getOAuthAccount($user);\n\n $this->validateUserAccountExists($user, $account);\n\n if (method_exists($this->client, 'setOAuthAccount')) {\n $this->client->setOAuthAccount($account);\n }\n if (method_exists($this->client, 'setLogger')) {\n $this->client->setLogger($this->logger);\n }\n\n if ($this->profile === null) {\n // Try to fetch their profile, maybe it was not yet imported?\n $cacheKey = sprintf('crm_profile_sync-%s', $user->getId());\n $lock = \\Cache::lock($cacheKey, 300);\n if ($lock->get()) {\n $this->profile = $this->getProfile($user);\n }\n }\n\n // The CRM Service is properly bootstrapped, and supports remote operations\n $this->connect();\n }\n\n protected function configureSentryScope(User $user): void\n {\n \\Sentry\\configureScope(function (Scope $scope) use ($user): void {\n $scope->setTag('team_id', (string) $user->getTeamId());\n $scope->setUser([\n 'id' => $user->getId(),\n 'email' => $user->getEmailAddress(),\n ]);\n });\n }\n\n /**\n * @param User $user\n *\n * @return Profile|null\n */\n protected function getProfile(User $user): ?Profile\n {\n return $this->syncProfiles($user);\n }\n\n public function getConfiguration(): Configuration\n {\n return $this->config;\n }\n\n public function setConfiguration(Configuration $config): void\n {\n $this->config = $config;\n $this->client->setConfiguration($config);\n\n // Clear field cache when configuration changes to ensure fresh data for new team/config\n $this->cachedOpportunityFields = null;\n\n if ($this->team === null) {\n $this->team = $config->team;\n }\n }\n\n public function setPage(int $limit, int $offset): void\n {\n $this->limit = $limit;\n $this->offset = $offset;\n }\n\n abstract protected function getOAuthAccount(User $user): ?SocialAccount;\n abstract protected function getDefaultFollowupLayoutFields(string $activityType): array;\n abstract protected function getFieldTypes(): array;\n abstract protected function getFields(string $fieldType): array;\n\n public function syncFields(): void\n {\n foreach ($this->getFieldTypes() as $fieldType) {\n $currentFields = $this->getFields($fieldType);\n\n // TODO: only sync the field once a day if we don't use it in any layout. If we do, sync hourly?\n foreach ($currentFields as $field) {\n /** @var Models\\Crm\\Field $field */\n $field = $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => mb_strimwidth($field['name'], 0, 128),\n 'object_type' => $fieldType,\n ], [\n 'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),\n ]);\n\n try {\n $this->syncField($field);\n\n if ($field->type === Models\\Crm\\Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n } catch (HttpNotFoundException $e) {\n $this->logger->error('[sync-fields] Field not found', [\n 'provider' => $this->getDisplayName(),\n 'crm_field' => $field->crm_provider_id,\n 'object_type' => $field->object_type,\n 'team_id' => $this->team->id,\n ]);\n } catch (HttpBadRequestException $e) {\n $this->logger->error('[sync-fields] Field not supported', [\n 'provider' => $this->getDisplayName(),\n 'crm_field' => $field->crm_provider_id,\n 'object_type' => $field->object_type,\n 'team_id' => $this->team->id,\n ]);\n }\n }\n }\n }\n\n /**\n * @param string $objectId\n * @param ?string $objectType\n *\n * @return array\n */\n public function parseRecords(string $objectId, ?string $objectType = null): array\n {\n if ($objectType === null && $this instanceof SupportsObjectTypeParseInterface) {\n $objectType = $this->parseObjectType($objectId);\n }\n\n $lead = null;\n $contact = null;\n $opportunity = null;\n $account = null;\n $stage = null;\n $countryCode = null;\n\n // Gather the prospect data to store on activity/participant.\n switch ($objectType) {\n case self::OBJECT_LEAD:\n /** @var ?Lead $lead */\n $lead = $this->config->leads()->where('crm_provider_id', $objectId)->first();\n\n if ($lead === null) {\n $lead = $this->syncLead($objectId);\n }\n\n if ($lead?->country_code) {\n $countryCode = $lead->country_code;\n }\n\n $stage = $lead?->stage;\n\n break;\n\n case self::OBJECT_ACCOUNT:\n $account = $this->config->accounts()->where('crm_provider_id', $objectId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($objectId);\n }\n\n if ($account->country_code) {\n $countryCode = $account->country_code;\n }\n\n break;\n\n case self::OBJECT_CONTACT:\n $contact = $this->config->contacts()->where('crm_provider_id', $objectId)->first();\n\n if ($contact === null) {\n $contact = $this->syncContact($objectId);\n }\n\n if ($contact?->country_code) {\n $countryCode = $contact->country_code;\n }\n\n $account = $contact?->account;\n\n break;\n\n case self::OBJECT_OPPORTUNITY:\n $opportunity = $this->config->opportunities()->where('crm_provider_id', $objectId)->first();\n\n if ($opportunity === null) {\n $opportunity = $this->syncOpportunity($objectId);\n }\n\n if ($opportunity !== null) {\n $stage = $opportunity->stage;\n\n $account = $opportunity->account;\n\n if ($account->country_code) {\n $countryCode = $account->country_code;\n }\n }\n\n break;\n }\n\n return [\n $lead,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n /**\n * @param null|string $name\n *\n * @return null|string\n */\n public function convertCountryNameToCode(?string $name): ?string\n {\n return app(CountryCodeResolver::class)->resolveCountryCode($name);\n }\n\n /**\n * @param PlaybookCategory $category\n *\n * @return bool\n */\n public function matchesCrmType(PlaybookCategory $category): bool\n {\n if ($category->playbook === null) {\n return false;\n }\n\n if ($category->getPlaybook()->getActivityField() === null) {\n return false;\n }\n\n $fieldValue = $category\n ->playbook\n ->activityField\n ->values()\n ->where('label', $category->name);\n\n // Check the field values for a matching option.\n return $fieldValue->exists();\n }\n\n /**\n * @param PlaybookCategory $category\n *\n * @return FieldValue|null\n */\n public function getCrmType(PlaybookCategory $category): ?FieldValue\n {\n $fieldValue = $category\n ->playbook\n ->activityField\n ->values()\n ->where('label', $category->name);\n\n return $fieldValue->first();\n }\n\n\n /**\n * @return int|float|string\n */\n public function getMinimumApiVersion(): int|float|string\n {\n return $this->client->getMinimumApiVersion();\n }\n\n /**\n * @param string $accountId\n *\n * @return bool\n */\n protected function hasAccount(string $accountId): bool\n {\n return $this->config->accounts()->where('crm_provider_id', $accountId)->exists();\n }\n\n /**\n * @param string $opportunityId\n *\n * @return bool\n */\n protected function hasOpportunity(string $opportunityId): bool\n {\n return $this->config->opportunities()->where('crm_provider_id', $opportunityId)->exists();\n }\n\n /**\n * @param string $contactId\n *\n * @return bool\n */\n protected function hasContact(string $contactId): bool\n {\n return $this->config->contacts()->where('crm_provider_id', $contactId)->exists();\n }\n\n /**\n * @param string $leadId\n *\n * @return bool\n */\n protected function hasLead(string $leadId): bool\n {\n return $this->config->leads()->where('crm_provider_id', $leadId)->exists();\n }\n\n public function fetchAndAssociateRelatedActivity(Activity $activity): ?Activity\n {\n return null;\n }\n\n public function getJobDelay(): int\n {\n return 0;\n }\n\n public function getPlaybookFromActivity(Activity $activity): ?Playbook\n {\n if ($activity->hasActivityType() && $activity->getActivityType()->hasPlaybook()) {\n return $activity->getActivityType()->getPlaybook();\n }\n\n return $this->getPlaybook($activity->getUser());\n }\n\n /**\n * Gets the playbook for the user\n */\n protected function getPlaybook(User $user): ?Playbook\n {\n $playbookResolver = app(PlaybookResolver::class);\n\n return $playbookResolver->resolvePlaybookByUser($user);\n }\n\n /**\n * @param Models\\Playbook $playbook\n * @param string $categoryName\n *\n * @return Models\\PlaybookCategory|null\n */\n protected function getPlaybookCategory(Models\\Playbook $playbook, string $categoryName): ?Models\\PlaybookCategory\n {\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->latest()\n ->first();\n }\n\n public function buildLayout(Layout $layout, ?string $activityType): void\n {\n if ($activityType) {\n // Base section. Currently, the fields within are hard coded so this is empty for now.\n /** @var Models\\Crm\\LayoutEntity $activitySection */\n $activitySection = $layout->entities()->create([\n 'label' => 'activity-summary',\n 'description' => 'Activity Summary',\n 'sequence' => 0,\n ]);\n\n if ($this instanceof HubspotInterface) {\n $activityFields = $this->getDefaultActivityLayoutFields($activityType, $layout->type);\n\n foreach ($activityFields as $i => $field) {\n $layout->entities()->create([\n 'parent_entity_id' => $activitySection->getId(),\n 'crm_field_id' => $field->getId(),\n 'sequence' => $i,\n ]);\n }\n }\n\n // Follow-up section. These are all dynamic fields.\n $sectionTitle = ($layout->type === Layout::TYPE_CONFERENCE_SUMMARY ? 'Next Steps...' : 'Follow up?');\n /** @var Models\\Crm\\LayoutEntity $followupSection */\n $followupSection = $layout->entities()->create([\n 'label' => 'follow-up',\n 'description' => $sectionTitle,\n 'sequence' => 1,\n ]);\n\n $followupFields = $this->getDefaultFollowupLayoutFields($activityType);\n\n foreach ($followupFields as $i => $field) {\n $layout->entities()->create([\n 'parent_entity_id' => $followupSection->getId(),\n 'crm_field_id' => $field->getId(),\n 'sequence' => $i,\n ]);\n }\n } elseif ($layout->type == Layout::TYPE_DEAL_INSIGHTS) {\n $this->populateLayoutEntities($layout);\n }\n }\n\n protected function populateLayoutEntities(Layout $layout): void\n {\n $dealFields = $this->getDefaultDealLayoutFields();\n\n foreach ($dealFields as $i => $field) {\n $readOnly = $field->getType() === Field::TYPE_CURRENCY\n || $this->isBusinessTypeField($field);\n\n $layout->entities()->updateOrCreate([\n 'crm_field_id' => $field->id,\n ], [\n 'sequence' => $i,\n 'read_only' => $readOnly,\n ]);\n }\n }\n\n public function prepareValueForUpdate(array $params): array\n {\n $fieldName = $params['fieldName'];\n $fieldValue = $params['fieldValue'];\n\n return [$fieldName => $fieldValue];\n }\n\n protected function getDefaultDealLayoutFields(): array\n {\n $fieldData = $this->getDealInsightsFields();\n\n $fields = [];\n foreach ($fieldData as $data) {\n /** @var Field $field */\n $field = $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => $data['crm_provider_id'],\n 'object_type' => $data['object_type'],\n ], ['label' => $data['crm_provider_id']]);\n\n try {\n dispatch_sync(new SyncFieldMetadata($this->config->team, $field));\n $field->refresh();\n } catch (\\Throwable $throwable) {\n \\Sentry::captureException($throwable);\n }\n\n $fields[] = $field;\n }\n\n return $fields;\n }\n\n public function importOpportunityCrmFieldData(array $crmData, array $crmFields, int $opportunityId): void\n {\n // Pre-fetch all opportunity fields once per batch to avoid N+1 queries.\n // During webhook floods, this reduces DB queries from O(fields × deals) to O(1) for field lookups.\n $fieldsMap = $this->getOpportunityFieldsMap();\n\n foreach ($crmFields as $fieldName) {\n $field = $fieldsMap->get($fieldName);\n\n if (! $field instanceof Field) {\n $this->logger->warning('Field not found', [\n 'field' => $fieldName,\n 'opportunity_id' => $opportunityId,\n ]);\n\n continue;\n }\n\n // A CRM field data will be synced only if the field exists as part of at least one layout,\n // i.e. an entity related to the field exists.\n $entity = $field->entities->first();\n if (! $entity instanceof Models\\Crm\\LayoutEntity) {\n continue;\n }\n\n $fieldValue = $crmData[$fieldName] ?? '';\n\n if (is_object($fieldValue)) {\n $this->logger->warning('Field value is an object', [\n 'field' => $fieldName,\n ]);\n\n continue;\n }\n\n $value = $this->normalizeValue($field->type, $fieldValue, true);\n\n FieldData::updateOrCreate([\n 'crm_layout_entity_id' => $entity->id,\n 'crm_field_id' => $field->id,\n 'object_type' => 'opportunity',\n 'object_id' => $opportunityId,\n ], ['value' => $value]);\n }\n }\n\n /**\n * Get cached opportunity fields map for efficient lookups during batch imports.\n *\n * This method fetches all opportunity fields with their entities relation ONCE\n * and caches them for the lifetime of this service instance. This eliminates\n * the N+1 query problem where each field was fetched individually per deal.\n *\n * Performance impact:\n * - Before: 10 fields × 100 deals = 1,000 field queries per batch\n * - After: 1 query per batch (regardless of deal count)\n *\n * @return Collection<string, Field> Fields keyed by crm_provider_id\n */\n private function getOpportunityFieldsMap(): Collection\n {\n if ($this->cachedOpportunityFields === null) {\n $this->cachedOpportunityFields = $this->config->fields()\n ->with('entities')\n ->where('object_type', '=', self::OBJECT_OPPORTUNITY)\n ->get()\n ->keyBy('crm_provider_id');\n }\n\n return $this->cachedOpportunityFields;\n }\n\n /**\n * @param array<mixed> $crmData\n * @param Collection $crmFields\n * @param int $objectId\n *\n * @return void\n */\n public function importCrmFieldData(array $crmData, Collection $crmFields, int $objectId): void\n {\n /** @var Field $crmField */\n foreach ($crmFields as $crmField) {\n // If the field name does not match one we are interested in, skip.\n if (array_key_exists($crmField->crm_provider_id, $crmData) === false) {\n continue;\n }\n\n /** @var string $fieldValue */\n $fieldValue = $crmData[$crmField->crm_provider_id];\n\n $value = $this->normalizeValue($crmField->type, $fieldValue, true);\n\n FieldData::updateOrCreate([\n 'crm_field_id' => $crmField->id,\n 'object_type' => $crmField->object_type,\n 'object_id' => $objectId,\n ], ['value' => $value]);\n }\n }\n\n protected function getTeam(): Team\n {\n if (! $this->team instanceof Team) {\n throw new LogicException('Expecting team model instance');\n }\n\n return $this->team;\n }\n\n public function isBusinessTypeField(Field $field): bool\n {\n return in_array($field->crm_provider_id, Field::BUSINESS_TYPE_FIELDS)\n && $field->object_type === Field::OBJECT_OPPORTUNITY;\n }\n\n /**\n * @return mixed[]\n */\n public function fetchRelatedActivity(Activity $activity): array\n {\n return [];\n }\n\n /**\n * @throws SocialAccountTokenInvalidException\n */\n private function validateUserAccountExists(User $user, ?SocialAccount $account = null): void\n {\n if ($account instanceof SocialAccount && $account->state === SocialAccount::STATE_CONNECTED) {\n return;\n }\n\n $this->logger->warning(\n sprintf('[%s] Account not connected for user', $this->getDisplayName()),\n [\n 'userId' => $user->getIdString(),\n 'account' => $account,\n ]\n );\n\n // If their profile was never setup in the first place\n if ($this->profile === null) {\n // Create a dummy in-memory profile just to be able to run\n $this->profile = new Profile();\n }\n\n if (! $account instanceof SocialAccount) {\n throw new SocialAccountTokenInvalidException(\n sprintf(\n 'Social account for %s cannot be found. Please login to Jiminny to connect.',\n $this->getDisplayName()\n )\n );\n }\n\n throw new SocialAccountTokenInvalidException(\n sprintf(\n 'Your %s account has become disconnected. Please login to Jiminny to reconnect.',\n $this->getDisplayName()\n )\n );\n }\n\n public function listSupportedObjectTypes(): array\n {\n return $this->getFieldTypes();\n }\n}","depth":4,"value":"<?php\n\nnamespace Jiminny\\Services\\Crm;\n\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Component\\Transcription\\Service\\TranscriptionService;\nuse Jiminny\\Contracts\\Services\\Crm\\ClientInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\ConnectionStateInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\HubspotInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\ServiceInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SupportsObjectTypeParseInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Exceptions\\HttpBadRequestException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Exceptions\\LogicException;\nuse Jiminny\\Exceptions\\SocialAccountTokenInvalidException;\nuse Jiminny\\Integrations\\PlaybookResolver;\nuse Jiminny\\Jobs\\Crm\\SyncFieldMetadata;\nuse Jiminny\\Models;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Crm\\Layout;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Crm\\Helpers\\ConnectionStateTrait;\nuse Jiminny\\Services\\Crm\\Helpers\\OpportunitySyncableFieldsTrait;\nuse Jiminny\\Services\\TeamService;\nuse Psr\\Log\\LoggerInterface;\nuse Sentry\\State\\Scope;\n\nabstract class BaseService implements\n ServiceInterface,\n SettingsInterface,\n SyncCrmEntitiesInterface,\n ConnectionStateInterface\n{\n use ConnectionStateTrait;\n use OpportunitySyncableFieldsTrait;\n\n public const string OBJECT_LEAD = 'lead';\n public const string OBJECT_ACCOUNT = 'account';\n public const string OBJECT_CONTACT = 'contact';\n public const string OBJECT_OPPORTUNITY = 'opportunity';\n public const string OBJECT_TASK = 'task';\n public const string OBJECT_EVENT = 'event';\n\n public const int SOFT_DELETE_CHUNK = 100;\n public const int HARD_DELETE_CHUNK = 1000;\n\n public ?Configuration $config;\n\n public ?Profile $profile;\n\n public ?Team $team = null;\n\n /**\n * @var ClientInterface\n */\n protected $client;\n\n /**\n * @var TeamService\n */\n protected TeamService $teamService;\n\n /**\n * @var int\n */\n protected int $limit;\n\n /**\n * @var int\n */\n protected int $offset;\n\n /**\n * Transcription Service instance.\n *\n * @var TranscriptionService\n */\n protected TranscriptionService $transcriptionService;\n\n protected LoggerInterface $logger;\n\n /**\n * Cache for opportunity fields to avoid N+1 queries during batch imports.\n * Key: crm_provider_id, Value: Field model with entities relation.\n * Cleared when configuration changes.\n *\n * @var Collection<string, Field>|null\n */\n private ?Collection $cachedOpportunityFields = null;\n\n public function __construct()\n {\n $this->teamService = app(TeamService::class);\n $this->transcriptionService = app(TranscriptionService::class);\n $this->logger = app(LoggerInterface::class);\n }\n\n /**\n * @param User $user\n *\n * @throws SocialAccountTokenInvalidException\n */\n public function setUser(User $user): void\n {\n $this->configureSentryScope($user);\n\n $this->team = $user->team;\n $this->teamService->setTeam($user->team);\n $this->setConfiguration($user->team->crm);\n\n // Reset state.\n $this->profile = $user->crmProfile;\n\n /**\n * DO NOT DELETE THIS `clearTokens` CALL\n * The purpose of purging tokens is to fix a problem in importing calendar events.\n * Calendar Import doesn't always respect \"SocialAccountInvalidTokenException\" exception\n * and may try to recycle old SF instance, with wrong credentials (by ignoring the exception).\n *\n * This code guarantees the CRM Service is unusable, unless always provided with a valid social account.\n */\n if (method_exists($this->client, 'clearTokens')) {\n $this->client->clearTokens();\n }\n\n $account = $this->getOAuthAccount($user);\n\n $this->validateUserAccountExists($user, $account);\n\n if (method_exists($this->client, 'setOAuthAccount')) {\n $this->client->setOAuthAccount($account);\n }\n if (method_exists($this->client, 'setLogger')) {\n $this->client->setLogger($this->logger);\n }\n\n if ($this->profile === null) {\n // Try to fetch their profile, maybe it was not yet imported?\n $cacheKey = sprintf('crm_profile_sync-%s', $user->getId());\n $lock = \\Cache::lock($cacheKey, 300);\n if ($lock->get()) {\n $this->profile = $this->getProfile($user);\n }\n }\n\n // The CRM Service is properly bootstrapped, and supports remote operations\n $this->connect();\n }\n\n protected function configureSentryScope(User $user): void\n {\n \\Sentry\\configureScope(function (Scope $scope) use ($user): void {\n $scope->setTag('team_id', (string) $user->getTeamId());\n $scope->setUser([\n 'id' => $user->getId(),\n 'email' => $user->getEmailAddress(),\n ]);\n });\n }\n\n /**\n * @param User $user\n *\n * @return Profile|null\n */\n protected function getProfile(User $user): ?Profile\n {\n return $this->syncProfiles($user);\n }\n\n public function getConfiguration(): Configuration\n {\n return $this->config;\n }\n\n public function setConfiguration(Configuration $config): void\n {\n $this->config = $config;\n $this->client->setConfiguration($config);\n\n // Clear field cache when configuration changes to ensure fresh data for new team/config\n $this->cachedOpportunityFields = null;\n\n if ($this->team === null) {\n $this->team = $config->team;\n }\n }\n\n public function setPage(int $limit, int $offset): void\n {\n $this->limit = $limit;\n $this->offset = $offset;\n }\n\n abstract protected function getOAuthAccount(User $user): ?SocialAccount;\n abstract protected function getDefaultFollowupLayoutFields(string $activityType): array;\n abstract protected function getFieldTypes(): array;\n abstract protected function getFields(string $fieldType): array;\n\n public function syncFields(): void\n {\n foreach ($this->getFieldTypes() as $fieldType) {\n $currentFields = $this->getFields($fieldType);\n\n // TODO: only sync the field once a day if we don't use it in any layout. If we do, sync hourly?\n foreach ($currentFields as $field) {\n /** @var Models\\Crm\\Field $field */\n $field = $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => mb_strimwidth($field['name'], 0, 128),\n 'object_type' => $fieldType,\n ], [\n 'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),\n ]);\n\n try {\n $this->syncField($field);\n\n if ($field->type === Models\\Crm\\Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n } catch (HttpNotFoundException $e) {\n $this->logger->error('[sync-fields] Field not found', [\n 'provider' => $this->getDisplayName(),\n 'crm_field' => $field->crm_provider_id,\n 'object_type' => $field->object_type,\n 'team_id' => $this->team->id,\n ]);\n } catch (HttpBadRequestException $e) {\n $this->logger->error('[sync-fields] Field not supported', [\n 'provider' => $this->getDisplayName(),\n 'crm_field' => $field->crm_provider_id,\n 'object_type' => $field->object_type,\n 'team_id' => $this->team->id,\n ]);\n }\n }\n }\n }\n\n /**\n * @param string $objectId\n * @param ?string $objectType\n *\n * @return array\n */\n public function parseRecords(string $objectId, ?string $objectType = null): array\n {\n if ($objectType === null && $this instanceof SupportsObjectTypeParseInterface) {\n $objectType = $this->parseObjectType($objectId);\n }\n\n $lead = null;\n $contact = null;\n $opportunity = null;\n $account = null;\n $stage = null;\n $countryCode = null;\n\n // Gather the prospect data to store on activity/participant.\n switch ($objectType) {\n case self::OBJECT_LEAD:\n /** @var ?Lead $lead */\n $lead = $this->config->leads()->where('crm_provider_id', $objectId)->first();\n\n if ($lead === null) {\n $lead = $this->syncLead($objectId);\n }\n\n if ($lead?->country_code) {\n $countryCode = $lead->country_code;\n }\n\n $stage = $lead?->stage;\n\n break;\n\n case self::OBJECT_ACCOUNT:\n $account = $this->config->accounts()->where('crm_provider_id', $objectId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($objectId);\n }\n\n if ($account->country_code) {\n $countryCode = $account->country_code;\n }\n\n break;\n\n case self::OBJECT_CONTACT:\n $contact = $this->config->contacts()->where('crm_provider_id', $objectId)->first();\n\n if ($contact === null) {\n $contact = $this->syncContact($objectId);\n }\n\n if ($contact?->country_code) {\n $countryCode = $contact->country_code;\n }\n\n $account = $contact?->account;\n\n break;\n\n case self::OBJECT_OPPORTUNITY:\n $opportunity = $this->config->opportunities()->where('crm_provider_id', $objectId)->first();\n\n if ($opportunity === null) {\n $opportunity = $this->syncOpportunity($objectId);\n }\n\n if ($opportunity !== null) {\n $stage = $opportunity->stage;\n\n $account = $opportunity->account;\n\n if ($account->country_code) {\n $countryCode = $account->country_code;\n }\n }\n\n break;\n }\n\n return [\n $lead,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n /**\n * @param null|string $name\n *\n * @return null|string\n */\n public function convertCountryNameToCode(?string $name): ?string\n {\n return app(CountryCodeResolver::class)->resolveCountryCode($name);\n }\n\n /**\n * @param PlaybookCategory $category\n *\n * @return bool\n */\n public function matchesCrmType(PlaybookCategory $category): bool\n {\n if ($category->playbook === null) {\n return false;\n }\n\n if ($category->getPlaybook()->getActivityField() === null) {\n return false;\n }\n\n $fieldValue = $category\n ->playbook\n ->activityField\n ->values()\n ->where('label', $category->name);\n\n // Check the field values for a matching option.\n return $fieldValue->exists();\n }\n\n /**\n * @param PlaybookCategory $category\n *\n * @return FieldValue|null\n */\n public function getCrmType(PlaybookCategory $category): ?FieldValue\n {\n $fieldValue = $category\n ->playbook\n ->activityField\n ->values()\n ->where('label', $category->name);\n\n return $fieldValue->first();\n }\n\n\n /**\n * @return int|float|string\n */\n public function getMinimumApiVersion(): int|float|string\n {\n return $this->client->getMinimumApiVersion();\n }\n\n /**\n * @param string $accountId\n *\n * @return bool\n */\n protected function hasAccount(string $accountId): bool\n {\n return $this->config->accounts()->where('crm_provider_id', $accountId)->exists();\n }\n\n /**\n * @param string $opportunityId\n *\n * @return bool\n */\n protected function hasOpportunity(string $opportunityId): bool\n {\n return $this->config->opportunities()->where('crm_provider_id', $opportunityId)->exists();\n }\n\n /**\n * @param string $contactId\n *\n * @return bool\n */\n protected function hasContact(string $contactId): bool\n {\n return $this->config->contacts()->where('crm_provider_id', $contactId)->exists();\n }\n\n /**\n * @param string $leadId\n *\n * @return bool\n */\n protected function hasLead(string $leadId): bool\n {\n return $this->config->leads()->where('crm_provider_id', $leadId)->exists();\n }\n\n public function fetchAndAssociateRelatedActivity(Activity $activity): ?Activity\n {\n return null;\n }\n\n public function getJobDelay(): int\n {\n return 0;\n }\n\n public function getPlaybookFromActivity(Activity $activity): ?Playbook\n {\n if ($activity->hasActivityType() && $activity->getActivityType()->hasPlaybook()) {\n return $activity->getActivityType()->getPlaybook();\n }\n\n return $this->getPlaybook($activity->getUser());\n }\n\n /**\n * Gets the playbook for the user\n */\n protected function getPlaybook(User $user): ?Playbook\n {\n $playbookResolver = app(PlaybookResolver::class);\n\n return $playbookResolver->resolvePlaybookByUser($user);\n }\n\n /**\n * @param Models\\Playbook $playbook\n * @param string $categoryName\n *\n * @return Models\\PlaybookCategory|null\n */\n protected function getPlaybookCategory(Models\\Playbook $playbook, string $categoryName): ?Models\\PlaybookCategory\n {\n return $playbook->categories()\n ->where('name', trim($categoryName))\n ->latest()\n ->first();\n }\n\n public function buildLayout(Layout $layout, ?string $activityType): void\n {\n if ($activityType) {\n // Base section. Currently, the fields within are hard coded so this is empty for now.\n /** @var Models\\Crm\\LayoutEntity $activitySection */\n $activitySection = $layout->entities()->create([\n 'label' => 'activity-summary',\n 'description' => 'Activity Summary',\n 'sequence' => 0,\n ]);\n\n if ($this instanceof HubspotInterface) {\n $activityFields = $this->getDefaultActivityLayoutFields($activityType, $layout->type);\n\n foreach ($activityFields as $i => $field) {\n $layout->entities()->create([\n 'parent_entity_id' => $activitySection->getId(),\n 'crm_field_id' => $field->getId(),\n 'sequence' => $i,\n ]);\n }\n }\n\n // Follow-up section. These are all dynamic fields.\n $sectionTitle = ($layout->type === Layout::TYPE_CONFERENCE_SUMMARY ? 'Next Steps...' : 'Follow up?');\n /** @var Models\\Crm\\LayoutEntity $followupSection */\n $followupSection = $layout->entities()->create([\n 'label' => 'follow-up',\n 'description' => $sectionTitle,\n 'sequence' => 1,\n ]);\n\n $followupFields = $this->getDefaultFollowupLayoutFields($activityType);\n\n foreach ($followupFields as $i => $field) {\n $layout->entities()->create([\n 'parent_entity_id' => $followupSection->getId(),\n 'crm_field_id' => $field->getId(),\n 'sequence' => $i,\n ]);\n }\n } elseif ($layout->type == Layout::TYPE_DEAL_INSIGHTS) {\n $this->populateLayoutEntities($layout);\n }\n }\n\n protected function populateLayoutEntities(Layout $layout): void\n {\n $dealFields = $this->getDefaultDealLayoutFields();\n\n foreach ($dealFields as $i => $field) {\n $readOnly = $field->getType() === Field::TYPE_CURRENCY\n || $this->isBusinessTypeField($field);\n\n $layout->entities()->updateOrCreate([\n 'crm_field_id' => $field->id,\n ], [\n 'sequence' => $i,\n 'read_only' => $readOnly,\n ]);\n }\n }\n\n public function prepareValueForUpdate(array $params): array\n {\n $fieldName = $params['fieldName'];\n $fieldValue = $params['fieldValue'];\n\n return [$fieldName => $fieldValue];\n }\n\n protected function getDefaultDealLayoutFields(): array\n {\n $fieldData = $this->getDealInsightsFields();\n\n $fields = [];\n foreach ($fieldData as $data) {\n /** @var Field $field */\n $field = $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => $data['crm_provider_id'],\n 'object_type' => $data['object_type'],\n ], ['label' => $data['crm_provider_id']]);\n\n try {\n dispatch_sync(new SyncFieldMetadata($this->config->team, $field));\n $field->refresh();\n } catch (\\Throwable $throwable) {\n \\Sentry::captureException($throwable);\n }\n\n $fields[] = $field;\n }\n\n return $fields;\n }\n\n public function importOpportunityCrmFieldData(array $crmData, array $crmFields, int $opportunityId): void\n {\n // Pre-fetch all opportunity fields once per batch to avoid N+1 queries.\n // During webhook floods, this reduces DB queries from O(fields × deals) to O(1) for field lookups.\n $fieldsMap = $this->getOpportunityFieldsMap();\n\n foreach ($crmFields as $fieldName) {\n $field = $fieldsMap->get($fieldName);\n\n if (! $field instanceof Field) {\n $this->logger->warning('Field not found', [\n 'field' => $fieldName,\n 'opportunity_id' => $opportunityId,\n ]);\n\n continue;\n }\n\n // A CRM field data will be synced only if the field exists as part of at least one layout,\n // i.e. an entity related to the field exists.\n $entity = $field->entities->first();\n if (! $entity instanceof Models\\Crm\\LayoutEntity) {\n continue;\n }\n\n $fieldValue = $crmData[$fieldName] ?? '';\n\n if (is_object($fieldValue)) {\n $this->logger->warning('Field value is an object', [\n 'field' => $fieldName,\n ]);\n\n continue;\n }\n\n $value = $this->normalizeValue($field->type, $fieldValue, true);\n\n FieldData::updateOrCreate([\n 'crm_layout_entity_id' => $entity->id,\n 'crm_field_id' => $field->id,\n 'object_type' => 'opportunity',\n 'object_id' => $opportunityId,\n ], ['value' => $value]);\n }\n }\n\n /**\n * Get cached opportunity fields map for efficient lookups during batch imports.\n *\n * This method fetches all opportunity fields with their entities relation ONCE\n * and caches them for the lifetime of this service instance. This eliminates\n * the N+1 query problem where each field was fetched individually per deal.\n *\n * Performance impact:\n * - Before: 10 fields × 100 deals = 1,000 field queries per batch\n * - After: 1 query per batch (regardless of deal count)\n *\n * @return Collection<string, Field> Fields keyed by crm_provider_id\n */\n private function getOpportunityFieldsMap(): Collection\n {\n if ($this->cachedOpportunityFields === null) {\n $this->cachedOpportunityFields = $this->config->fields()\n ->with('entities')\n ->where('object_type', '=', self::OBJECT_OPPORTUNITY)\n ->get()\n ->keyBy('crm_provider_id');\n }\n\n return $this->cachedOpportunityFields;\n }\n\n /**\n * @param array<mixed> $crmData\n * @param Collection $crmFields\n * @param int $objectId\n *\n * @return void\n */\n public function importCrmFieldData(array $crmData, Collection $crmFields, int $objectId): void\n {\n /** @var Field $crmField */\n foreach ($crmFields as $crmField) {\n // If the field name does not match one we are interested in, skip.\n if (array_key_exists($crmField->crm_provider_id, $crmData) === false) {\n continue;\n }\n\n /** @var string $fieldValue */\n $fieldValue = $crmData[$crmField->crm_provider_id];\n\n $value = $this->normalizeValue($crmField->type, $fieldValue, true);\n\n FieldData::updateOrCreate([\n 'crm_field_id' => $crmField->id,\n 'object_type' => $crmField->object_type,\n 'object_id' => $objectId,\n ], ['value' => $value]);\n }\n }\n\n protected function getTeam(): Team\n {\n if (! $this->team instanceof Team) {\n throw new LogicException('Expecting team model instance');\n }\n\n return $this->team;\n }\n\n public function isBusinessTypeField(Field $field): bool\n {\n return in_array($field->crm_provider_id, Field::BUSINESS_TYPE_FIELDS)\n && $field->object_type === Field::OBJECT_OPPORTUNITY;\n }\n\n /**\n * @return mixed[]\n */\n public function fetchRelatedActivity(Activity $activity): array\n {\n return [];\n }\n\n /**\n * @throws SocialAccountTokenInvalidException\n */\n private function validateUserAccountExists(User $user, ?SocialAccount $account = null): void\n {\n if ($account instanceof SocialAccount && $account->state === SocialAccount::STATE_CONNECTED) {\n return;\n }\n\n $this->logger->warning(\n sprintf('[%s] Account not connected for user', $this->getDisplayName()),\n [\n 'userId' => $user->getIdString(),\n 'account' => $account,\n ]\n );\n\n // If their profile was never setup in the first place\n if ($this->profile === null) {\n // Create a dummy in-memory profile just to be able to run\n $this->profile = new Profile();\n }\n\n if (! $account instanceof SocialAccount) {\n throw new SocialAccountTokenInvalidException(\n sprintf(\n 'Social account for %s cannot be found. Please login to Jiminny to connect.',\n $this->getDisplayName()\n )\n );\n }\n\n throw new SocialAccountTokenInvalidException(\n sprintf(\n 'Your %s account has become disconnected. Please login to Jiminny to reconnect.',\n $this->getDisplayName()\n )\n );\n }\n\n public function listSupportedObjectTypes(): array\n {\n return $this->getFieldTypes();\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"bounds":{"left":0.5265958,"top":0.074221864,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"bounds":{"left":0.53523934,"top":0.074221864,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"bounds":{"left":0.5462101,"top":0.074221864,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"bounds":{"left":0.55485374,"top":0.074221864,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"bounds":{"left":0.56349736,"top":0.074221864,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"bounds":{"left":0.5744681,"top":0.074221864,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"bounds":{"left":0.58543885,"top":0.074221864,"width":0.024268618,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"bounds":{"left":0.61203456,"top":0.074221864,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"bounds":{"left":0.62300533,"top":0.074221864,"width":0.029587766,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"bounds":{"left":0.9587766,"top":0.074221864,"width":0.02825798,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.94514626,"top":0.09896249,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.95511967,"top":0.09896249,"width":0.00731383,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.9644282,"top":0.09896249,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.09736632,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.09736632,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"# **************************** HS **************************************\n\nselect * from teams where id = 2; # 2\nselect * from features; # 2\nselect * from team_features where team_id = 2; # 2\nselect * from crm_configurations where id = 2; # 2\nselect * from users where team_id = 2; #\nselect * from playbooks where team_id = 2; # event 38\nselect * from playbook_categories where playbook_id = 38; #\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;\nhttps://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624\n https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0\n\nSELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;\n# 609126 softphone tr. 11241\n\nSELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;\n# 608874 conference tr. 11226 crmId: 103422236596\n\nselect * from ai_prompts where transcription_id IN (11241, 11226);\nselect * from activity_summary_logs where activity_id = 608874;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nselect * from crm_field_data where activity_id = 1223;\n\nselect * from crm_layouts where crm_configuration_id = 2;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);\nselect * from crm_fields where crm_configuration_id = 11 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);\n\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u\n on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 2 and sa.provider = 'hubspot';\n\nselect * from opportunities where team_id = 2\nand crm_provider_id IN ('51317301383');\n\nselect * from contacts where id = 85;\n\nselect * from opportunities where team_id = 2 order by id desc;\nselect * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112\nselect * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112\nselect * from opportunity_contacts where opportunity_id = 5117;\nselect * from crm_field_data where object_id = 1365;\nSELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);\n\nselect * from features;\nselect * from team_features where team_id IN (1);\nselect * from team_features where feature_id IN (36);\n\nSHOW CREATE TABLE opportunity_contacts;\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';\n\n# $slug = 'HUBSPOT_WEBHOOK_SYNC';\n# $team = Jiminny\\Models\\Team::find(2);\n# $feature = Feature::query()->where('slug', $slug)->first();\n# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);\n\n# hubspot_webhook_metrics\n\nselect * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365\nSELECT * FROM opportunity_contacts WHERE opportunity_id = '414';\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';\nselect * from contacts where id in (414, 464);\n\nselect * from activities where crm_configuration_id = 2;\n\nselect settings from crm_configurations where id = 11;\n\nselect * from teams; # 1, 2\nselect * from users;\nselect * from crm_configurations where id = 39;\nselect * from team_features where team_id = 2;\nselect * from features;\n# SELECT * FROM opportunities WHERE crm_configuration_id = 2\n# order by id desc;\n# and crm_provider_id = '49908861993';\n\n\nselect * from activity_providers where id IN (443, 202, 203, 227);\n\nselect * from activity_imports where id = 795889;\n\nselect c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id\nwhere c.provider = 'hubspot';\n\nselect * from crm_configurations crm JOIN teams t on crm.team_id = t.id\nwhere provider = 'hubspot';\nSELECT * FROM teams WHERE id = 31;\nSELECT * FROM users WHERE id = 257;\nSELECT * FROM opportunities WHERE team_id = 2;\n\nselect * from opportunity_contacts where opportunity_id = 5124;\nselect * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)\n\nselect * from activities where crm_configuration_id = 13;\n\nSELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141\n\n\nselect id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;\nSELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 order by id desc;\nselect * from opportunity_contacts where contact_id = 6223;\nSELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;\n\nselect * from crm_profiles where crm_configuration_id = 2;\n\nselect * from activities where account_id = 46;","depth":4,"value":"# **************************** HS **************************************\n\nselect * from teams where id = 2; # 2\nselect * from features; # 2\nselect * from team_features where team_id = 2; # 2\nselect * from crm_configurations where id = 2; # 2\nselect * from users where team_id = 2; #\nselect * from playbooks where team_id = 2; # event 38\nselect * from playbook_categories where playbook_id = 38; #\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;\nhttps://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624\n https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0\n\nSELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;\n# 609126 softphone tr. 11241\n\nSELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;\n# 608874 conference tr. 11226 crmId: 103422236596\n\nselect * from ai_prompts where transcription_id IN (11241, 11226);\nselect * from activity_summary_logs where activity_id = 608874;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nselect * from crm_field_data where activity_id = 1223;\n\nselect * from crm_layouts where crm_configuration_id = 2;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);\nselect * from crm_fields where crm_configuration_id = 11 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);\n\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u\n on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 2 and sa.provider = 'hubspot';\n\nselect * from opportunities where team_id = 2\nand crm_provider_id IN ('51317301383');\n\nselect * from contacts where id = 85;\n\nselect * from opportunities where team_id = 2 order by id desc;\nselect * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112\nselect * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112\nselect * from opportunity_contacts where opportunity_id = 5117;\nselect * from crm_field_data where object_id = 1365;\nSELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);\n\nselect * from features;\nselect * from team_features where team_id IN (1);\nselect * from team_features where feature_id IN (36);\n\nSHOW CREATE TABLE opportunity_contacts;\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';\n\n# $slug = 'HUBSPOT_WEBHOOK_SYNC';\n# $team = Jiminny\\Models\\Team::find(2);\n# $feature = Feature::query()->where('slug', $slug)->first();\n# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);\n\n# hubspot_webhook_metrics\n\nselect * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365\nSELECT * FROM opportunity_contacts WHERE opportunity_id = '414';\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';\nselect * from contacts where id in (414, 464);\n\nselect * from activities where crm_configuration_id = 2;\n\nselect settings from crm_configurations where id = 11;\n\nselect * from teams; # 1, 2\nselect * from users;\nselect * from crm_configurations where id = 39;\nselect * from team_features where team_id = 2;\nselect * from features;\n# SELECT * FROM opportunities WHERE crm_configuration_id = 2\n# order by id desc;\n# and crm_provider_id = '49908861993';\n\n\nselect * from activity_providers where id IN (443, 202, 203, 227);\n\nselect * from activity_imports where id = 795889;\n\nselect c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id\nwhere c.provider = 'hubspot';\n\nselect * from crm_configurations crm JOIN teams t on crm.team_id = t.id\nwhere provider = 'hubspot';\nSELECT * FROM teams WHERE id = 31;\nSELECT * FROM users WHERE id = 257;\nSELECT * FROM opportunities WHERE team_id = 2;\n\nselect * from opportunity_contacts where opportunity_id = 5124;\nselect * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)\n\nselect * from activities where crm_configuration_id = 13;\n\nSELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141\n\n\nselect id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;\nSELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 order by id desc;\nselect * from opportunity_contacts where contact_id = 6223;\nSELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;\n\nselect * from crm_profiles where crm_configuration_id = 2;\n\nselect * from activities where account_id = 46;","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-3901041415012267504
|
633758359911316605
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#11976 on JY-20553-debug- Project: faVsco.js, menu
#11976 on JY-20553-debug-crm-sync-delays, menu
Start Listening for PHP Debug Connections
RequestGenerateAskJiminnyReportJobTest
Run 'RequestGenerateAskJiminnyReportJobTest'
Debug 'RequestGenerateAskJiminnyReportJobTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
1
19
2
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm;
use Illuminate\Support\Collection;
use Jiminny\Component\Transcription\Service\TranscriptionService;
use Jiminny\Contracts\Services\Crm\ClientInterface;
use Jiminny\Contracts\Services\Crm\ConnectionStateInterface;
use Jiminny\Contracts\Services\Crm\Provider\HubspotInterface;
use Jiminny\Contracts\Services\Crm\ServiceInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SupportsObjectTypeParseInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Exceptions\HttpBadRequestException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Exceptions\LogicException;
use Jiminny\Exceptions\SocialAccountTokenInvalidException;
use Jiminny\Integrations\PlaybookResolver;
use Jiminny\Jobs\Crm\SyncFieldMetadata;
use Jiminny\Models;
use Jiminny\Models\Activity;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Crm\Layout;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\Crm\Helpers\ConnectionStateTrait;
use Jiminny\Services\Crm\Helpers\OpportunitySyncableFieldsTrait;
use Jiminny\Services\TeamService;
use Psr\Log\LoggerInterface;
use Sentry\State\Scope;
abstract class BaseService implements
ServiceInterface,
SettingsInterface,
SyncCrmEntitiesInterface,
ConnectionStateInterface
{
use ConnectionStateTrait;
use OpportunitySyncableFieldsTrait;
public const string OBJECT_LEAD = 'lead';
public const string OBJECT_ACCOUNT = 'account';
public const string OBJECT_CONTACT = 'contact';
public const string OBJECT_OPPORTUNITY = 'opportunity';
public const string OBJECT_TASK = 'task';
public const string OBJECT_EVENT = 'event';
public const int SOFT_DELETE_CHUNK = 100;
public const int HARD_DELETE_CHUNK = 1000;
public ?Configuration $config;
public ?Profile $profile;
public ?Team $team = null;
/**
* @var ClientInterface
*/
protected $client;
/**
* @var TeamService
*/
protected TeamService $teamService;
/**
* @var int
*/
protected int $limit;
/**
* @var int
*/
protected int $offset;
/**
* Transcription Service instance.
*
* @var TranscriptionService
*/
protected TranscriptionService $transcriptionService;
protected LoggerInterface $logger;
/**
* Cache for opportunity fields to avoid N+1 queries during batch imports.
* Key: crm_provider_id, Value: Field model with entities relation.
* Cleared when configuration changes.
*
* @var Collection<string, Field>|null
*/
private ?Collection $cachedOpportunityFields = null;
public function __construct()
{
$this->teamService = app(TeamService::class);
$this->transcriptionService = app(TranscriptionService::class);
$this->logger = app(LoggerInterface::class);
}
/**
* @param User $user
*
* @throws SocialAccountTokenInvalidException
*/
public function setUser(User $user): void
{
$this->configureSentryScope($user);
$this->team = $user->team;
$this->teamService->setTeam($user->team);
$this->setConfiguration($user->team->crm);
// Reset state.
$this->profile = $user->crmProfile;
/**
* DO NOT DELETE THIS `clearTokens` CALL
* The purpose of purging tokens is to fix a problem in importing calendar events.
* Calendar Import doesn't always respect "SocialAccountInvalidTokenException" exception
* and may try to recycle old SF instance, with wrong credentials (by ignoring the exception).
*
* This code guarantees the CRM Service is unusable, unless always provided with a valid social account.
*/
if (method_exists($this->client, 'clearTokens')) {
$this->client->clearTokens();
}
$account = $this->getOAuthAccount($user);
$this->validateUserAccountExists($user, $account);
if (method_exists($this->client, 'setOAuthAccount')) {
$this->client->setOAuthAccount($account);
}
if (method_exists($this->client, 'setLogger')) {
$this->client->setLogger($this->logger);
}
if ($this->profile === null) {
// Try to fetch their profile, maybe it was not yet imported?
$cacheKey = sprintf('crm_profile_sync-%s', $user->getId());
$lock = \Cache::lock($cacheKey, 300);
if ($lock->get()) {
$this->profile = $this->getProfile($user);
}
}
// The CRM Service is properly bootstrapped, and supports remote operations
$this->connect();
}
protected function configureSentryScope(User $user): void
{
\Sentry\configureScope(function (Scope $scope) use ($user): void {
$scope->setTag('team_id', (string) $user->getTeamId());
$scope->setUser([
'id' => $user->getId(),
'email' => $user->getEmailAddress(),
]);
});
}
/**
* @param User $user
*
* @return Profile|null
*/
protected function getProfile(User $user): ?Profile
{
return $this->syncProfiles($user);
}
public function getConfiguration(): Configuration
{
return $this->config;
}
public function setConfiguration(Configuration $config): void
{
$this->config = $config;
$this->client->setConfiguration($config);
// Clear field cache when configuration changes to ensure fresh data for new team/config
$this->cachedOpportunityFields = null;
if ($this->team === null) {
$this->team = $config->team;
}
}
public function setPage(int $limit, int $offset): void
{
$this->limit = $limit;
$this->offset = $offset;
}
abstract protected function getOAuthAccount(User $user): ?SocialAccount;
abstract protected function getDefaultFollowupLayoutFields(string $activityType): array;
abstract protected function getFieldTypes(): array;
abstract protected function getFields(string $fieldType): array;
public function syncFields(): void
{
foreach ($this->getFieldTypes() as $fieldType) {
$currentFields = $this->getFields($fieldType);
// TODO: only sync the field once a day if we don't use it in any layout. If we do, sync hourly?
foreach ($currentFields as $field) {
/** @var Models\Crm\Field $field */
$field = $this->config->fields()->updateOrCreate([
'crm_provider_id' => mb_strimwidth($field['name'], 0, 128),
'object_type' => $fieldType,
], [
'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),
]);
try {
$this->syncField($field);
if ($field->type === Models\Crm\Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
} catch (HttpNotFoundException $e) {
$this->logger->error('[sync-fields] Field not found', [
'provider' => $this->getDisplayName(),
'crm_field' => $field->crm_provider_id,
'object_type' => $field->object_type,
'team_id' => $this->team->id,
]);
} catch (HttpBadRequestException $e) {
$this->logger->error('[sync-fields] Field not supported', [
'provider' => $this->getDisplayName(),
'crm_field' => $field->crm_provider_id,
'object_type' => $field->object_type,
'team_id' => $this->team->id,
]);
}
}
}
}
/**
* @param string $objectId
* @param ?string $objectType
*
* @return array
*/
public function parseRecords(string $objectId, ?string $objectType = null): array
{
if ($objectType === null && $this instanceof SupportsObjectTypeParseInterface) {
$objectType = $this->parseObjectType($objectId);
}
$lead = null;
$contact = null;
$opportunity = null;
$account = null;
$stage = null;
$countryCode = null;
// Gather the prospect data to store on activity/participant.
switch ($objectType) {
case self::OBJECT_LEAD:
/** @var ?Lead $lead */
$lead = $this->config->leads()->where('crm_provider_id', $objectId)->first();
if ($lead === null) {
$lead = $this->syncLead($objectId);
}
if ($lead?->country_code) {
$countryCode = $lead->country_code;
}
$stage = $lead?->stage;
break;
case self::OBJECT_ACCOUNT:
$account = $this->config->accounts()->where('crm_provider_id', $objectId)->first();
if ($account === null) {
$account = $this->syncAccount($objectId);
}
if ($account->country_code) {
$countryCode = $account->country_code;
}
break;
case self::OBJECT_CONTACT:
$contact = $this->config->contacts()->where('crm_provider_id', $objectId)->first();
if ($contact === null) {
$contact = $this->syncContact($objectId);
}
if ($contact?->country_code) {
$countryCode = $contact->country_code;
}
$account = $contact?->account;
break;
case self::OBJECT_OPPORTUNITY:
$opportunity = $this->config->opportunities()->where('crm_provider_id', $objectId)->first();
if ($opportunity === null) {
$opportunity = $this->syncOpportunity($objectId);
}
if ($opportunity !== null) {
$stage = $opportunity->stage;
$account = $opportunity->account;
if ($account->country_code) {
$countryCode = $account->country_code;
}
}
break;
}
return [
$lead,
$account,
$opportunity,
$contact,
$stage,
$countryCode,
];
}
/**
* @param null|string $name
*
* @return null|string
*/
public function convertCountryNameToCode(?string $name): ?string
{
return app(CountryCodeResolver::class)->resolveCountryCode($name);
}
/**
* @param PlaybookCategory $category
*
* @return bool
*/
public function matchesCrmType(PlaybookCategory $category): bool
{
if ($category->playbook === null) {
return false;
}
if ($category->getPlaybook()->getActivityField() === null) {
return false;
}
$fieldValue = $category
->playbook
->activityField
->values()
->where('label', $category->name);
// Check the field values for a matching option.
return $fieldValue->exists();
}
/**
* @param PlaybookCategory $category
*
* @return FieldValue|null
*/
public function getCrmType(PlaybookCategory $category): ?FieldValue
{
$fieldValue = $category
->playbook
->activityField
->values()
->where('label', $category->name);
return $fieldValue->first();
}
/**
* @return int|float|string
*/
public function getMinimumApiVersion(): int|float|string
{
return $this->client->getMinimumApiVersion();
}
/**
* @param string $accountId
*
* @return bool
*/
protected function hasAccount(string $accountId): bool
{
return $this->config->accounts()->where('crm_provider_id', $accountId)->exists();
}
/**
* @param string $opportunityId
*
* @return bool
*/
protected function hasOpportunity(string $opportunityId): bool
{
return $this->config->opportunities()->where('crm_provider_id', $opportunityId)->exists();
}
/**
* @param string $contactId
*
* @return bool
*/
protected function hasContact(string $contactId): bool
{
return $this->config->contacts()->where('crm_provider_id', $contactId)->exists();
}
/**
* @param string $leadId
*
* @return bool
*/
protected function hasLead(string $leadId): bool
{
return $this->config->leads()->where('crm_provider_id', $leadId)->exists();
}
public function fetchAndAssociateRelatedActivity(Activity $activity): ?Activity
{
return null;
}
public function getJobDelay(): int
{
return 0;
}
public function getPlaybookFromActivity(Activity $activity): ?Playbook
{
if ($activity->hasActivityType() && $activity->getActivityType()->hasPlaybook()) {
return $activity->getActivityType()->getPlaybook();
}
return $this->getPlaybook($activity->getUser());
}
/**
* Gets the playbook for the user
*/
protected function getPlaybook(User $user): ?Playbook
{
$playbookResolver = app(PlaybookResolver::class);
return $playbookResolver->resolvePlaybookByUser($user);
}
/**
* @param Models\Playbook $playbook
* @param string $categoryName
*
* @return Models\PlaybookCategory|null
*/
protected function getPlaybookCategory(Models\Playbook $playbook, string $categoryName): ?Models\PlaybookCategory
{
return $playbook->categories()
->where('name', trim($categoryName))
->latest()
->first();
}
public function buildLayout(Layout $layout, ?string $activityType): void
{
if ($activityType) {
// Base section. Currently, the fields within are hard coded so this is empty for now.
/** @var Models\Crm\LayoutEntity $activitySection */
$activitySection = $layout->entities()->create([
'label' => 'activity-summary',
'description' => 'Activity Summary',
'sequence' => 0,
]);
if ($this instanceof HubspotInterface) {
$activityFields = $this->getDefaultActivityLayoutFields($activityType, $layout->type);
foreach ($activityFields as $i => $field) {
$layout->entities()->create([
'parent_entity_id' => $activitySection->getId(),
'crm_field_id' => $field->getId(),
'sequence' => $i,
]);
}
}
// Follow-up section. These are all dynamic fields.
$sectionTitle = ($layout->type === Layout::TYPE_CONFERENCE_SUMMARY ? 'Next Steps...' : 'Follow up?');
/** @var Models\Crm\LayoutEntity $followupSection */
$followupSection = $layout->entities()->create([
'label' => 'follow-up',
'description' => $sectionTitle,
'sequence' => 1,
]);
$followupFields = $this->getDefaultFollowupLayoutFields($activityType);
foreach ($followupFields as $i => $field) {
$layout->entities()->create([
'parent_entity_id' => $followupSection->getId(),
'crm_field_id' => $field->getId(),
'sequence' => $i,
]);
}
} elseif ($layout->type == Layout::TYPE_DEAL_INSIGHTS) {
$this->populateLayoutEntities($layout);
}
}
protected function populateLayoutEntities(Layout $layout): void
{
$dealFields = $this->getDefaultDealLayoutFields();
foreach ($dealFields as $i => $field) {
$readOnly = $field->getType() === Field::TYPE_CURRENCY
|| $this->isBusinessTypeField($field);
$layout->entities()->updateOrCreate([
'crm_field_id' => $field->id,
], [
'sequence' => $i,
'read_only' => $readOnly,
]);
}
}
public function prepareValueForUpdate(array $params): array
{
$fieldName = $params['fieldName'];
$fieldValue = $params['fieldValue'];
return [$fieldName => $fieldValue];
}
protected function getDefaultDealLayoutFields(): array
{
$fieldData = $this->getDealInsightsFields();
$fields = [];
foreach ($fieldData as $data) {
/** @var Field $field */
$field = $this->config->fields()->updateOrCreate([
'crm_provider_id' => $data['crm_provider_id'],
'object_type' => $data['object_type'],
], ['label' => $data['crm_provider_id']]);
try {
dispatch_sync(new SyncFieldMetadata($this->config->team, $field));
$field->refresh();
} catch (\Throwable $throwable) {
\Sentry::captureException($throwable);
}
$fields[] = $field;
}
return $fields;
}
public function importOpportunityCrmFieldData(array $crmData, array $crmFields, int $opportunityId): void
{
// Pre-fetch all opportunity fields once per batch to avoid N+1 queries.
// During webhook floods, this reduces DB queries from O(fields × deals) to O(1) for field lookups.
$fieldsMap = $this->getOpportunityFieldsMap();
foreach ($crmFields as $fieldName) {
$field = $fieldsMap->get($fieldName);
if (! $field instanceof Field) {
$this->logger->warning('Field not found', [
'field' => $fieldName,
'opportunity_id' => $opportunityId,
]);
continue;
}
// A CRM field data will be synced only if the field exists as part of at least one layout,
// i.e. an entity related to the field exists.
$entity = $field->entities->first();
if (! $entity instanceof Models\Crm\LayoutEntity) {
continue;
}
$fieldValue = $crmData[$fieldName] ?? '';
if (is_object($fieldValue)) {
$this->logger->warning('Field value is an object', [
'field' => $fieldName,
]);
continue;
}
$value = $this->normalizeValue($field->type, $fieldValue, true);
FieldData::updateOrCreate([
'crm_layout_entity_id' => $entity->id,
'crm_field_id' => $field->id,
'object_type' => 'opportunity',
'object_id' => $opportunityId,
], ['value' => $value]);
}
}
/**
* Get cached opportunity fields map for efficient lookups during batch imports.
*
* This method fetches all opportunity fields with their entities relation ONCE
* and caches them for the lifetime of this service instance. This eliminates
* the N+1 query problem where each field was fetched individually per deal.
*
* Performance impact:
* - Before: 10 fields × 100 deals = 1,000 field queries per batch
* - After: 1 query per batch (regardless of deal count)
*
* @return Collection<string, Field> Fields keyed by crm_provider_id
*/
private function getOpportunityFieldsMap(): Collection
{
if ($this->cachedOpportunityFields === null) {
$this->cachedOpportunityFields = $this->config->fields()
->with('entities')
->where('object_type', '=', self::OBJECT_OPPORTUNITY)
->get()
->keyBy('crm_provider_id');
}
return $this->cachedOpportunityFields;
}
/**
* @param array<mixed> $crmData
* @param Collection $crmFields
* @param int $objectId
*
* @return void
*/
public function importCrmFieldData(array $crmData, Collection $crmFields, int $objectId): void
{
/** @var Field $crmField */
foreach ($crmFields as $crmField) {
// If the field name does not match one we are interested in, skip.
if (array_key_exists($crmField->crm_provider_id, $crmData) === false) {
continue;
}
/** @var string $fieldValue */
$fieldValue = $crmData[$crmField->crm_provider_id];
$value = $this->normalizeValue($crmField->type, $fieldValue, true);
FieldData::updateOrCreate([
'crm_field_id' => $crmField->id,
'object_type' => $crmField->object_type,
'object_id' => $objectId,
], ['value' => $value]);
}
}
protected function getTeam(): Team
{
if (! $this->team instanceof Team) {
throw new LogicException('Expecting team model instance');
}
return $this->team;
}
public function isBusinessTypeField(Field $field): bool
{
return in_array($field->crm_provider_id, Field::BUSINESS_TYPE_FIELDS)
&& $field->object_type === Field::OBJECT_OPPORTUNITY;
}
/**
* @return mixed[]
*/
public function fetchRelatedActivity(Activity $activity): array
{
return [];
}
/**
* @throws SocialAccountTokenInvalidException
*/
private function validateUserAccountExists(User $user, ?SocialAccount $account = null): void
{
if ($account instanceof SocialAccount && $account->state === SocialAccount::STATE_CONNECTED) {
return;
}
$this->logger->warning(
sprintf('[%s] Account not connected for user', $this->getDisplayName()),
[
'userId' => $user->getIdString(),
'account' => $account,
]
);
// If their profile was never setup in the first place
if ($this->profile === null) {
// Create a dummy in-memory profile just to be able to run
$this->profile = new Profile();
}
if (! $account instanceof SocialAccount) {
throw new SocialAccountTokenInvalidException(
sprintf(
'Social account for %s cannot be found. Please login to Jiminny to connect.',
$this->getDisplayName()
)
);
}
throw new SocialAccountTokenInvalidException(
sprintf(
'Your %s account has become disconnected. Please login to Jiminny to reconnect.',
$this->getDisplayName()
)
);
}
public function listSupportedObjectTypes(): array
{
return $this->getFieldTypes();
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
6
1
6
Previous Highlighted Error
Next Highlighted Error
# [PASSWORD_DOTS] HS [PASSWORD_DOTS]
select * from teams where id = 2; # 2
select * from features; # 2
select * from team_features where team_id = 2; # 2
select * from crm_configurations where id = 2; # 2
select * from users where team_id = 2; #
select * from playbooks where team_id = 2; # event 38
select * from playbook_categories where playbook_id = 38; #
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;
https://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624
https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0
SELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;
# 609126 softphone tr. 11241
SELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;
# 608874 conference tr. 11226 crmId: 103422236596
select * from ai_prompts where transcription_id IN (11241, 11226);
select * from activity_summary_logs where activity_id = 608874;
select * from sidekick_settings;
select * from default_activity_types;
select * from crm_field_data where activity_id = 1223;
select * from crm_layouts where crm_configuration_id = 2;
SELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);
select * from crm_fields where crm_configuration_id = 11 and object_type = 'event';
SELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);
SELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;
SELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u
on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 2 and sa.provider = 'hubspot';
select * from opportunities where team_id = 2
and crm_provider_id IN ('51317301383');
select * from contacts where id = 85;
select * from opportunities where team_id = 2 order by id desc;
select * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112
select * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112
select * from opportunity_contacts where opportunity_id = 5117;
select * from crm_field_data where object_id = 1365;
SELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);
select * from features;
select * from team_features where team_id IN (1);
select * from team_features where feature_id IN (36);
SHOW CREATE TABLE opportunity_contacts;
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';
# $slug = 'HUBSPOT_WEBHOOK_SYNC';
# $team = Jiminny\Models\Team::find(2);
# $feature = Feature::query()->where('slug', $slug)->first();
# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);
# hubspot_webhook_metrics
select * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365
SELECT * FROM opportunity_contacts WHERE opportunity_id = '414';
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';
select * from contacts where id in (414, 464);
select * from activities where crm_configuration_id = 2;
select settings from crm_configurations where id = 11;
select * from teams; # 1, 2
select * from users;
select * from crm_configurations where id = 39;
select * from team_features where team_id = 2;
select * from features;
# SELECT * FROM opportunities WHERE crm_configuration_id = 2
# order by id desc;
# and crm_provider_id = '49908861993';
select * from activity_providers where id IN (443, 202, 203, 227);
select * from activity_imports where id = 795889;
select c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id
where c.provider = 'hubspot';
select * from crm_configurations crm JOIN teams t on crm.team_id = t.id
where provider = 'hubspot';
SELECT * FROM teams WHERE id = 31;
SELECT * FROM users WHERE id = 257;
SELECT * FROM opportunities WHERE team_id = 2;
select * from opportunity_contacts where opportunity_id = 5124;
select * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)
select * from activities where crm_configuration_id = 13;
SELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141
select id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;
SELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;
SELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;
SELECT * FROM contacts WHERE team_id = 2 order by id desc;
select * from opportunity_contacts where contact_id = 6223;
SELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;
select * from crm_profiles where crm_configuration_id = 2;
select * from activities where account_id = 46;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
55616
|
|
55533
|
NULL
|
0
|
2026-04-20T09:53:20.980246+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776678800980_m2.jpg...
|
PhpStorm
|
faVsco.js – OpportunitySyncTrait.php
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#11976 on JY-20553-debug- Project: faVsco.js, menu
#11976 on JY-20553-debug-crm-sync-delays, menu
Start Listening for PHP Debug Connections
RequestGenerateAskJiminnyReportJobTest
Run 'RequestGenerateAskJiminnyReportJobTest'
Debug 'RequestGenerateAskJiminnyReportJobTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
33
2
19
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot\ServiceTraits;
use Carbon\Carbon;
use HubSpot\Client\Crm\Deals\Model\CollectionResponseAssociatedId;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Exception;
use Jiminny\Component\DealInsights\Forecast\Forecast;
use Jiminny\Jobs\Crm\MatchActivitiesToNewOpportunity;
use Jiminny\Models\Contact;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Exceptions\CrmException;
use Jiminny\Models\Opportunity;
use Illuminate\Support\Collection;
use Jiminny\Models\Stage;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Services\Crm\Hubspot\DealFieldsService;
use Jiminny\Services\Crm\Hubspot\OpportunitySyncStrategy\HubspotSingleSyncStrategy;
use Jiminny\Services\Crm\Hubspot\WebhookSyncBatchProcessor;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Utils\CurrencyFormatter;
/**
* Optimized sync methods for better performance
* These methods can be integrated into SyncCrmEntitiesTrait for significant performance gains
*/
trait OpportunitySyncTrait
{
private const int BATCH_SIZE = 100;
private const int BATCH_PROCESS_SIZE = 800;
protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;
protected CrmEntityRepository $crmEntityRepository;
protected DealFieldsService $dealFieldsService;
private ?array $cachedClosedDealStages = null;
private array $cachedBusinessProcesses = [];
private array $cachedStages = [];
public function syncOpportunities(array $parameters, ?string $strategy = null): int
{
$startTime = microtime(true);
$strategies = $this->opportunitySyncStrategyResolver->getStrategies($this->config, $strategy);
$parameters['config'] = $this->config;
$syncCount = 0;
$reportedTotal = 0;
$lastSyncedId = [];
$strategyNames = [];
try {
foreach ($strategies as $strategyName => $syncStrategy) {
$strategyNames[] = $strategyName;
$this->logger->info(
'[' . $this->getDisplayName() . '] Syncing opportunities using strategy: ' . $strategyName,
['team' => $this->team->getId()]
);
$total = 0;
$lastId = null;
$buffer = [];
// HubspotWebhookBatchSyncStrategy returns empty generator, this is for other strategies
foreach ($syncStrategy->fetchOpportunities($parameters, $total, $lastId) as $hsOpportunity) {
$buffer[] = $hsOpportunity;
// process every 800 rows (fits < 1 000 association limit)
if (\count($buffer) >= self::BATCH_PROCESS_SIZE) {
$syncCount += $this->processOpportunityBatch($buffer);
$buffer = [];
}
}
// leftovers
if ($buffer) {
$syncCount += $this->processOpportunityBatch($buffer);
}
$reportedTotal += $total;
$lastSyncedId = $lastId;
}
} catch (\HubSpot\Client\Crm\Deals\ApiException | CrmException $e) {
$this->handleSyncException($e, $parameters);
}
$durationMs = round((microtime(true) - $startTime) * 1000, 2);
$this->logger->info(
'[HubSpot] Synced opportunities',
[
'team' => $this->team->getId(),
'strategies' => implode(',', $strategyNames),
'sync_count' => $syncCount,
'total' => $reportedTotal,
'last_synced_id' => $lastSyncedId,
'duration_ms' => $durationMs,
]
);
return $reportedTotal;
}
private function handleSyncException(\Throwable $e, array $parameters): void
{
if (($parameters['since'] ?? null) instanceof Carbon) {
$parameters['since'] = $parameters['since']->toDateTimeString();
}
$parameters['config'] = $this->config->getId();
$this->logger->warning('[' . $this->getDisplayName() . '] Sync opportunities failed', [
'teamId' => $this->team->getUuid(),
'parameters' => $parameters,
'reason' => $e->getMessage(),
]);
}
/**
* @inheritdoc
*/
public function syncOpportunity(string $crmId): ?Opportunity
{
$strategy = $this->opportunitySyncStrategyResolver->resolve(
$this->config,
OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY,
);
$parameters = [
'config' => $this->config,
'crm_id' => $crmId,
];
try {
if (! $strategy instanceof HubspotSingleSyncStrategy) {
throw new InvalidArgumentException('Strategy must by HubspotSingleSyncStrategy');
}
$hsOpportunity = $strategy->fetchOpportunity($parameters);
} catch (\HubSpot\Client\Crm\Deals\ApiException $e) {
$this->logger->info('[' . $this->getDisplayName() . '] Opportunity not found', [
'teamId' => $this->team->getUuid(),
'crmId' => $crmId,
'reason' => $e->getMessage(),
]);
return null;
}
$hsOpportunity['associations'] = $this->convertDealAssociations($hsOpportunity['associations'] ?? []);
return $this->importOrUpdateOpportunity($hsOpportunity);
}
/**
* Process webhook-collected opportunity batches.
*
* Drains Redis sets containing company CRM IDs collected from webhook events
* and dispatches ImportOpportunityBatch jobs for batch processing.
*
* @return int Number of opportunity IDs dispatched to jobs
*/
public function batchSyncOpportunities(): int
{
$configId = $this->team->getCrmConfiguration()->getId();
return $this->batchProcessor->processBatchesForObjectType(
WebhookSyncBatchProcessor::OBJECT_TYPE_DEAL,
$configId
);
}
/**
* Import a batch of opportunities by their CRM IDs.
* Fetches opportunity data from HubSpot API and delegates to importOpportunityBatch().
*
* @param array<string> $crmIds HubSpot deal CRM IDs
*
* @return array{success: array, failed_ids: array, errors?: array<string, string>}
*/
public function importOpportunityBatchByIds(array $crmIds): array
{
$fields = $this->dealFieldsService->getFieldsForConfiguration($this->config);
$allDeals = [];
foreach (array_chunk($crmIds, self::BATCH_SIZE) as $chunk) {
$deals = $this->client->getOpportunitiesByIds($chunk, $fields);
foreach ($deals as $deal) {
$allDeals[] = $deal;
}
}
// IDs not returned by HubSpot are likely deleted or inaccessible deals.
// These are not failures — retrying won't bring them back.
$fetchedIds = array_map('strval', array_column($allDeals, 'id'));
$notFoundIds = array_values(array_diff(array_map('strval', $crmIds), $fetchedIds));
if (! empty($notFoundIds)) {
$this->logger->info('[' . $this->getDisplayName() . '] CRM IDs not found in HubSpot (likely deleted)', [
'teamId' => $this->team->getId(),
'notFoundCount' => \count($notFoundIds),
'notFoundIds' => $notFoundIds,
'requestedCount' => \count($crmIds),
'fetchedCount' => \count($allDeals),
]);
}
if (empty($allDeals)) {
return ['success' => [], 'failed_ids' => []];
}
return $this->importOpportunityBatch($allDeals);
}
private function getClosedDealStages(): array
{
if ($this->cachedClosedDealStages !== null) {
return $this->cachedClosedDealStages;
}
$stages = $this->crmEntityRepository->getOpportunityClosedStages($this->config);
$data = [
'lost' => [],
'won' => [],
];
foreach ($stages as $stage) {
if ($stage->probability == 0.00) {
$data['lost'][] = $stage->crm_provider_id;
}
if ($stage->probability == 100.00) {
$data['won'][] = $stage->crm_provider_id;
}
}
$this->cachedClosedDealStages = $data;
return $data;
}
/**
* Import deals into the database with pre-fetched associations.
*
* API calls here (getAssociationsData, getExistingOpportunityCrmIds) are NOT
* caught — if they throw, the exception propagates to ImportOpportunityBatch::handle()
* where Laravel retries the whole job with backoff. After all retries exhausted,
* failed() requeues all IDs to Redis.
*
* The per-deal loop catches exceptions individually. A deal can end up in three states:
* - success: imported/updated successfully
* - failed_ids: exception thrown (DB constraint violation, corrupt data, etc.)
* These are permanent issues — retrying won't fix them.
* - skipped (null): missing dependencies (no account, unknown pipeline/stage).
* This is acceptable — the deal cannot be imported until those exist.
*/
private function importOpportunityBatch(array $deals): array
{
$syncedOpportunities = [
'success' => [],
'failed_ids' => [],
];
$dealIds = array_column($deals, 'id');
// Shared association/existing-ID preparation is batch-level state. If it fails, rethrow so the
// queue job retries the whole batch and eventually requeues all deal IDs back to Redis.
try {
$companyAssociations = $this->client->getAssociationsData($dealIds, 'deals', 'companies');
$contactAssociations = $this->client->getAssociationsData($dealIds, 'deals', 'contacts');
$associationsData = $this->prepareAssociatedEntities($companyAssociations, $contactAssociations);
$existingCrmIds = $this->crmEntityRepository->getExistingOpportunityCrmIds(
$this->config,
array_map('strval', $dealIds)
);
$existingCrmIdSet = array_flip($existingCrmIds);
} catch (\Throwable $e) {
$this->logger->error('[' . $this->getDisplayName() . '] Failed to fetch associations or existing IDs', [
'teamId' => $this->team->getId(),
'dealCount' => count($dealIds),
'error' => $e->getMessage(),
]);
throw $e;
}
foreach ($deals as $deal) {
try {
$deal['associations'] = $this->prepareAssociationsForOpportunity(
$deal['id'],
$companyAssociations,
$contactAssociations,
$associationsData
);
$syncedOpportunity = $this->importOrUpdateOpportunity(
$deal,
isset($existingCrmIdSet[(string) $deal['id']])
);
if ($syncedOpportunity) {
$syncedOpportunities['success'][] = $syncedOpportunity;
}
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Failed to import opportunity', [
'teamId' => $this->team->getId(),
'crmId' => $deal['id'],
'error' => $e->getMessage(),
]);
$syncedOpportunities['failed_ids'][] = $deal['id'];
$syncedOpportunities['errors'][$deal['id']] = $e->getMessage();
}
}
return $syncedOpportunities;
}
/**
* Prepare associated entities for opportunities with optimized batch processing
* Returns structured data with CRM ID to DB ID mappings for each opportunity
*/
private function prepareAssociatedEntities(array $companyAssociations, array $contactAssociations): array
{
// Step 1: Collect all unique company and contact IDs from associations
$allCompanyIds = $this->flattenAssociationIds($companyAssociations);
$allContactIds = $this->flattenAssociationIds($contactAssociations);
// Step 2: Batch sync missing entities and get CRM ID to DB ID mappings
$companyIdMappings = [];
$contactIdMappings = [];
if (! empty($allCompanyIds)) {
$companyIdMappings = $this->prepareAssociatedAccounts($allCompanyIds);
}
if (! empty($allContactIds)) {
$contactIdMappings = $this->prepareAssociatedContacts($allContactIds);
}
return [
'company_id_mappings' => $companyIdMappings,
'contact_id_mappings' => $contactIdMappings,
];
}
/**
* Flatten association data to get unique IDs
*/
private function flattenAssociationIds(array $associations): array
{
$ids = [];
foreach ($associations as $dealAssociations) {
if (is_array($dealAssociations)) {
foreach ($dealAssociations as $id) {
$ids[$id] = true;
}
}
}
return array_keys($ids);
}
/**
* Batch sync missing accounts
*/
private function prepareAssociatedAccounts(array $companyIds): array
{
// Find which accounts already exist
$existingAccounts = $this->crmEntityRepository
->findAccountsByExternalIds($this->config, $companyIds);
$existingCompanyIds = $existingAccounts->pluck('crm_provider_id')->toArray();
$existingAccountsData = $existingAccounts->mapWithKeys(function ($account) {
return [$account->getCrmProviderId() => $account->getId()];
})->toArray();
$missingCompanyIds = array_diff($companyIds, $existingCompanyIds);
if (empty($missingCompanyIds)) {
return $existingAccountsData;
}
$this->logger->info('[' . $this->getDisplayName() . '] Batch syncing missing accounts', [
'teamId' => $this->team->getUuid(),
'total_companies' => count($companyIds),
'existing_companies' => count($existingCompanyIds),
'missing_companies' => count($missingCompanyIds),
]);
// we already have limit on opportunity ids count
// Initialize variable before try block
$syncedAccountsData = [];
try {
$syncedAccountsData = $this->batchSyncCrmObjects('companies', $missingCompanyIds);
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Failed to sync missing accounts', [
'size' => count($missingCompanyIds),
'error' => $e->getMessage(),
]);
$syncedAccountsData = [];
}
return $existingAccountsData + $syncedAccountsData;
}
/**
* Prepare associated contacts - find existing and sync missing ones
* Returns mapping of CRM ID to DB ID
*/
private function prepareAssociatedContacts(array $contactIds): array
{
// Find which contacts already exist
$existingContacts = $this->crmEntityRepository
->findContactsByExternalIds($this->config, $contactIds);
$existingContactIds = $existingContacts->pluck('crm_provider_id')->toArray();
// Create mapping for existing contacts
$existingContactsData = $existingContacts->mapWithKeys(function ($contact) {
return [$contact->getCrmProviderId() => $contact->getId()];
})->toArray();
$missingContactIds = array_diff($contactIds, $existingContactIds);
if (empty($missingContactIds)) {
return $existingContactsData;
}
$this->logger->info('[' . $this->getDisplayName() . '] Batch syncing missing contacts', [
'teamId' => $this->team->getUuid(),
'total_contacts' => count($contactIds),
'existing_contacts' => count($existingContactIds),
'missing_contacts' => count($missingContactIds),
]);
// Sync missing contacts using batch API
try {
$syncedContactsData = $this->batchSyncCrmObjects('contacts', $missingContactIds);
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Failed to sync missing contacts', [
'size' => count($missingContactIds),
'error' => $e->getMessage(),
]);
$syncedContactsData = [];
}
return $existingContactsData + $syncedContactsData;
}
private function batchSyncCrmObjects(string $objectType, array $crmIds): array
{
$syncObjects = [];
$crmObjectIds = array_values($crmIds);
foreach (array_chunk($crmObjectIds, self::BATCH_SIZE) as $chunk) {
try {
$objects = $objectType === 'companies' ?
$this->client->getCompaniesByIds($chunk, $this->getCompanyFields()) :
$this->client->getContactsByIds($chunk, $this->getContactFields());
foreach ($objects as $objectId => $objectData) {
$this->importCrmObject($objectType, (string) $objectId, $objectData, $syncObjects);
}
$this->logger->info('[' . $this->getDisplayName() . '] Batch synced ' . $objectType, [
'requested_count' => count($chunk),
'synced_count' => count($objects),
]);
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Batch ' . $objectType . ' sync failed', [
'ids' => $chunk,
'error' => $e->getMessage(),
]);
}
}
return $syncObjects;
}
private function importCrmObject(string $objectType, string $objectId, mixed $objectData, array &$syncObjects): void
{
try {
$object = $objectType === 'companies' ?
$this->importAccount($objectData) :
$this->importContact($objectData);
if ($object) {
$syncObjects[$object->getCrmProviderId()] = $object->getId();
}
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Failed to import batch ' . $objectType, [
'id' => $objectId,
'error' => $e->getMessage(),
]);
}
}
/**
* Prepare associations for a single opportunity
*
* The return value is an array with the following structure:
* [
* 'companies' => [
* $companyCrmId => $companyId,
* ...
* ],
* 'contacts' => [
* $contactCrmId => $contactId,
* ...
* ],
* 'account_id' => $accountId,
* ]
*/
private function prepareAssociationsForOpportunity(
string $oppCrmId,
array $companyAssociations,
array $contactAssociations,
array $associationsData
): array {
$associations = [
'companies' => [],
'contacts' => [],
'account_id' => null, // Primary account for opportunity
];
$oppCompanyIds = $companyAssociations[$oppCrmId] ?? [];
foreach ($oppCompanyIds as $companyCrmId) {
if (isset($associationsData['company_id_mappings'][$companyCrmId])) {
$associations['companies'][$companyCrmId] = $associationsData['company_id_mappings'][$companyCrmId];
// Set primary account (first company becomes primary account)
if ($associations['account_id'] === null) {
$associations['account_id'] = $associationsData['company_id_mappings'][$companyCrmId];
}
}
}
$oppContactIds = $contactAssociations[$oppCrmId] ?? [];
foreach ($oppContactIds as $contactCrmId) {
if (isset($associationsData['contact_id_mappings'][$contactCrmId])) {
$associations['contacts'][$contactCrmId] = $associationsData['contact_id_mappings'][$contactCrmId];
}
}
return $associations;
}
/**
* Update only associations for an opportunity
*/
private function updateOpportunityAssociations(Opportunity $opportunity, array $associations): void
{
// Update contact associations
$this->importOpportunityContacts($opportunity, $associations['contacts']);
// Update company (account) associations
$this->updateOpportunityAccount($opportunity, $associations['account_id']);
}
/**
* Remove all contact associations from an opportunity
*/
private function removeAllOpportunityContacts(Opportunity $opportunity): void
{
$currentCount = (int) $opportunity->contacts()->count();
if ($currentCount > 0) {
$opportunity->contacts()->detach();
$this->logger->info('[' . $this->getDisplayName() . '] Removed all contact associations', [
'opportunity_id' => $opportunity->getId(),
'removed_count' => $currentCount,
]);
}
}
private function updateOpportunityAccount(Opportunity $opportunity, ?int $accountId): void
{
if ($accountId === null) {
// No account ID provided - keep current account
return;
}
$currentAccountId = $opportunity->getAccountId();
// Only update if account has changed
if ($currentAccountId !== $accountId) {
$opportunity->account_id = $accountId;
$opportunity->save();
$this->logger->info('[' . $this->getDisplayName() . '] Updated opportunity account association', [
'opportunity_id' => $opportunity->getId(),
'old_account_id' => $currentAccountId,
'new_account_id' => $accountId,
]);
}
}
/**
* Find existing opportunities by external IDs (OPTIMIZED VERSION)
* Uses batch query for better performance
*/
private function findExistingOpportunities(array $crmIds): Collection
{
return $this->crmEntityRepository
->findOpportunitiesByExternalIds($this->config, $crmIds);
}
private function processOpportunityBatch(array $opportunities): int
{
$syncedOpportunities = $this->importOpportunityBatch($opportunities);
return count($syncedOpportunities['success'] ?? []);
}
/**
* Convert single deal associations from HubSpot format to internal format
* Handles both HubSpot SDK objects and array formats
*
* @param array $opportunityAssociations Raw associations from HubSpot API or pre-processed
*
* @return array Processed associations with DB IDs
*/
private function convertDealAssociations(array $opportunityAssociations): array
{
$associations = $this->initializeAssociationsStructure();
if (empty($opportunityAssociations)) {
return $associations;
}
$associationIds = $this->extractAssociationIds($opportunityAssociations);
$this->processCompanyAssociations($associationIds, $associations);
$this->processContactAssociations($associationIds, $associations);
return $associations;
}
private function initializeAssociationsStructure(): array
{
return [
'companies' => [],
'contacts' => [],
'account_id' => null, // Primary account for opportunity
];
}
private function extractAssociationIds(array $opportunityAssociations): array
{
$associationIds = [];
foreach ($opportunityAssociations as $type => $associationData) {
if (! empty($associationData)) {
$associationIds[$type] = $this->convertSingleDealAssociations($associationData);
}
}
return $associationIds;
}
private function processCompanyAssociations(array $associationIds, array &$associations): void
{
if (empty($associationIds['companies'])) {
return;
}
$companyId = $associationIds['companies'][0];
$account = $this->findOrSyncAccount($companyId);
if ($account instanceof Account) {
$associations['companies'][$companyId] = $account->getId();
$associations['account_id'] = $account->getId();
}
}
private function processContactAssociations(array $associationIds, array &$associations): void
{
if (empty($associationIds['contacts'])) {
return;
}
foreach ($associationIds['contacts'] as $contactId) {
$contact = $this->findOrSyncContact($contactId);
if ($contact instanceof Contact) {
$associations['contacts'][$contactId] = $contact->getId();
}
}
}
private function findOrSyncAccount(string $companyId): ?Account
{
$account = $this->crmEntityRepository->findAccountByExternalId($this->config, $companyId);
if (! $account instanceof Account) {
$account = $this->syncAccount($companyId);
}
return $account;
}
private function findOrSyncContact(string $contactId): ?Contact
{
$contact = $this->crmEntityRepository->findContactByExternalId($this->config, $contactId);
if (! $contact instanceof Contact) {
$contact = $this->syncContact($contactId);
}
return $contact;
}
private function convertSingleDealAssociations($opportunityAssociations = null): array
{
$associationData = [];
if ($opportunityAssociations === null) {
return $associationData;
}
// Handle array input (from extractAssociationIds)
if (is_array($opportunityAssociations)) {
return $opportunityAssociations;
}
// Handle CollectionResponseAssociatedId object
if ($opportunityAssociations instanceof CollectionResponseAssociatedId) {
foreach ($opportunityAssociations->getResults() as $association) {
$associationData[] = $association->getId();
}
}
return $associationData;
}
private function importOrUpdateOpportunity($crmData, ?bool $exists = null): ?Opportunity
{
if (empty($crmData['properties'])) {
return null;
}
$crmId = (string) $crmData['id'];
$properties = $crmData['properties'];
$associations = $crmData['associations'] ?? [];
$opportunityExists = $exists ?? (bool) $this->crmEntityRepository->findOpportunityByExternalId(
$this->config,
$crmId
);
if ($opportunityExists) {
return $this->updateOpportunity($crmId, $properties, $associations);
}
return $this->createOpportunity($crmId, $properties, $associations);
}
/**
* Create new opportunity
*/
private function createOpportunity(string $crmId, array $properties, array $associations): ?Opportunity
{
$accountId = $this->resolveAccountId($associations);
if (! $accountId) {
return null;
}
$businessProcess = $this->resolveBusinessProcess($properties['pipeline'] ?? null);
if (! $businessProcess) {
return null;
}
$stage = $this->resolveStage($businessProcess, $properties['dealstage'] ?? null);
if (! $stage) {
return null;
}
$data = $this->buildOpportunityData($properties, $accountId, $businessProcess, $stage);
$attributes = [
'crm_configuration_id' => $this->config->getId(),
'crm_provider_id' => $crmId,
];
$values = array_merge($attributes, $data);
$opportunity = $this->crmEntityRepository->upsertOpportunity($attributes, $values);
$this->importExternalFieldData($properties, $opportunity->getId());
$this->importOpportunityContacts($opportunity, $associations['contacts']);
if ($opportunity->wasRecentlyCreated) {
MatchActivitiesToNewOpportunity::dispatch($opportunity->getId());
}
return $opportunity;
}
/**
* Update existing opportunity
*/
private function updateOpportunity(string $crmId, array $properties, array $associations): Opportunity
{
$accountId = $this->resolveAccountId($associations);
$businessProcess = $this->resolveBusinessProcess($properties['pipeline'] ?? null);
$stage = $businessProcess ? $this->resolveStage($businessProcess, $properties['dealstage'] ?? null) : null;
$data = $this->buildOpportunityData($properties, $accountId, $businessProcess, $stage);
$attributes = [
'crm_configuration_id' => $this->config->getId(),
'crm_provider_id' => $crmId,
];
$values = array_merge($attributes, $data);
$opportunity = $this->crmEntityRepository->upsertOpportunity($attributes, $values);
$this->importExternalFieldData($properties, $opportunity->getId());
$this->updateOpportunityAssociations($opportunity, $associations);
return $opportunity;
}
private function resolveAccountId(array $associations): ?int
{
if (! empty($associations['account_id'])) {
return $associations['account_id'];
}
if (empty($associations)) {
return null;
}
// Fallback: use first company as account (currently SDK returns one company)
foreach ($associations['companies'] as $accountId) {
return $accountId;
}
return null;
}
private function buildOpportunityData(
array $properties,
?int $accountId,
?BusinessProcess $businessProcess,
?Stage $stage
): array {
$ownerId = null;
$profile = null;
if (! empty($properties['hubspot_owner_id'])) {
$ownerId = $properties['hubspot_owner_id'];
$profile = $this->crmEntityRepository->findProfileByExternalId($this->config, (string) $ownerId);
}
$name = 'Unknown';
if (isset($properties['dealname'])) {
$name = mb_strimwidth($properties['dealname'], 0, 128);
}
$amount = $this->resolveAmount($properties);
$currency = $properties['deal_currency_code'] ?? null;
$closeDate = null;
if (! empty($properties['closedate'])) {
$closeDate = Carbon::parse($properties['closedate'])->format('Y-m-d');
}
$remotelyCreatedAt = null;
if (! empty($properties['createdate']) && strtotime($properties['createdate'])) {
$date = $this->parseCleanDatetime($properties['createdate']);
$remotelyCreatedAt = $date?->format('Y-m-d H:i:s');
}
$closedStages = $this->getClosedDealStages();
$isWon = in_array($properties['dealstage'], $closedStages['won']);
$isLost = in_array($properties['dealstage'], $closedStages['lost']);
$data = [
'team_id' => $this->team->getId(),
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $ownerId,
'name' => $name,
'value' => ! empty($amount) ? $amount : null,
'currency_code' => CurrencyFormatter::formatCode($currency),
'close_date' => $closeDate,
'is_closed' => $isWon || $isLost,
'is_won' => $isWon,
'remotely_created_at' => $remotelyCreatedAt,
'probability' => $this->resolveDealProbability($properties['hs_deal_stage_probability']),
'forecast_category' => $this->resolveForecastCategory($properties['hs_manual_forecast_category']),
];
if ($accountId) {
$data['account_id'] = $accountId;
}
if ($stage) {
$data['stage_id'] = $stage->id;
}
if ($businessProcess) {
$recordType = $this->crmEntityRepository->getBusinessProcessRecordType($businessProcess);
if ($recordType) {
$data['record_type_id'] = $recordType->id;
}
}
return $data;
}
private function resolveBusinessProcess(?string $pipelineId): ?BusinessProcess
{
if ($pipelineId === null) {
return null;
}
$cacheKey = $this->getBusinessProcessCacheKey($pipelineId);
if (isset($this->cachedBusinessProcesses[$cacheKey])) {
return $this->cachedBusinessProcesses[$cacheKey];
}
$businessProcess = $this->getBusinessProcess($pipelineId);
if (! $businessProcess instanceof BusinessProcess) {
$this->importStages();
$businessProcess = $this->getBusinessProcess($pipelineId);
}
if (! $businessProcess instanceof BusinessProcess) {
$this->logger->info(
'[HubSpot] Deal is not attached to a pipeline',
[
'pipeline' => $pipelineId]
);
}
$this->cachedBusinessProcesses[$cacheKey] = $businessProcess;
return $businessProcess;
}
private function getBusinessProcess(string $pipelineId): ?BusinessProcess
{
return $this->crmEntityRepository->findBusinessProcessesByExternalId($this->config, $pipelineId);
}
private function getBusinessProcessCacheKey(string $pipelineId): string
{
return $this->config->getId() . '_' . $pipelineId;
}
private function resolveStage(BusinessProcess $businessProcess, ?string $stageId): ?Stage
{
if (empty($stageId)) {
return null;
}
$cacheKey = $businessProcess->getId() . ':' . $stageId;
if (isset($this->cachedStages[$cacheKey])) {
return $this->cachedStages[$cacheKey];
}
$stage = $this->crmEntityRepository->getPipelineStageByConditions(
$businessProcess,
[
'crm_provider_id' => $stageId,
'type' => Stage::TYPE_OPPORTUNITY,
]
);
if ($stage === null) {
$this->importStages(null, $stageId);
}
if ($stage === null) {
$this->logger->info('[HubSpot] Stage does not exist => ' . $stageId);
}
$this->cachedStages[$cacheKey] = $stage;
return $stage;
}
private function resolveAmount(array $properties): ?string
{
$amount = null;
if (! empty($properties['amount'])) {
$amount = str_replace(',', '', $properties['amount']);
}
if ($this->config->hasDefaultCurrencyFieldSet()) {
$valueFieldName = $this->config->getDefaultCurrencyField()->getCrmProviderId();
$amount = $properties[$valueFieldName] ?? $amount;
}
return $amount;
}
private function parseCleanDatetime(string $datetime): ?Carbon
{
// Treat pre-1980 values as invalid
$minValidDate = Carbon::parse('1980-01-01 00:00:00');
try {
$date = Carbon::parse($datetime);
if ($minValidDate->gt($date)) {
return null;
}
return $date;
} catch (Exception) {
return null; // On parse error, treat as null
}
}
private function resolveDealProbability(?string $stageProbability): int
{
if ($stageProbability === null) {
return 0;
}
$probability = (float) $stageProbability;
return $probability > 1 ? 0 : (int) ($probability * 100);
}
private function resolveForecastCategory(?string $forecastCategory): string
{
if (! $forecastCategory) {
return Forecast::FORECAST_CATEGORY_UNCATEGORIZED;
}
$forecastCategory = str_replace('_', ' ', $forecastCategory);
return ucwords(strtolower($forecastCategory));
}
private function importExternalFieldData(array $properties, int $opportunityId): void
{
$crmFields = $this->getOpportunitySyncableFields();
$this->importOpportunityCrmFieldData($properties, $crmFields, $opportunityId);
}
private function importOpportunityContacts(Opportunity $opportunity, array $associations): void
{
// Handle empty or missing contact associations
if (empty($associations)) {
// Remove all existing contact associations if none provided
$this->removeAllOpportunityContacts($opportunity);
return;
}
// Use differential sync approach for better performance and accuracy
$this->syncOpportunityContactsDifferential($opportunity, $associations);
}
/**
* Sync opportunity contacts using differential approach
* This compares current vs new associations and only makes necessary changes
*/
private function syncOpportunityContactsDifferential(Opportunity $opportunity, array $contactAssociations): void
{
$currentContactCrmIds = $this->getCurrentContactCrmIds($opportunity);
$contactAssociationIds = array_keys($contactAssociations);
$contactsToAdd = array_diff($contactAssociationIds, $currentContactCrmIds);
$contactsToRemove = array_diff($currentContactCrmIds, $contactAssociationIds);
if (empty($contactsToAdd) && empty($contactsToRemove)) {
return;
}
$this->logContactAssociationChanges($opportunity, $currentContactCrmIds, $contactAssociations, $contactsToAdd, $contactsToRemove);
$this->removeContactAssociations($opportunity, $contactsToRemove);
$this->addContactAssociations($opportunity, $contactsToAdd, $contactAssociations);
}
private function getCurrentContactCrmIds(Opportunity $opportunity): array
{
return $opportunity->contacts()
->pluck('contacts.crm_provider_id')
->toArray();
}
private function logContactAssociationChanges(
Opportunity $opportunity,
array $currentContactCrmIds,
array $contactAssociations,
array $contactsToAdd,
array $contactsToRemove
): void {
$this->logger->info('[' . $this->getDisplayName() . '] Contact association changes', [
'opportunity_id' => $opportunity->getId(),
'current_contacts' => $currentContactCrmIds,
'new_contacts' => $contactAssociations,
'contacts_to_add' => $contactsToAdd,
'contacts_to_remove' => $contactsToRemove,
]);
}
private function removeContactAssociations(Opportunity $opportunity, array $contactsToRemove): void
{
if (empty($contactsToRemove)) {
return;
}
$contactsToDetach = $opportunity->contacts()
->whereIn('contacts.crm_provider_id', $contactsToRemove)
->pluck('contacts.id')
->toArray();
if (! empty($contactsToDetach)) {
$opportunity->contacts()->detach($contactsToDetach);
$this->logger->info('[' . $this->getDisplayName() . '] Removed contact associations', [
'opportunity_id' => $opportunity->getId(),
'removed_contact_crm_ids' => $contactsToRemove,
'removed_contact_count' => count($contactsToDetach),
]);
}
}
private function addContactAssociations(Opportunity $opportunity, array $contactsToAdd, array $contactAssociations): void
{
if (empty($contactsToAdd)) {
return;
}
$contactsAdded = [];
foreach ($contactsToAdd as $crmId) {
$id = $contactAssociations[$crmId];
if ($this->attachSingleContact($opportunity, (string) $crmId, $id)) {
$contactsAdded[] = $crmId;
}
}
$this->logAddedContacts($opportunity, $contactsAdded);
}
private function attachSingleContact(Opportunity $opportunity, string $crmId, int $id): bool
{
try {
$contact = $this->crmEntityRepository->findContactByConfigurationAndId($this->config, $id);
if (! $contact) {
return false;
}
return $this->performContactAttachment($opportunity, $contact, $crmId);
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Failed to add contact association', [
'opportunity_id' => $opportunity->getId(),
'contact_crm_id' => $crmId,
'error' => $e->getMessage(),
]);
return false;
}
}
private function performContactAttachment(Opportunity $opportunity, Contact $contact, string $crmId): bool
{
try {
$opportunity->contacts()->attach($contact->getId(), [
'crm_provider_id' => $crmId,
]);
return true;
} catch (\Illuminate\Database\QueryException $e) {
if (str_contains($e->getMessage(), 'Duplicate entry')) {
$this->logger->info('[' . $this->getDisplayName() . '] Contact association already exists', [
'contact_id' => $contact->getId(),
'contact_crm_id' => $crmId,
'opportunity_id' => $opportunity->getId(),
]);
return false;
}
throw $e;
}
}
private function logAddedContacts(Opportunity $opportunity, array $contactsAdded): void
{
if (! empty($contactsAdded)) {
$this->logger->info('[' . $this->getDisplayName() . '] Added contact associations', [
'opportunity_id' => $opportunity->getId(),
'added_contact_crm_ids' => $contactsAdded,
'added_contacts_count' => count($contactsAdded),
]);
}
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
6
1
6
Previous Highlighted Error
Next Highlighted Error
# [PASSWORD_DOTS] HS [PASSWORD_DOTS]
select * from teams where id = 2; # 2
select * from features; # 2
select * from team_features where team_id = 2; # 2
select * from crm_configurations where id = 2; # 2
select * from users where team_id = 2; #
select * from playbooks where team_id = 2; # event 38
select * from playbook_categories where playbook_id = 38; #
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;
https://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624
https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0
SELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;
# 609126 softphone tr. 11241
SELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;
# 608874 conference tr. 11226 crmId: 103422236596
select * from ai_prompts where transcription_id IN (11241, 11226);
select * from activity_summary_logs where activity_id = 608874;
select * from sidekick_settings;
select * from default_activity_types;
select * from crm_field_data where activity_id = 1223;
select * from crm_layouts where crm_configuration_id = 2;
SELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);
select * from crm_fields where crm_configuration_id = 11 and object_type = 'event';
SELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);
SELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;
SELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u
on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 2 and sa.provider = 'hubspot';
select * from opportunities where team_id = 2
and crm_provider_id IN ('51317301383');
select * from contacts where id = 85;
select * from opportunities where team_id = 2 order by id desc;
select * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112
select * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112
select * from opportunity_contacts where opportunity_id = 5117;
select * from crm_field_data where object_id = 1365;
SELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);
select * from features;
select * from team_features where team_id IN (1);
select * from team_features where feature_id IN (36);
SHOW CREATE TABLE opportunity_contacts;
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';
# $slug = 'HUBSPOT_WEBHOOK_SYNC';
# $team = Jiminny\Models\Team::find(2);
# $feature = Feature::query()->where('slug', $slug)->first();
# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);
# hubspot_webhook_metrics
select * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365
SELECT * FROM opportunity_contacts WHERE opportunity_id = '414';
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';
select * from contacts where id in (414, 464);
select * from activities where crm_configuration_id = 2;
select settings from crm_configurations where id = 11;
select * from teams; # 1, 2
select * from users;
select * from crm_configurations where id = 39;
select * from team_features where team_id = 2;
select * from features;
# SELECT * FROM opportunities WHERE crm_configuration_id = 2
# order by id desc;
# and crm_provider_id = '49908861993';
select * from activity_providers where id IN (443, 202, 203, 227);
select * from activity_imports where id = 795889;
select c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id
where c.provider = 'hubspot';
select * from crm_configurations crm JOIN teams t on crm.team_id = t.id
where provider = 'hubspot';
SELECT * FROM teams WHERE id = 31;
SELECT * FROM users WHERE id = 257;
SELECT * FROM opportunities WHERE team_id = 2;
select * from opportunity_contacts where opportunity_id = 5124;
select * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)
select * from activities where crm_configuration_id = 13;
SELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141
select id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;
SELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;
SELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;
SELECT * FROM contacts WHERE team_id = 2 order by id desc;
select * from opportunity_contacts where contact_id = 6223;
SELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;
select * from crm_profiles where crm_configuration_id = 2;
select * from activities where account_id = 46;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11976 on JY-20553-debug-crm-sync-delays, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.10837766,"height":0.025538707},"help_text":"Pull request #11976 exists for current branch JY-20553-debug-crm-sync-delays","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.7972075,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"RequestGenerateAskJiminnyReportJobTest","depth":6,"bounds":{"left":0.8125,"top":0.019952115,"width":0.10305851,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'RequestGenerateAskJiminnyReportJobTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'RequestGenerateAskJiminnyReportJobTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"33","depth":4,"bounds":{"left":0.47739363,"top":0.19952115,"width":0.010305851,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.48969415,"top":0.19952115,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"19","depth":4,"bounds":{"left":0.49966756,"top":0.19952115,"width":0.009640957,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.5109708,"top":0.19792499,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.51828456,"top":0.19792499,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits;\n\nuse Carbon\\Carbon;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\CollectionResponseAssociatedId;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Exception;\nuse Jiminny\\Component\\DealInsights\\Forecast\\Forecast;\nuse Jiminny\\Jobs\\Crm\\MatchActivitiesToNewOpportunity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Models\\Opportunity;\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Services\\Crm\\Hubspot\\DealFieldsService;\nuse Jiminny\\Services\\Crm\\Hubspot\\OpportunitySyncStrategy\\HubspotSingleSyncStrategy;\nuse Jiminny\\Services\\Crm\\Hubspot\\WebhookSyncBatchProcessor;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Utils\\CurrencyFormatter;\n\n/**\n * Optimized sync methods for better performance\n * These methods can be integrated into SyncCrmEntitiesTrait for significant performance gains\n */\ntrait OpportunitySyncTrait\n{\n private const int BATCH_SIZE = 100;\n private const int BATCH_PROCESS_SIZE = 800;\n\n protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;\n protected CrmEntityRepository $crmEntityRepository;\n protected DealFieldsService $dealFieldsService;\n\n private ?array $cachedClosedDealStages = null;\n private array $cachedBusinessProcesses = [];\n private array $cachedStages = [];\n\n public function syncOpportunities(array $parameters, ?string $strategy = null): int\n {\n $startTime = microtime(true);\n $strategies = $this->opportunitySyncStrategyResolver->getStrategies($this->config, $strategy);\n $parameters['config'] = $this->config;\n $syncCount = 0;\n $reportedTotal = 0;\n $lastSyncedId = [];\n $strategyNames = [];\n\n try {\n foreach ($strategies as $strategyName => $syncStrategy) {\n $strategyNames[] = $strategyName;\n $this->logger->info(\n '[' . $this->getDisplayName() . '] Syncing opportunities using strategy: ' . $strategyName,\n ['team' => $this->team->getId()]\n );\n\n $total = 0;\n $lastId = null;\n $buffer = [];\n\n // HubspotWebhookBatchSyncStrategy returns empty generator, this is for other strategies\n foreach ($syncStrategy->fetchOpportunities($parameters, $total, $lastId) as $hsOpportunity) {\n $buffer[] = $hsOpportunity;\n\n // process every 800 rows (fits < 1 000 association limit)\n if (\\count($buffer) >= self::BATCH_PROCESS_SIZE) {\n $syncCount += $this->processOpportunityBatch($buffer);\n $buffer = [];\n }\n }\n\n // leftovers\n if ($buffer) {\n $syncCount += $this->processOpportunityBatch($buffer);\n }\n\n $reportedTotal += $total;\n $lastSyncedId = $lastId;\n }\n } catch (\\HubSpot\\Client\\Crm\\Deals\\ApiException | CrmException $e) {\n $this->handleSyncException($e, $parameters);\n }\n\n $durationMs = round((microtime(true) - $startTime) * 1000, 2);\n $this->logger->info(\n '[HubSpot] Synced opportunities',\n [\n 'team' => $this->team->getId(),\n 'strategies' => implode(',', $strategyNames),\n 'sync_count' => $syncCount,\n 'total' => $reportedTotal,\n 'last_synced_id' => $lastSyncedId,\n 'duration_ms' => $durationMs,\n ]\n );\n\n return $reportedTotal;\n }\n\n private function handleSyncException(\\Throwable $e, array $parameters): void\n {\n if (($parameters['since'] ?? null) instanceof Carbon) {\n $parameters['since'] = $parameters['since']->toDateTimeString();\n }\n $parameters['config'] = $this->config->getId();\n\n $this->logger->warning('[' . $this->getDisplayName() . '] Sync opportunities failed', [\n 'teamId' => $this->team->getUuid(),\n 'parameters' => $parameters,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n /**\n * @inheritdoc\n */\n public function syncOpportunity(string $crmId): ?Opportunity\n {\n $strategy = $this->opportunitySyncStrategyResolver->resolve(\n $this->config,\n OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY,\n );\n\n $parameters = [\n 'config' => $this->config,\n 'crm_id' => $crmId,\n ];\n\n try {\n if (! $strategy instanceof HubspotSingleSyncStrategy) {\n throw new InvalidArgumentException('Strategy must by HubspotSingleSyncStrategy');\n }\n\n $hsOpportunity = $strategy->fetchOpportunity($parameters);\n } catch (\\HubSpot\\Client\\Crm\\Deals\\ApiException $e) {\n $this->logger->info('[' . $this->getDisplayName() . '] Opportunity not found', [\n 'teamId' => $this->team->getUuid(),\n 'crmId' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n return null;\n }\n\n $hsOpportunity['associations'] = $this->convertDealAssociations($hsOpportunity['associations'] ?? []);\n\n return $this->importOrUpdateOpportunity($hsOpportunity);\n }\n\n /**\n * Process webhook-collected opportunity batches.\n *\n * Drains Redis sets containing company CRM IDs collected from webhook events\n * and dispatches ImportOpportunityBatch jobs for batch processing.\n *\n * @return int Number of opportunity IDs dispatched to jobs\n */\n public function batchSyncOpportunities(): int\n {\n $configId = $this->team->getCrmConfiguration()->getId();\n\n return $this->batchProcessor->processBatchesForObjectType(\n WebhookSyncBatchProcessor::OBJECT_TYPE_DEAL,\n $configId\n );\n }\n\n /**\n * Import a batch of opportunities by their CRM IDs.\n * Fetches opportunity data from HubSpot API and delegates to importOpportunityBatch().\n *\n * @param array<string> $crmIds HubSpot deal CRM IDs\n *\n * @return array{success: array, failed_ids: array, errors?: array<string, string>}\n */\n public function importOpportunityBatchByIds(array $crmIds): array\n {\n $fields = $this->dealFieldsService->getFieldsForConfiguration($this->config);\n\n $allDeals = [];\n foreach (array_chunk($crmIds, self::BATCH_SIZE) as $chunk) {\n $deals = $this->client->getOpportunitiesByIds($chunk, $fields);\n foreach ($deals as $deal) {\n $allDeals[] = $deal;\n }\n }\n\n // IDs not returned by HubSpot are likely deleted or inaccessible deals.\n // These are not failures — retrying won't bring them back.\n $fetchedIds = array_map('strval', array_column($allDeals, 'id'));\n $notFoundIds = array_values(array_diff(array_map('strval', $crmIds), $fetchedIds));\n\n if (! empty($notFoundIds)) {\n $this->logger->info('[' . $this->getDisplayName() . '] CRM IDs not found in HubSpot (likely deleted)', [\n 'teamId' => $this->team->getId(),\n 'notFoundCount' => \\count($notFoundIds),\n 'notFoundIds' => $notFoundIds,\n 'requestedCount' => \\count($crmIds),\n 'fetchedCount' => \\count($allDeals),\n ]);\n }\n\n if (empty($allDeals)) {\n return ['success' => [], 'failed_ids' => []];\n }\n\n return $this->importOpportunityBatch($allDeals);\n }\n\n private function getClosedDealStages(): array\n {\n if ($this->cachedClosedDealStages !== null) {\n return $this->cachedClosedDealStages;\n }\n\n $stages = $this->crmEntityRepository->getOpportunityClosedStages($this->config);\n $data = [\n 'lost' => [],\n 'won' => [],\n ];\n\n foreach ($stages as $stage) {\n if ($stage->probability == 0.00) {\n $data['lost'][] = $stage->crm_provider_id;\n }\n if ($stage->probability == 100.00) {\n $data['won'][] = $stage->crm_provider_id;\n }\n }\n\n $this->cachedClosedDealStages = $data;\n\n return $data;\n }\n\n /**\n * Import deals into the database with pre-fetched associations.\n *\n * API calls here (getAssociationsData, getExistingOpportunityCrmIds) are NOT\n * caught — if they throw, the exception propagates to ImportOpportunityBatch::handle()\n * where Laravel retries the whole job with backoff. After all retries exhausted,\n * failed() requeues all IDs to Redis.\n *\n * The per-deal loop catches exceptions individually. A deal can end up in three states:\n * - success: imported/updated successfully\n * - failed_ids: exception thrown (DB constraint violation, corrupt data, etc.)\n * These are permanent issues — retrying won't fix them.\n * - skipped (null): missing dependencies (no account, unknown pipeline/stage).\n * This is acceptable — the deal cannot be imported until those exist.\n */\n private function importOpportunityBatch(array $deals): array\n {\n $syncedOpportunities = [\n 'success' => [],\n 'failed_ids' => [],\n ];\n $dealIds = array_column($deals, 'id');\n\n // Shared association/existing-ID preparation is batch-level state. If it fails, rethrow so the\n // queue job retries the whole batch and eventually requeues all deal IDs back to Redis.\n try {\n $companyAssociations = $this->client->getAssociationsData($dealIds, 'deals', 'companies');\n $contactAssociations = $this->client->getAssociationsData($dealIds, 'deals', 'contacts');\n\n $associationsData = $this->prepareAssociatedEntities($companyAssociations, $contactAssociations);\n\n $existingCrmIds = $this->crmEntityRepository->getExistingOpportunityCrmIds(\n $this->config,\n array_map('strval', $dealIds)\n );\n $existingCrmIdSet = array_flip($existingCrmIds);\n } catch (\\Throwable $e) {\n $this->logger->error('[' . $this->getDisplayName() . '] Failed to fetch associations or existing IDs', [\n 'teamId' => $this->team->getId(),\n 'dealCount' => count($dealIds),\n 'error' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n foreach ($deals as $deal) {\n try {\n $deal['associations'] = $this->prepareAssociationsForOpportunity(\n $deal['id'],\n $companyAssociations,\n $contactAssociations,\n $associationsData\n );\n\n $syncedOpportunity = $this->importOrUpdateOpportunity(\n $deal,\n isset($existingCrmIdSet[(string) $deal['id']])\n );\n if ($syncedOpportunity) {\n $syncedOpportunities['success'][] = $syncedOpportunity;\n }\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Failed to import opportunity', [\n 'teamId' => $this->team->getId(),\n 'crmId' => $deal['id'],\n 'error' => $e->getMessage(),\n ]);\n $syncedOpportunities['failed_ids'][] = $deal['id'];\n $syncedOpportunities['errors'][$deal['id']] = $e->getMessage();\n }\n }\n\n return $syncedOpportunities;\n }\n\n /**\n * Prepare associated entities for opportunities with optimized batch processing\n * Returns structured data with CRM ID to DB ID mappings for each opportunity\n */\n private function prepareAssociatedEntities(array $companyAssociations, array $contactAssociations): array\n {\n // Step 1: Collect all unique company and contact IDs from associations\n $allCompanyIds = $this->flattenAssociationIds($companyAssociations);\n $allContactIds = $this->flattenAssociationIds($contactAssociations);\n\n // Step 2: Batch sync missing entities and get CRM ID to DB ID mappings\n $companyIdMappings = [];\n $contactIdMappings = [];\n\n if (! empty($allCompanyIds)) {\n $companyIdMappings = $this->prepareAssociatedAccounts($allCompanyIds);\n }\n\n if (! empty($allContactIds)) {\n $contactIdMappings = $this->prepareAssociatedContacts($allContactIds);\n }\n\n return [\n 'company_id_mappings' => $companyIdMappings,\n 'contact_id_mappings' => $contactIdMappings,\n ];\n }\n\n /**\n * Flatten association data to get unique IDs\n */\n private function flattenAssociationIds(array $associations): array\n {\n $ids = [];\n foreach ($associations as $dealAssociations) {\n if (is_array($dealAssociations)) {\n foreach ($dealAssociations as $id) {\n $ids[$id] = true;\n }\n }\n }\n\n return array_keys($ids);\n }\n\n /**\n * Batch sync missing accounts\n */\n private function prepareAssociatedAccounts(array $companyIds): array\n {\n // Find which accounts already exist\n $existingAccounts = $this->crmEntityRepository\n ->findAccountsByExternalIds($this->config, $companyIds);\n\n $existingCompanyIds = $existingAccounts->pluck('crm_provider_id')->toArray();\n\n $existingAccountsData = $existingAccounts->mapWithKeys(function ($account) {\n return [$account->getCrmProviderId() => $account->getId()];\n })->toArray();\n\n $missingCompanyIds = array_diff($companyIds, $existingCompanyIds);\n\n if (empty($missingCompanyIds)) {\n return $existingAccountsData;\n }\n\n $this->logger->info('[' . $this->getDisplayName() . '] Batch syncing missing accounts', [\n 'teamId' => $this->team->getUuid(),\n 'total_companies' => count($companyIds),\n 'existing_companies' => count($existingCompanyIds),\n 'missing_companies' => count($missingCompanyIds),\n ]);\n\n // we already have limit on opportunity ids count\n // Initialize variable before try block\n $syncedAccountsData = [];\n\n try {\n $syncedAccountsData = $this->batchSyncCrmObjects('companies', $missingCompanyIds);\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Failed to sync missing accounts', [\n 'size' => count($missingCompanyIds),\n 'error' => $e->getMessage(),\n ]);\n $syncedAccountsData = [];\n }\n\n return $existingAccountsData + $syncedAccountsData;\n }\n\n /**\n * Prepare associated contacts - find existing and sync missing ones\n * Returns mapping of CRM ID to DB ID\n */\n private function prepareAssociatedContacts(array $contactIds): array\n {\n // Find which contacts already exist\n $existingContacts = $this->crmEntityRepository\n ->findContactsByExternalIds($this->config, $contactIds);\n\n $existingContactIds = $existingContacts->pluck('crm_provider_id')->toArray();\n\n // Create mapping for existing contacts\n $existingContactsData = $existingContacts->mapWithKeys(function ($contact) {\n return [$contact->getCrmProviderId() => $contact->getId()];\n })->toArray();\n\n $missingContactIds = array_diff($contactIds, $existingContactIds);\n\n if (empty($missingContactIds)) {\n return $existingContactsData;\n }\n\n $this->logger->info('[' . $this->getDisplayName() . '] Batch syncing missing contacts', [\n 'teamId' => $this->team->getUuid(),\n 'total_contacts' => count($contactIds),\n 'existing_contacts' => count($existingContactIds),\n 'missing_contacts' => count($missingContactIds),\n ]);\n\n // Sync missing contacts using batch API\n try {\n $syncedContactsData = $this->batchSyncCrmObjects('contacts', $missingContactIds);\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Failed to sync missing contacts', [\n 'size' => count($missingContactIds),\n 'error' => $e->getMessage(),\n ]);\n $syncedContactsData = [];\n }\n\n return $existingContactsData + $syncedContactsData;\n }\n\n private function batchSyncCrmObjects(string $objectType, array $crmIds): array\n {\n $syncObjects = [];\n $crmObjectIds = array_values($crmIds);\n\n foreach (array_chunk($crmObjectIds, self::BATCH_SIZE) as $chunk) {\n try {\n $objects = $objectType === 'companies' ?\n $this->client->getCompaniesByIds($chunk, $this->getCompanyFields()) :\n $this->client->getContactsByIds($chunk, $this->getContactFields());\n\n foreach ($objects as $objectId => $objectData) {\n $this->importCrmObject($objectType, (string) $objectId, $objectData, $syncObjects);\n }\n\n $this->logger->info('[' . $this->getDisplayName() . '] Batch synced ' . $objectType, [\n 'requested_count' => count($chunk),\n 'synced_count' => count($objects),\n ]);\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Batch ' . $objectType . ' sync failed', [\n 'ids' => $chunk,\n 'error' => $e->getMessage(),\n ]);\n }\n }\n\n return $syncObjects;\n }\n\n private function importCrmObject(string $objectType, string $objectId, mixed $objectData, array &$syncObjects): void\n {\n try {\n $object = $objectType === 'companies' ?\n $this->importAccount($objectData) :\n $this->importContact($objectData);\n\n if ($object) {\n $syncObjects[$object->getCrmProviderId()] = $object->getId();\n }\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Failed to import batch ' . $objectType, [\n 'id' => $objectId,\n 'error' => $e->getMessage(),\n ]);\n }\n }\n\n /**\n * Prepare associations for a single opportunity\n *\n * The return value is an array with the following structure:\n * [\n * 'companies' => [\n * $companyCrmId => $companyId,\n * ...\n * ],\n * 'contacts' => [\n * $contactCrmId => $contactId,\n * ...\n * ],\n * 'account_id' => $accountId,\n * ]\n */\n private function prepareAssociationsForOpportunity(\n string $oppCrmId,\n array $companyAssociations,\n array $contactAssociations,\n array $associationsData\n ): array {\n $associations = [\n 'companies' => [],\n 'contacts' => [],\n 'account_id' => null, // Primary account for opportunity\n ];\n\n $oppCompanyIds = $companyAssociations[$oppCrmId] ?? [];\n foreach ($oppCompanyIds as $companyCrmId) {\n if (isset($associationsData['company_id_mappings'][$companyCrmId])) {\n $associations['companies'][$companyCrmId] = $associationsData['company_id_mappings'][$companyCrmId];\n\n // Set primary account (first company becomes primary account)\n if ($associations['account_id'] === null) {\n $associations['account_id'] = $associationsData['company_id_mappings'][$companyCrmId];\n }\n }\n }\n\n $oppContactIds = $contactAssociations[$oppCrmId] ?? [];\n foreach ($oppContactIds as $contactCrmId) {\n if (isset($associationsData['contact_id_mappings'][$contactCrmId])) {\n $associations['contacts'][$contactCrmId] = $associationsData['contact_id_mappings'][$contactCrmId];\n }\n }\n\n return $associations;\n }\n\n /**\n * Update only associations for an opportunity\n */\n private function updateOpportunityAssociations(Opportunity $opportunity, array $associations): void\n {\n // Update contact associations\n $this->importOpportunityContacts($opportunity, $associations['contacts']);\n\n // Update company (account) associations\n $this->updateOpportunityAccount($opportunity, $associations['account_id']);\n }\n\n /**\n * Remove all contact associations from an opportunity\n */\n private function removeAllOpportunityContacts(Opportunity $opportunity): void\n {\n $currentCount = (int) $opportunity->contacts()->count();\n\n if ($currentCount > 0) {\n $opportunity->contacts()->detach();\n\n $this->logger->info('[' . $this->getDisplayName() . '] Removed all contact associations', [\n 'opportunity_id' => $opportunity->getId(),\n 'removed_count' => $currentCount,\n ]);\n }\n }\n\n private function updateOpportunityAccount(Opportunity $opportunity, ?int $accountId): void\n {\n if ($accountId === null) {\n // No account ID provided - keep current account\n return;\n }\n\n $currentAccountId = $opportunity->getAccountId();\n\n // Only update if account has changed\n if ($currentAccountId !== $accountId) {\n $opportunity->account_id = $accountId;\n $opportunity->save();\n\n $this->logger->info('[' . $this->getDisplayName() . '] Updated opportunity account association', [\n 'opportunity_id' => $opportunity->getId(),\n 'old_account_id' => $currentAccountId,\n 'new_account_id' => $accountId,\n ]);\n }\n }\n\n /**\n * Find existing opportunities by external IDs (OPTIMIZED VERSION)\n * Uses batch query for better performance\n */\n private function findExistingOpportunities(array $crmIds): Collection\n {\n return $this->crmEntityRepository\n ->findOpportunitiesByExternalIds($this->config, $crmIds);\n }\n\n private function processOpportunityBatch(array $opportunities): int\n {\n $syncedOpportunities = $this->importOpportunityBatch($opportunities);\n\n return count($syncedOpportunities['success'] ?? []);\n }\n\n /**\n * Convert single deal associations from HubSpot format to internal format\n * Handles both HubSpot SDK objects and array formats\n *\n * @param array $opportunityAssociations Raw associations from HubSpot API or pre-processed\n *\n * @return array Processed associations with DB IDs\n */\n private function convertDealAssociations(array $opportunityAssociations): array\n {\n $associations = $this->initializeAssociationsStructure();\n\n if (empty($opportunityAssociations)) {\n return $associations;\n }\n\n $associationIds = $this->extractAssociationIds($opportunityAssociations);\n\n $this->processCompanyAssociations($associationIds, $associations);\n $this->processContactAssociations($associationIds, $associations);\n\n return $associations;\n }\n\n private function initializeAssociationsStructure(): array\n {\n return [\n 'companies' => [],\n 'contacts' => [],\n 'account_id' => null, // Primary account for opportunity\n ];\n }\n\n private function extractAssociationIds(array $opportunityAssociations): array\n {\n $associationIds = [];\n\n foreach ($opportunityAssociations as $type => $associationData) {\n if (! empty($associationData)) {\n $associationIds[$type] = $this->convertSingleDealAssociations($associationData);\n }\n }\n\n return $associationIds;\n }\n\n private function processCompanyAssociations(array $associationIds, array &$associations): void\n {\n if (empty($associationIds['companies'])) {\n return;\n }\n\n $companyId = $associationIds['companies'][0];\n $account = $this->findOrSyncAccount($companyId);\n\n if ($account instanceof Account) {\n $associations['companies'][$companyId] = $account->getId();\n $associations['account_id'] = $account->getId();\n }\n }\n\n private function processContactAssociations(array $associationIds, array &$associations): void\n {\n if (empty($associationIds['contacts'])) {\n return;\n }\n\n foreach ($associationIds['contacts'] as $contactId) {\n $contact = $this->findOrSyncContact($contactId);\n\n if ($contact instanceof Contact) {\n $associations['contacts'][$contactId] = $contact->getId();\n }\n }\n }\n\n private function findOrSyncAccount(string $companyId): ?Account\n {\n $account = $this->crmEntityRepository->findAccountByExternalId($this->config, $companyId);\n\n if (! $account instanceof Account) {\n $account = $this->syncAccount($companyId);\n }\n\n return $account;\n }\n\n private function findOrSyncContact(string $contactId): ?Contact\n {\n $contact = $this->crmEntityRepository->findContactByExternalId($this->config, $contactId);\n\n if (! $contact instanceof Contact) {\n $contact = $this->syncContact($contactId);\n }\n\n return $contact;\n }\n\n private function convertSingleDealAssociations($opportunityAssociations = null): array\n {\n $associationData = [];\n\n if ($opportunityAssociations === null) {\n return $associationData;\n }\n\n // Handle array input (from extractAssociationIds)\n if (is_array($opportunityAssociations)) {\n return $opportunityAssociations;\n }\n\n // Handle CollectionResponseAssociatedId object\n if ($opportunityAssociations instanceof CollectionResponseAssociatedId) {\n foreach ($opportunityAssociations->getResults() as $association) {\n $associationData[] = $association->getId();\n }\n }\n\n return $associationData;\n }\n\n private function importOrUpdateOpportunity($crmData, ?bool $exists = null): ?Opportunity\n {\n if (empty($crmData['properties'])) {\n return null;\n }\n\n $crmId = (string) $crmData['id'];\n $properties = $crmData['properties'];\n $associations = $crmData['associations'] ?? [];\n\n $opportunityExists = $exists ?? (bool) $this->crmEntityRepository->findOpportunityByExternalId(\n $this->config,\n $crmId\n );\n\n if ($opportunityExists) {\n return $this->updateOpportunity($crmId, $properties, $associations);\n }\n\n return $this->createOpportunity($crmId, $properties, $associations);\n }\n\n /**\n * Create new opportunity\n */\n private function createOpportunity(string $crmId, array $properties, array $associations): ?Opportunity\n {\n $accountId = $this->resolveAccountId($associations);\n if (! $accountId) {\n return null;\n }\n\n $businessProcess = $this->resolveBusinessProcess($properties['pipeline'] ?? null);\n if (! $businessProcess) {\n return null;\n }\n\n $stage = $this->resolveStage($businessProcess, $properties['dealstage'] ?? null);\n if (! $stage) {\n return null;\n }\n\n $data = $this->buildOpportunityData($properties, $accountId, $businessProcess, $stage);\n\n $attributes = [\n 'crm_configuration_id' => $this->config->getId(),\n 'crm_provider_id' => $crmId,\n ];\n\n $values = array_merge($attributes, $data);\n\n $opportunity = $this->crmEntityRepository->upsertOpportunity($attributes, $values);\n\n $this->importExternalFieldData($properties, $opportunity->getId());\n $this->importOpportunityContacts($opportunity, $associations['contacts']);\n\n if ($opportunity->wasRecentlyCreated) {\n MatchActivitiesToNewOpportunity::dispatch($opportunity->getId());\n }\n\n return $opportunity;\n }\n\n /**\n * Update existing opportunity\n */\n private function updateOpportunity(string $crmId, array $properties, array $associations): Opportunity\n {\n $accountId = $this->resolveAccountId($associations);\n $businessProcess = $this->resolveBusinessProcess($properties['pipeline'] ?? null);\n $stage = $businessProcess ? $this->resolveStage($businessProcess, $properties['dealstage'] ?? null) : null;\n\n $data = $this->buildOpportunityData($properties, $accountId, $businessProcess, $stage);\n\n $attributes = [\n 'crm_configuration_id' => $this->config->getId(),\n 'crm_provider_id' => $crmId,\n ];\n\n $values = array_merge($attributes, $data);\n $opportunity = $this->crmEntityRepository->upsertOpportunity($attributes, $values);\n\n $this->importExternalFieldData($properties, $opportunity->getId());\n $this->updateOpportunityAssociations($opportunity, $associations);\n\n return $opportunity;\n }\n\n private function resolveAccountId(array $associations): ?int\n {\n if (! empty($associations['account_id'])) {\n return $associations['account_id'];\n }\n\n if (empty($associations)) {\n return null;\n }\n\n // Fallback: use first company as account (currently SDK returns one company)\n foreach ($associations['companies'] as $accountId) {\n return $accountId;\n }\n\n return null;\n }\n\n private function buildOpportunityData(\n array $properties,\n ?int $accountId,\n ?BusinessProcess $businessProcess,\n ?Stage $stage\n ): array {\n $ownerId = null;\n $profile = null;\n if (! empty($properties['hubspot_owner_id'])) {\n $ownerId = $properties['hubspot_owner_id'];\n $profile = $this->crmEntityRepository->findProfileByExternalId($this->config, (string) $ownerId);\n }\n\n $name = 'Unknown';\n if (isset($properties['dealname'])) {\n $name = mb_strimwidth($properties['dealname'], 0, 128);\n }\n\n $amount = $this->resolveAmount($properties);\n $currency = $properties['deal_currency_code'] ?? null;\n\n $closeDate = null;\n if (! empty($properties['closedate'])) {\n $closeDate = Carbon::parse($properties['closedate'])->format('Y-m-d');\n }\n\n $remotelyCreatedAt = null;\n if (! empty($properties['createdate']) && strtotime($properties['createdate'])) {\n $date = $this->parseCleanDatetime($properties['createdate']);\n $remotelyCreatedAt = $date?->format('Y-m-d H:i:s');\n }\n\n $closedStages = $this->getClosedDealStages();\n $isWon = in_array($properties['dealstage'], $closedStages['won']);\n $isLost = in_array($properties['dealstage'], $closedStages['lost']);\n\n $data = [\n 'team_id' => $this->team->getId(),\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $ownerId,\n 'name' => $name,\n 'value' => ! empty($amount) ? $amount : null,\n 'currency_code' => CurrencyFormatter::formatCode($currency),\n 'close_date' => $closeDate,\n 'is_closed' => $isWon || $isLost,\n 'is_won' => $isWon,\n 'remotely_created_at' => $remotelyCreatedAt,\n 'probability' => $this->resolveDealProbability($properties['hs_deal_stage_probability']),\n 'forecast_category' => $this->resolveForecastCategory($properties['hs_manual_forecast_category']),\n ];\n\n if ($accountId) {\n $data['account_id'] = $accountId;\n }\n\n if ($stage) {\n $data['stage_id'] = $stage->id;\n }\n\n if ($businessProcess) {\n $recordType = $this->crmEntityRepository->getBusinessProcessRecordType($businessProcess);\n if ($recordType) {\n $data['record_type_id'] = $recordType->id;\n }\n }\n\n return $data;\n }\n\n private function resolveBusinessProcess(?string $pipelineId): ?BusinessProcess\n {\n if ($pipelineId === null) {\n return null;\n }\n\n $cacheKey = $this->getBusinessProcessCacheKey($pipelineId);\n if (isset($this->cachedBusinessProcesses[$cacheKey])) {\n return $this->cachedBusinessProcesses[$cacheKey];\n }\n\n $businessProcess = $this->getBusinessProcess($pipelineId);\n\n if (! $businessProcess instanceof BusinessProcess) {\n $this->importStages();\n $businessProcess = $this->getBusinessProcess($pipelineId);\n }\n\n if (! $businessProcess instanceof BusinessProcess) {\n $this->logger->info(\n '[HubSpot] Deal is not attached to a pipeline',\n [\n 'pipeline' => $pipelineId]\n );\n }\n\n $this->cachedBusinessProcesses[$cacheKey] = $businessProcess;\n\n return $businessProcess;\n }\n\n private function getBusinessProcess(string $pipelineId): ?BusinessProcess\n {\n return $this->crmEntityRepository->findBusinessProcessesByExternalId($this->config, $pipelineId);\n }\n\n private function getBusinessProcessCacheKey(string $pipelineId): string\n {\n return $this->config->getId() . '_' . $pipelineId;\n }\n\n private function resolveStage(BusinessProcess $businessProcess, ?string $stageId): ?Stage\n {\n if (empty($stageId)) {\n return null;\n }\n\n $cacheKey = $businessProcess->getId() . ':' . $stageId;\n if (isset($this->cachedStages[$cacheKey])) {\n return $this->cachedStages[$cacheKey];\n }\n\n $stage = $this->crmEntityRepository->getPipelineStageByConditions(\n $businessProcess,\n [\n 'crm_provider_id' => $stageId,\n 'type' => Stage::TYPE_OPPORTUNITY,\n ]\n );\n\n if ($stage === null) {\n $this->importStages(null, $stageId);\n }\n\n if ($stage === null) {\n $this->logger->info('[HubSpot] Stage does not exist => ' . $stageId);\n }\n\n $this->cachedStages[$cacheKey] = $stage;\n\n return $stage;\n }\n\n private function resolveAmount(array $properties): ?string\n {\n $amount = null;\n if (! empty($properties['amount'])) {\n $amount = str_replace(',', '', $properties['amount']);\n }\n\n if ($this->config->hasDefaultCurrencyFieldSet()) {\n $valueFieldName = $this->config->getDefaultCurrencyField()->getCrmProviderId();\n $amount = $properties[$valueFieldName] ?? $amount;\n }\n\n return $amount;\n }\n\n private function parseCleanDatetime(string $datetime): ?Carbon\n {\n // Treat pre-1980 values as invalid\n $minValidDate = Carbon::parse('1980-01-01 00:00:00');\n\n try {\n $date = Carbon::parse($datetime);\n\n if ($minValidDate->gt($date)) {\n return null;\n }\n\n return $date;\n } catch (Exception) {\n return null; // On parse error, treat as null\n }\n }\n\n private function resolveDealProbability(?string $stageProbability): int\n {\n if ($stageProbability === null) {\n return 0;\n }\n\n $probability = (float) $stageProbability;\n\n return $probability > 1 ? 0 : (int) ($probability * 100);\n }\n\n private function resolveForecastCategory(?string $forecastCategory): string\n {\n if (! $forecastCategory) {\n return Forecast::FORECAST_CATEGORY_UNCATEGORIZED;\n }\n\n $forecastCategory = str_replace('_', ' ', $forecastCategory);\n\n return ucwords(strtolower($forecastCategory));\n }\n\n private function importExternalFieldData(array $properties, int $opportunityId): void\n {\n $crmFields = $this->getOpportunitySyncableFields();\n $this->importOpportunityCrmFieldData($properties, $crmFields, $opportunityId);\n }\n\n private function importOpportunityContacts(Opportunity $opportunity, array $associations): void\n {\n // Handle empty or missing contact associations\n if (empty($associations)) {\n // Remove all existing contact associations if none provided\n $this->removeAllOpportunityContacts($opportunity);\n\n return;\n }\n\n // Use differential sync approach for better performance and accuracy\n $this->syncOpportunityContactsDifferential($opportunity, $associations);\n }\n\n /**\n * Sync opportunity contacts using differential approach\n * This compares current vs new associations and only makes necessary changes\n */\n private function syncOpportunityContactsDifferential(Opportunity $opportunity, array $contactAssociations): void\n {\n $currentContactCrmIds = $this->getCurrentContactCrmIds($opportunity);\n $contactAssociationIds = array_keys($contactAssociations);\n\n $contactsToAdd = array_diff($contactAssociationIds, $currentContactCrmIds);\n $contactsToRemove = array_diff($currentContactCrmIds, $contactAssociationIds);\n\n if (empty($contactsToAdd) && empty($contactsToRemove)) {\n return;\n }\n\n $this->logContactAssociationChanges($opportunity, $currentContactCrmIds, $contactAssociations, $contactsToAdd, $contactsToRemove);\n\n $this->removeContactAssociations($opportunity, $contactsToRemove);\n $this->addContactAssociations($opportunity, $contactsToAdd, $contactAssociations);\n }\n\n private function getCurrentContactCrmIds(Opportunity $opportunity): array\n {\n return $opportunity->contacts()\n ->pluck('contacts.crm_provider_id')\n ->toArray();\n }\n\n private function logContactAssociationChanges(\n Opportunity $opportunity,\n array $currentContactCrmIds,\n array $contactAssociations,\n array $contactsToAdd,\n array $contactsToRemove\n ): void {\n $this->logger->info('[' . $this->getDisplayName() . '] Contact association changes', [\n 'opportunity_id' => $opportunity->getId(),\n 'current_contacts' => $currentContactCrmIds,\n 'new_contacts' => $contactAssociations,\n 'contacts_to_add' => $contactsToAdd,\n 'contacts_to_remove' => $contactsToRemove,\n ]);\n }\n\n private function removeContactAssociations(Opportunity $opportunity, array $contactsToRemove): void\n {\n if (empty($contactsToRemove)) {\n return;\n }\n\n $contactsToDetach = $opportunity->contacts()\n ->whereIn('contacts.crm_provider_id', $contactsToRemove)\n ->pluck('contacts.id')\n ->toArray();\n\n if (! empty($contactsToDetach)) {\n $opportunity->contacts()->detach($contactsToDetach);\n\n $this->logger->info('[' . $this->getDisplayName() . '] Removed contact associations', [\n 'opportunity_id' => $opportunity->getId(),\n 'removed_contact_crm_ids' => $contactsToRemove,\n 'removed_contact_count' => count($contactsToDetach),\n ]);\n }\n }\n\n private function addContactAssociations(Opportunity $opportunity, array $contactsToAdd, array $contactAssociations): void\n {\n if (empty($contactsToAdd)) {\n return;\n }\n\n $contactsAdded = [];\n foreach ($contactsToAdd as $crmId) {\n $id = $contactAssociations[$crmId];\n\n if ($this->attachSingleContact($opportunity, (string) $crmId, $id)) {\n $contactsAdded[] = $crmId;\n }\n }\n\n $this->logAddedContacts($opportunity, $contactsAdded);\n }\n\n private function attachSingleContact(Opportunity $opportunity, string $crmId, int $id): bool\n {\n try {\n $contact = $this->crmEntityRepository->findContactByConfigurationAndId($this->config, $id);\n\n if (! $contact) {\n return false;\n }\n\n return $this->performContactAttachment($opportunity, $contact, $crmId);\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Failed to add contact association', [\n 'opportunity_id' => $opportunity->getId(),\n 'contact_crm_id' => $crmId,\n 'error' => $e->getMessage(),\n ]);\n\n return false;\n }\n }\n\n private function performContactAttachment(Opportunity $opportunity, Contact $contact, string $crmId): bool\n {\n try {\n $opportunity->contacts()->attach($contact->getId(), [\n 'crm_provider_id' => $crmId,\n ]);\n\n return true;\n } catch (\\Illuminate\\Database\\QueryException $e) {\n if (str_contains($e->getMessage(), 'Duplicate entry')) {\n $this->logger->info('[' . $this->getDisplayName() . '] Contact association already exists', [\n 'contact_id' => $contact->getId(),\n 'contact_crm_id' => $crmId,\n 'opportunity_id' => $opportunity->getId(),\n ]);\n\n return false;\n }\n\n throw $e;\n }\n }\n\n private function logAddedContacts(Opportunity $opportunity, array $contactsAdded): void\n {\n if (! empty($contactsAdded)) {\n $this->logger->info('[' . $this->getDisplayName() . '] Added contact associations', [\n 'opportunity_id' => $opportunity->getId(),\n 'added_contact_crm_ids' => $contactsAdded,\n 'added_contacts_count' => count($contactsAdded),\n ]);\n }\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits;\n\nuse Carbon\\Carbon;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\CollectionResponseAssociatedId;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Exception;\nuse Jiminny\\Component\\DealInsights\\Forecast\\Forecast;\nuse Jiminny\\Jobs\\Crm\\MatchActivitiesToNewOpportunity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Models\\Opportunity;\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Services\\Crm\\Hubspot\\DealFieldsService;\nuse Jiminny\\Services\\Crm\\Hubspot\\OpportunitySyncStrategy\\HubspotSingleSyncStrategy;\nuse Jiminny\\Services\\Crm\\Hubspot\\WebhookSyncBatchProcessor;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Utils\\CurrencyFormatter;\n\n/**\n * Optimized sync methods for better performance\n * These methods can be integrated into SyncCrmEntitiesTrait for significant performance gains\n */\ntrait OpportunitySyncTrait\n{\n private const int BATCH_SIZE = 100;\n private const int BATCH_PROCESS_SIZE = 800;\n\n protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;\n protected CrmEntityRepository $crmEntityRepository;\n protected DealFieldsService $dealFieldsService;\n\n private ?array $cachedClosedDealStages = null;\n private array $cachedBusinessProcesses = [];\n private array $cachedStages = [];\n\n public function syncOpportunities(array $parameters, ?string $strategy = null): int\n {\n $startTime = microtime(true);\n $strategies = $this->opportunitySyncStrategyResolver->getStrategies($this->config, $strategy);\n $parameters['config'] = $this->config;\n $syncCount = 0;\n $reportedTotal = 0;\n $lastSyncedId = [];\n $strategyNames = [];\n\n try {\n foreach ($strategies as $strategyName => $syncStrategy) {\n $strategyNames[] = $strategyName;\n $this->logger->info(\n '[' . $this->getDisplayName() . '] Syncing opportunities using strategy: ' . $strategyName,\n ['team' => $this->team->getId()]\n );\n\n $total = 0;\n $lastId = null;\n $buffer = [];\n\n // HubspotWebhookBatchSyncStrategy returns empty generator, this is for other strategies\n foreach ($syncStrategy->fetchOpportunities($parameters, $total, $lastId) as $hsOpportunity) {\n $buffer[] = $hsOpportunity;\n\n // process every 800 rows (fits < 1 000 association limit)\n if (\\count($buffer) >= self::BATCH_PROCESS_SIZE) {\n $syncCount += $this->processOpportunityBatch($buffer);\n $buffer = [];\n }\n }\n\n // leftovers\n if ($buffer) {\n $syncCount += $this->processOpportunityBatch($buffer);\n }\n\n $reportedTotal += $total;\n $lastSyncedId = $lastId;\n }\n } catch (\\HubSpot\\Client\\Crm\\Deals\\ApiException | CrmException $e) {\n $this->handleSyncException($e, $parameters);\n }\n\n $durationMs = round((microtime(true) - $startTime) * 1000, 2);\n $this->logger->info(\n '[HubSpot] Synced opportunities',\n [\n 'team' => $this->team->getId(),\n 'strategies' => implode(',', $strategyNames),\n 'sync_count' => $syncCount,\n 'total' => $reportedTotal,\n 'last_synced_id' => $lastSyncedId,\n 'duration_ms' => $durationMs,\n ]\n );\n\n return $reportedTotal;\n }\n\n private function handleSyncException(\\Throwable $e, array $parameters): void\n {\n if (($parameters['since'] ?? null) instanceof Carbon) {\n $parameters['since'] = $parameters['since']->toDateTimeString();\n }\n $parameters['config'] = $this->config->getId();\n\n $this->logger->warning('[' . $this->getDisplayName() . '] Sync opportunities failed', [\n 'teamId' => $this->team->getUuid(),\n 'parameters' => $parameters,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n /**\n * @inheritdoc\n */\n public function syncOpportunity(string $crmId): ?Opportunity\n {\n $strategy = $this->opportunitySyncStrategyResolver->resolve(\n $this->config,\n OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY,\n );\n\n $parameters = [\n 'config' => $this->config,\n 'crm_id' => $crmId,\n ];\n\n try {\n if (! $strategy instanceof HubspotSingleSyncStrategy) {\n throw new InvalidArgumentException('Strategy must by HubspotSingleSyncStrategy');\n }\n\n $hsOpportunity = $strategy->fetchOpportunity($parameters);\n } catch (\\HubSpot\\Client\\Crm\\Deals\\ApiException $e) {\n $this->logger->info('[' . $this->getDisplayName() . '] Opportunity not found', [\n 'teamId' => $this->team->getUuid(),\n 'crmId' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n return null;\n }\n\n $hsOpportunity['associations'] = $this->convertDealAssociations($hsOpportunity['associations'] ?? []);\n\n return $this->importOrUpdateOpportunity($hsOpportunity);\n }\n\n /**\n * Process webhook-collected opportunity batches.\n *\n * Drains Redis sets containing company CRM IDs collected from webhook events\n * and dispatches ImportOpportunityBatch jobs for batch processing.\n *\n * @return int Number of opportunity IDs dispatched to jobs\n */\n public function batchSyncOpportunities(): int\n {\n $configId = $this->team->getCrmConfiguration()->getId();\n\n return $this->batchProcessor->processBatchesForObjectType(\n WebhookSyncBatchProcessor::OBJECT_TYPE_DEAL,\n $configId\n );\n }\n\n /**\n * Import a batch of opportunities by their CRM IDs.\n * Fetches opportunity data from HubSpot API and delegates to importOpportunityBatch().\n *\n * @param array<string> $crmIds HubSpot deal CRM IDs\n *\n * @return array{success: array, failed_ids: array, errors?: array<string, string>}\n */\n public function importOpportunityBatchByIds(array $crmIds): array\n {\n $fields = $this->dealFieldsService->getFieldsForConfiguration($this->config);\n\n $allDeals = [];\n foreach (array_chunk($crmIds, self::BATCH_SIZE) as $chunk) {\n $deals = $this->client->getOpportunitiesByIds($chunk, $fields);\n foreach ($deals as $deal) {\n $allDeals[] = $deal;\n }\n }\n\n // IDs not returned by HubSpot are likely deleted or inaccessible deals.\n // These are not failures — retrying won't bring them back.\n $fetchedIds = array_map('strval', array_column($allDeals, 'id'));\n $notFoundIds = array_values(array_diff(array_map('strval', $crmIds), $fetchedIds));\n\n if (! empty($notFoundIds)) {\n $this->logger->info('[' . $this->getDisplayName() . '] CRM IDs not found in HubSpot (likely deleted)', [\n 'teamId' => $this->team->getId(),\n 'notFoundCount' => \\count($notFoundIds),\n 'notFoundIds' => $notFoundIds,\n 'requestedCount' => \\count($crmIds),\n 'fetchedCount' => \\count($allDeals),\n ]);\n }\n\n if (empty($allDeals)) {\n return ['success' => [], 'failed_ids' => []];\n }\n\n return $this->importOpportunityBatch($allDeals);\n }\n\n private function getClosedDealStages(): array\n {\n if ($this->cachedClosedDealStages !== null) {\n return $this->cachedClosedDealStages;\n }\n\n $stages = $this->crmEntityRepository->getOpportunityClosedStages($this->config);\n $data = [\n 'lost' => [],\n 'won' => [],\n ];\n\n foreach ($stages as $stage) {\n if ($stage->probability == 0.00) {\n $data['lost'][] = $stage->crm_provider_id;\n }\n if ($stage->probability == 100.00) {\n $data['won'][] = $stage->crm_provider_id;\n }\n }\n\n $this->cachedClosedDealStages = $data;\n\n return $data;\n }\n\n /**\n * Import deals into the database with pre-fetched associations.\n *\n * API calls here (getAssociationsData, getExistingOpportunityCrmIds) are NOT\n * caught — if they throw, the exception propagates to ImportOpportunityBatch::handle()\n * where Laravel retries the whole job with backoff. After all retries exhausted,\n * failed() requeues all IDs to Redis.\n *\n * The per-deal loop catches exceptions individually. A deal can end up in three states:\n * - success: imported/updated successfully\n * - failed_ids: exception thrown (DB constraint violation, corrupt data, etc.)\n * These are permanent issues — retrying won't fix them.\n * - skipped (null): missing dependencies (no account, unknown pipeline/stage).\n * This is acceptable — the deal cannot be imported until those exist.\n */\n private function importOpportunityBatch(array $deals): array\n {\n $syncedOpportunities = [\n 'success' => [],\n 'failed_ids' => [],\n ];\n $dealIds = array_column($deals, 'id');\n\n // Shared association/existing-ID preparation is batch-level state. If it fails, rethrow so the\n // queue job retries the whole batch and eventually requeues all deal IDs back to Redis.\n try {\n $companyAssociations = $this->client->getAssociationsData($dealIds, 'deals', 'companies');\n $contactAssociations = $this->client->getAssociationsData($dealIds, 'deals', 'contacts');\n\n $associationsData = $this->prepareAssociatedEntities($companyAssociations, $contactAssociations);\n\n $existingCrmIds = $this->crmEntityRepository->getExistingOpportunityCrmIds(\n $this->config,\n array_map('strval', $dealIds)\n );\n $existingCrmIdSet = array_flip($existingCrmIds);\n } catch (\\Throwable $e) {\n $this->logger->error('[' . $this->getDisplayName() . '] Failed to fetch associations or existing IDs', [\n 'teamId' => $this->team->getId(),\n 'dealCount' => count($dealIds),\n 'error' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n foreach ($deals as $deal) {\n try {\n $deal['associations'] = $this->prepareAssociationsForOpportunity(\n $deal['id'],\n $companyAssociations,\n $contactAssociations,\n $associationsData\n );\n\n $syncedOpportunity = $this->importOrUpdateOpportunity(\n $deal,\n isset($existingCrmIdSet[(string) $deal['id']])\n );\n if ($syncedOpportunity) {\n $syncedOpportunities['success'][] = $syncedOpportunity;\n }\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Failed to import opportunity', [\n 'teamId' => $this->team->getId(),\n 'crmId' => $deal['id'],\n 'error' => $e->getMessage(),\n ]);\n $syncedOpportunities['failed_ids'][] = $deal['id'];\n $syncedOpportunities['errors'][$deal['id']] = $e->getMessage();\n }\n }\n\n return $syncedOpportunities;\n }\n\n /**\n * Prepare associated entities for opportunities with optimized batch processing\n * Returns structured data with CRM ID to DB ID mappings for each opportunity\n */\n private function prepareAssociatedEntities(array $companyAssociations, array $contactAssociations): array\n {\n // Step 1: Collect all unique company and contact IDs from associations\n $allCompanyIds = $this->flattenAssociationIds($companyAssociations);\n $allContactIds = $this->flattenAssociationIds($contactAssociations);\n\n // Step 2: Batch sync missing entities and get CRM ID to DB ID mappings\n $companyIdMappings = [];\n $contactIdMappings = [];\n\n if (! empty($allCompanyIds)) {\n $companyIdMappings = $this->prepareAssociatedAccounts($allCompanyIds);\n }\n\n if (! empty($allContactIds)) {\n $contactIdMappings = $this->prepareAssociatedContacts($allContactIds);\n }\n\n return [\n 'company_id_mappings' => $companyIdMappings,\n 'contact_id_mappings' => $contactIdMappings,\n ];\n }\n\n /**\n * Flatten association data to get unique IDs\n */\n private function flattenAssociationIds(array $associations): array\n {\n $ids = [];\n foreach ($associations as $dealAssociations) {\n if (is_array($dealAssociations)) {\n foreach ($dealAssociations as $id) {\n $ids[$id] = true;\n }\n }\n }\n\n return array_keys($ids);\n }\n\n /**\n * Batch sync missing accounts\n */\n private function prepareAssociatedAccounts(array $companyIds): array\n {\n // Find which accounts already exist\n $existingAccounts = $this->crmEntityRepository\n ->findAccountsByExternalIds($this->config, $companyIds);\n\n $existingCompanyIds = $existingAccounts->pluck('crm_provider_id')->toArray();\n\n $existingAccountsData = $existingAccounts->mapWithKeys(function ($account) {\n return [$account->getCrmProviderId() => $account->getId()];\n })->toArray();\n\n $missingCompanyIds = array_diff($companyIds, $existingCompanyIds);\n\n if (empty($missingCompanyIds)) {\n return $existingAccountsData;\n }\n\n $this->logger->info('[' . $this->getDisplayName() . '] Batch syncing missing accounts', [\n 'teamId' => $this->team->getUuid(),\n 'total_companies' => count($companyIds),\n 'existing_companies' => count($existingCompanyIds),\n 'missing_companies' => count($missingCompanyIds),\n ]);\n\n // we already have limit on opportunity ids count\n // Initialize variable before try block\n $syncedAccountsData = [];\n\n try {\n $syncedAccountsData = $this->batchSyncCrmObjects('companies', $missingCompanyIds);\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Failed to sync missing accounts', [\n 'size' => count($missingCompanyIds),\n 'error' => $e->getMessage(),\n ]);\n $syncedAccountsData = [];\n }\n\n return $existingAccountsData + $syncedAccountsData;\n }\n\n /**\n * Prepare associated contacts - find existing and sync missing ones\n * Returns mapping of CRM ID to DB ID\n */\n private function prepareAssociatedContacts(array $contactIds): array\n {\n // Find which contacts already exist\n $existingContacts = $this->crmEntityRepository\n ->findContactsByExternalIds($this->config, $contactIds);\n\n $existingContactIds = $existingContacts->pluck('crm_provider_id')->toArray();\n\n // Create mapping for existing contacts\n $existingContactsData = $existingContacts->mapWithKeys(function ($contact) {\n return [$contact->getCrmProviderId() => $contact->getId()];\n })->toArray();\n\n $missingContactIds = array_diff($contactIds, $existingContactIds);\n\n if (empty($missingContactIds)) {\n return $existingContactsData;\n }\n\n $this->logger->info('[' . $this->getDisplayName() . '] Batch syncing missing contacts', [\n 'teamId' => $this->team->getUuid(),\n 'total_contacts' => count($contactIds),\n 'existing_contacts' => count($existingContactIds),\n 'missing_contacts' => count($missingContactIds),\n ]);\n\n // Sync missing contacts using batch API\n try {\n $syncedContactsData = $this->batchSyncCrmObjects('contacts', $missingContactIds);\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Failed to sync missing contacts', [\n 'size' => count($missingContactIds),\n 'error' => $e->getMessage(),\n ]);\n $syncedContactsData = [];\n }\n\n return $existingContactsData + $syncedContactsData;\n }\n\n private function batchSyncCrmObjects(string $objectType, array $crmIds): array\n {\n $syncObjects = [];\n $crmObjectIds = array_values($crmIds);\n\n foreach (array_chunk($crmObjectIds, self::BATCH_SIZE) as $chunk) {\n try {\n $objects = $objectType === 'companies' ?\n $this->client->getCompaniesByIds($chunk, $this->getCompanyFields()) :\n $this->client->getContactsByIds($chunk, $this->getContactFields());\n\n foreach ($objects as $objectId => $objectData) {\n $this->importCrmObject($objectType, (string) $objectId, $objectData, $syncObjects);\n }\n\n $this->logger->info('[' . $this->getDisplayName() . '] Batch synced ' . $objectType, [\n 'requested_count' => count($chunk),\n 'synced_count' => count($objects),\n ]);\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Batch ' . $objectType . ' sync failed', [\n 'ids' => $chunk,\n 'error' => $e->getMessage(),\n ]);\n }\n }\n\n return $syncObjects;\n }\n\n private function importCrmObject(string $objectType, string $objectId, mixed $objectData, array &$syncObjects): void\n {\n try {\n $object = $objectType === 'companies' ?\n $this->importAccount($objectData) :\n $this->importContact($objectData);\n\n if ($object) {\n $syncObjects[$object->getCrmProviderId()] = $object->getId();\n }\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Failed to import batch ' . $objectType, [\n 'id' => $objectId,\n 'error' => $e->getMessage(),\n ]);\n }\n }\n\n /**\n * Prepare associations for a single opportunity\n *\n * The return value is an array with the following structure:\n * [\n * 'companies' => [\n * $companyCrmId => $companyId,\n * ...\n * ],\n * 'contacts' => [\n * $contactCrmId => $contactId,\n * ...\n * ],\n * 'account_id' => $accountId,\n * ]\n */\n private function prepareAssociationsForOpportunity(\n string $oppCrmId,\n array $companyAssociations,\n array $contactAssociations,\n array $associationsData\n ): array {\n $associations = [\n 'companies' => [],\n 'contacts' => [],\n 'account_id' => null, // Primary account for opportunity\n ];\n\n $oppCompanyIds = $companyAssociations[$oppCrmId] ?? [];\n foreach ($oppCompanyIds as $companyCrmId) {\n if (isset($associationsData['company_id_mappings'][$companyCrmId])) {\n $associations['companies'][$companyCrmId] = $associationsData['company_id_mappings'][$companyCrmId];\n\n // Set primary account (first company becomes primary account)\n if ($associations['account_id'] === null) {\n $associations['account_id'] = $associationsData['company_id_mappings'][$companyCrmId];\n }\n }\n }\n\n $oppContactIds = $contactAssociations[$oppCrmId] ?? [];\n foreach ($oppContactIds as $contactCrmId) {\n if (isset($associationsData['contact_id_mappings'][$contactCrmId])) {\n $associations['contacts'][$contactCrmId] = $associationsData['contact_id_mappings'][$contactCrmId];\n }\n }\n\n return $associations;\n }\n\n /**\n * Update only associations for an opportunity\n */\n private function updateOpportunityAssociations(Opportunity $opportunity, array $associations): void\n {\n // Update contact associations\n $this->importOpportunityContacts($opportunity, $associations['contacts']);\n\n // Update company (account) associations\n $this->updateOpportunityAccount($opportunity, $associations['account_id']);\n }\n\n /**\n * Remove all contact associations from an opportunity\n */\n private function removeAllOpportunityContacts(Opportunity $opportunity): void\n {\n $currentCount = (int) $opportunity->contacts()->count();\n\n if ($currentCount > 0) {\n $opportunity->contacts()->detach();\n\n $this->logger->info('[' . $this->getDisplayName() . '] Removed all contact associations', [\n 'opportunity_id' => $opportunity->getId(),\n 'removed_count' => $currentCount,\n ]);\n }\n }\n\n private function updateOpportunityAccount(Opportunity $opportunity, ?int $accountId): void\n {\n if ($accountId === null) {\n // No account ID provided - keep current account\n return;\n }\n\n $currentAccountId = $opportunity->getAccountId();\n\n // Only update if account has changed\n if ($currentAccountId !== $accountId) {\n $opportunity->account_id = $accountId;\n $opportunity->save();\n\n $this->logger->info('[' . $this->getDisplayName() . '] Updated opportunity account association', [\n 'opportunity_id' => $opportunity->getId(),\n 'old_account_id' => $currentAccountId,\n 'new_account_id' => $accountId,\n ]);\n }\n }\n\n /**\n * Find existing opportunities by external IDs (OPTIMIZED VERSION)\n * Uses batch query for better performance\n */\n private function findExistingOpportunities(array $crmIds): Collection\n {\n return $this->crmEntityRepository\n ->findOpportunitiesByExternalIds($this->config, $crmIds);\n }\n\n private function processOpportunityBatch(array $opportunities): int\n {\n $syncedOpportunities = $this->importOpportunityBatch($opportunities);\n\n return count($syncedOpportunities['success'] ?? []);\n }\n\n /**\n * Convert single deal associations from HubSpot format to internal format\n * Handles both HubSpot SDK objects and array formats\n *\n * @param array $opportunityAssociations Raw associations from HubSpot API or pre-processed\n *\n * @return array Processed associations with DB IDs\n */\n private function convertDealAssociations(array $opportunityAssociations): array\n {\n $associations = $this->initializeAssociationsStructure();\n\n if (empty($opportunityAssociations)) {\n return $associations;\n }\n\n $associationIds = $this->extractAssociationIds($opportunityAssociations);\n\n $this->processCompanyAssociations($associationIds, $associations);\n $this->processContactAssociations($associationIds, $associations);\n\n return $associations;\n }\n\n private function initializeAssociationsStructure(): array\n {\n return [\n 'companies' => [],\n 'contacts' => [],\n 'account_id' => null, // Primary account for opportunity\n ];\n }\n\n private function extractAssociationIds(array $opportunityAssociations): array\n {\n $associationIds = [];\n\n foreach ($opportunityAssociations as $type => $associationData) {\n if (! empty($associationData)) {\n $associationIds[$type] = $this->convertSingleDealAssociations($associationData);\n }\n }\n\n return $associationIds;\n }\n\n private function processCompanyAssociations(array $associationIds, array &$associations): void\n {\n if (empty($associationIds['companies'])) {\n return;\n }\n\n $companyId = $associationIds['companies'][0];\n $account = $this->findOrSyncAccount($companyId);\n\n if ($account instanceof Account) {\n $associations['companies'][$companyId] = $account->getId();\n $associations['account_id'] = $account->getId();\n }\n }\n\n private function processContactAssociations(array $associationIds, array &$associations): void\n {\n if (empty($associationIds['contacts'])) {\n return;\n }\n\n foreach ($associationIds['contacts'] as $contactId) {\n $contact = $this->findOrSyncContact($contactId);\n\n if ($contact instanceof Contact) {\n $associations['contacts'][$contactId] = $contact->getId();\n }\n }\n }\n\n private function findOrSyncAccount(string $companyId): ?Account\n {\n $account = $this->crmEntityRepository->findAccountByExternalId($this->config, $companyId);\n\n if (! $account instanceof Account) {\n $account = $this->syncAccount($companyId);\n }\n\n return $account;\n }\n\n private function findOrSyncContact(string $contactId): ?Contact\n {\n $contact = $this->crmEntityRepository->findContactByExternalId($this->config, $contactId);\n\n if (! $contact instanceof Contact) {\n $contact = $this->syncContact($contactId);\n }\n\n return $contact;\n }\n\n private function convertSingleDealAssociations($opportunityAssociations = null): array\n {\n $associationData = [];\n\n if ($opportunityAssociations === null) {\n return $associationData;\n }\n\n // Handle array input (from extractAssociationIds)\n if (is_array($opportunityAssociations)) {\n return $opportunityAssociations;\n }\n\n // Handle CollectionResponseAssociatedId object\n if ($opportunityAssociations instanceof CollectionResponseAssociatedId) {\n foreach ($opportunityAssociations->getResults() as $association) {\n $associationData[] = $association->getId();\n }\n }\n\n return $associationData;\n }\n\n private function importOrUpdateOpportunity($crmData, ?bool $exists = null): ?Opportunity\n {\n if (empty($crmData['properties'])) {\n return null;\n }\n\n $crmId = (string) $crmData['id'];\n $properties = $crmData['properties'];\n $associations = $crmData['associations'] ?? [];\n\n $opportunityExists = $exists ?? (bool) $this->crmEntityRepository->findOpportunityByExternalId(\n $this->config,\n $crmId\n );\n\n if ($opportunityExists) {\n return $this->updateOpportunity($crmId, $properties, $associations);\n }\n\n return $this->createOpportunity($crmId, $properties, $associations);\n }\n\n /**\n * Create new opportunity\n */\n private function createOpportunity(string $crmId, array $properties, array $associations): ?Opportunity\n {\n $accountId = $this->resolveAccountId($associations);\n if (! $accountId) {\n return null;\n }\n\n $businessProcess = $this->resolveBusinessProcess($properties['pipeline'] ?? null);\n if (! $businessProcess) {\n return null;\n }\n\n $stage = $this->resolveStage($businessProcess, $properties['dealstage'] ?? null);\n if (! $stage) {\n return null;\n }\n\n $data = $this->buildOpportunityData($properties, $accountId, $businessProcess, $stage);\n\n $attributes = [\n 'crm_configuration_id' => $this->config->getId(),\n 'crm_provider_id' => $crmId,\n ];\n\n $values = array_merge($attributes, $data);\n\n $opportunity = $this->crmEntityRepository->upsertOpportunity($attributes, $values);\n\n $this->importExternalFieldData($properties, $opportunity->getId());\n $this->importOpportunityContacts($opportunity, $associations['contacts']);\n\n if ($opportunity->wasRecentlyCreated) {\n MatchActivitiesToNewOpportunity::dispatch($opportunity->getId());\n }\n\n return $opportunity;\n }\n\n /**\n * Update existing opportunity\n */\n private function updateOpportunity(string $crmId, array $properties, array $associations): Opportunity\n {\n $accountId = $this->resolveAccountId($associations);\n $businessProcess = $this->resolveBusinessProcess($properties['pipeline'] ?? null);\n $stage = $businessProcess ? $this->resolveStage($businessProcess, $properties['dealstage'] ?? null) : null;\n\n $data = $this->buildOpportunityData($properties, $accountId, $businessProcess, $stage);\n\n $attributes = [\n 'crm_configuration_id' => $this->config->getId(),\n 'crm_provider_id' => $crmId,\n ];\n\n $values = array_merge($attributes, $data);\n $opportunity = $this->crmEntityRepository->upsertOpportunity($attributes, $values);\n\n $this->importExternalFieldData($properties, $opportunity->getId());\n $this->updateOpportunityAssociations($opportunity, $associations);\n\n return $opportunity;\n }\n\n private function resolveAccountId(array $associations): ?int\n {\n if (! empty($associations['account_id'])) {\n return $associations['account_id'];\n }\n\n if (empty($associations)) {\n return null;\n }\n\n // Fallback: use first company as account (currently SDK returns one company)\n foreach ($associations['companies'] as $accountId) {\n return $accountId;\n }\n\n return null;\n }\n\n private function buildOpportunityData(\n array $properties,\n ?int $accountId,\n ?BusinessProcess $businessProcess,\n ?Stage $stage\n ): array {\n $ownerId = null;\n $profile = null;\n if (! empty($properties['hubspot_owner_id'])) {\n $ownerId = $properties['hubspot_owner_id'];\n $profile = $this->crmEntityRepository->findProfileByExternalId($this->config, (string) $ownerId);\n }\n\n $name = 'Unknown';\n if (isset($properties['dealname'])) {\n $name = mb_strimwidth($properties['dealname'], 0, 128);\n }\n\n $amount = $this->resolveAmount($properties);\n $currency = $properties['deal_currency_code'] ?? null;\n\n $closeDate = null;\n if (! empty($properties['closedate'])) {\n $closeDate = Carbon::parse($properties['closedate'])->format('Y-m-d');\n }\n\n $remotelyCreatedAt = null;\n if (! empty($properties['createdate']) && strtotime($properties['createdate'])) {\n $date = $this->parseCleanDatetime($properties['createdate']);\n $remotelyCreatedAt = $date?->format('Y-m-d H:i:s');\n }\n\n $closedStages = $this->getClosedDealStages();\n $isWon = in_array($properties['dealstage'], $closedStages['won']);\n $isLost = in_array($properties['dealstage'], $closedStages['lost']);\n\n $data = [\n 'team_id' => $this->team->getId(),\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $ownerId,\n 'name' => $name,\n 'value' => ! empty($amount) ? $amount : null,\n 'currency_code' => CurrencyFormatter::formatCode($currency),\n 'close_date' => $closeDate,\n 'is_closed' => $isWon || $isLost,\n 'is_won' => $isWon,\n 'remotely_created_at' => $remotelyCreatedAt,\n 'probability' => $this->resolveDealProbability($properties['hs_deal_stage_probability']),\n 'forecast_category' => $this->resolveForecastCategory($properties['hs_manual_forecast_category']),\n ];\n\n if ($accountId) {\n $data['account_id'] = $accountId;\n }\n\n if ($stage) {\n $data['stage_id'] = $stage->id;\n }\n\n if ($businessProcess) {\n $recordType = $this->crmEntityRepository->getBusinessProcessRecordType($businessProcess);\n if ($recordType) {\n $data['record_type_id'] = $recordType->id;\n }\n }\n\n return $data;\n }\n\n private function resolveBusinessProcess(?string $pipelineId): ?BusinessProcess\n {\n if ($pipelineId === null) {\n return null;\n }\n\n $cacheKey = $this->getBusinessProcessCacheKey($pipelineId);\n if (isset($this->cachedBusinessProcesses[$cacheKey])) {\n return $this->cachedBusinessProcesses[$cacheKey];\n }\n\n $businessProcess = $this->getBusinessProcess($pipelineId);\n\n if (! $businessProcess instanceof BusinessProcess) {\n $this->importStages();\n $businessProcess = $this->getBusinessProcess($pipelineId);\n }\n\n if (! $businessProcess instanceof BusinessProcess) {\n $this->logger->info(\n '[HubSpot] Deal is not attached to a pipeline',\n [\n 'pipeline' => $pipelineId]\n );\n }\n\n $this->cachedBusinessProcesses[$cacheKey] = $businessProcess;\n\n return $businessProcess;\n }\n\n private function getBusinessProcess(string $pipelineId): ?BusinessProcess\n {\n return $this->crmEntityRepository->findBusinessProcessesByExternalId($this->config, $pipelineId);\n }\n\n private function getBusinessProcessCacheKey(string $pipelineId): string\n {\n return $this->config->getId() . '_' . $pipelineId;\n }\n\n private function resolveStage(BusinessProcess $businessProcess, ?string $stageId): ?Stage\n {\n if (empty($stageId)) {\n return null;\n }\n\n $cacheKey = $businessProcess->getId() . ':' . $stageId;\n if (isset($this->cachedStages[$cacheKey])) {\n return $this->cachedStages[$cacheKey];\n }\n\n $stage = $this->crmEntityRepository->getPipelineStageByConditions(\n $businessProcess,\n [\n 'crm_provider_id' => $stageId,\n 'type' => Stage::TYPE_OPPORTUNITY,\n ]\n );\n\n if ($stage === null) {\n $this->importStages(null, $stageId);\n }\n\n if ($stage === null) {\n $this->logger->info('[HubSpot] Stage does not exist => ' . $stageId);\n }\n\n $this->cachedStages[$cacheKey] = $stage;\n\n return $stage;\n }\n\n private function resolveAmount(array $properties): ?string\n {\n $amount = null;\n if (! empty($properties['amount'])) {\n $amount = str_replace(',', '', $properties['amount']);\n }\n\n if ($this->config->hasDefaultCurrencyFieldSet()) {\n $valueFieldName = $this->config->getDefaultCurrencyField()->getCrmProviderId();\n $amount = $properties[$valueFieldName] ?? $amount;\n }\n\n return $amount;\n }\n\n private function parseCleanDatetime(string $datetime): ?Carbon\n {\n // Treat pre-1980 values as invalid\n $minValidDate = Carbon::parse('1980-01-01 00:00:00');\n\n try {\n $date = Carbon::parse($datetime);\n\n if ($minValidDate->gt($date)) {\n return null;\n }\n\n return $date;\n } catch (Exception) {\n return null; // On parse error, treat as null\n }\n }\n\n private function resolveDealProbability(?string $stageProbability): int\n {\n if ($stageProbability === null) {\n return 0;\n }\n\n $probability = (float) $stageProbability;\n\n return $probability > 1 ? 0 : (int) ($probability * 100);\n }\n\n private function resolveForecastCategory(?string $forecastCategory): string\n {\n if (! $forecastCategory) {\n return Forecast::FORECAST_CATEGORY_UNCATEGORIZED;\n }\n\n $forecastCategory = str_replace('_', ' ', $forecastCategory);\n\n return ucwords(strtolower($forecastCategory));\n }\n\n private function importExternalFieldData(array $properties, int $opportunityId): void\n {\n $crmFields = $this->getOpportunitySyncableFields();\n $this->importOpportunityCrmFieldData($properties, $crmFields, $opportunityId);\n }\n\n private function importOpportunityContacts(Opportunity $opportunity, array $associations): void\n {\n // Handle empty or missing contact associations\n if (empty($associations)) {\n // Remove all existing contact associations if none provided\n $this->removeAllOpportunityContacts($opportunity);\n\n return;\n }\n\n // Use differential sync approach for better performance and accuracy\n $this->syncOpportunityContactsDifferential($opportunity, $associations);\n }\n\n /**\n * Sync opportunity contacts using differential approach\n * This compares current vs new associations and only makes necessary changes\n */\n private function syncOpportunityContactsDifferential(Opportunity $opportunity, array $contactAssociations): void\n {\n $currentContactCrmIds = $this->getCurrentContactCrmIds($opportunity);\n $contactAssociationIds = array_keys($contactAssociations);\n\n $contactsToAdd = array_diff($contactAssociationIds, $currentContactCrmIds);\n $contactsToRemove = array_diff($currentContactCrmIds, $contactAssociationIds);\n\n if (empty($contactsToAdd) && empty($contactsToRemove)) {\n return;\n }\n\n $this->logContactAssociationChanges($opportunity, $currentContactCrmIds, $contactAssociations, $contactsToAdd, $contactsToRemove);\n\n $this->removeContactAssociations($opportunity, $contactsToRemove);\n $this->addContactAssociations($opportunity, $contactsToAdd, $contactAssociations);\n }\n\n private function getCurrentContactCrmIds(Opportunity $opportunity): array\n {\n return $opportunity->contacts()\n ->pluck('contacts.crm_provider_id')\n ->toArray();\n }\n\n private function logContactAssociationChanges(\n Opportunity $opportunity,\n array $currentContactCrmIds,\n array $contactAssociations,\n array $contactsToAdd,\n array $contactsToRemove\n ): void {\n $this->logger->info('[' . $this->getDisplayName() . '] Contact association changes', [\n 'opportunity_id' => $opportunity->getId(),\n 'current_contacts' => $currentContactCrmIds,\n 'new_contacts' => $contactAssociations,\n 'contacts_to_add' => $contactsToAdd,\n 'contacts_to_remove' => $contactsToRemove,\n ]);\n }\n\n private function removeContactAssociations(Opportunity $opportunity, array $contactsToRemove): void\n {\n if (empty($contactsToRemove)) {\n return;\n }\n\n $contactsToDetach = $opportunity->contacts()\n ->whereIn('contacts.crm_provider_id', $contactsToRemove)\n ->pluck('contacts.id')\n ->toArray();\n\n if (! empty($contactsToDetach)) {\n $opportunity->contacts()->detach($contactsToDetach);\n\n $this->logger->info('[' . $this->getDisplayName() . '] Removed contact associations', [\n 'opportunity_id' => $opportunity->getId(),\n 'removed_contact_crm_ids' => $contactsToRemove,\n 'removed_contact_count' => count($contactsToDetach),\n ]);\n }\n }\n\n private function addContactAssociations(Opportunity $opportunity, array $contactsToAdd, array $contactAssociations): void\n {\n if (empty($contactsToAdd)) {\n return;\n }\n\n $contactsAdded = [];\n foreach ($contactsToAdd as $crmId) {\n $id = $contactAssociations[$crmId];\n\n if ($this->attachSingleContact($opportunity, (string) $crmId, $id)) {\n $contactsAdded[] = $crmId;\n }\n }\n\n $this->logAddedContacts($opportunity, $contactsAdded);\n }\n\n private function attachSingleContact(Opportunity $opportunity, string $crmId, int $id): bool\n {\n try {\n $contact = $this->crmEntityRepository->findContactByConfigurationAndId($this->config, $id);\n\n if (! $contact) {\n return false;\n }\n\n return $this->performContactAttachment($opportunity, $contact, $crmId);\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Failed to add contact association', [\n 'opportunity_id' => $opportunity->getId(),\n 'contact_crm_id' => $crmId,\n 'error' => $e->getMessage(),\n ]);\n\n return false;\n }\n }\n\n private function performContactAttachment(Opportunity $opportunity, Contact $contact, string $crmId): bool\n {\n try {\n $opportunity->contacts()->attach($contact->getId(), [\n 'crm_provider_id' => $crmId,\n ]);\n\n return true;\n } catch (\\Illuminate\\Database\\QueryException $e) {\n if (str_contains($e->getMessage(), 'Duplicate entry')) {\n $this->logger->info('[' . $this->getDisplayName() . '] Contact association already exists', [\n 'contact_id' => $contact->getId(),\n 'contact_crm_id' => $crmId,\n 'opportunity_id' => $opportunity->getId(),\n ]);\n\n return false;\n }\n\n throw $e;\n }\n }\n\n private function logAddedContacts(Opportunity $opportunity, array $contactsAdded): void\n {\n if (! empty($contactsAdded)) {\n $this->logger->info('[' . $this->getDisplayName() . '] Added contact associations', [\n 'opportunity_id' => $opportunity->getId(),\n 'added_contact_crm_ids' => $contactsAdded,\n 'added_contacts_count' => count($contactsAdded),\n ]);\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"bounds":{"left":0.5265958,"top":0.074221864,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"bounds":{"left":0.53523934,"top":0.074221864,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"bounds":{"left":0.5462101,"top":0.074221864,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"bounds":{"left":0.55485374,"top":0.074221864,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"bounds":{"left":0.56349736,"top":0.074221864,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"bounds":{"left":0.5744681,"top":0.074221864,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"bounds":{"left":0.58543885,"top":0.074221864,"width":0.024268618,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"bounds":{"left":0.61203456,"top":0.074221864,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"bounds":{"left":0.62300533,"top":0.074221864,"width":0.029587766,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"bounds":{"left":0.9587766,"top":0.074221864,"width":0.02825798,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.94514626,"top":0.09896249,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.95511967,"top":0.09896249,"width":0.00731383,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.9644282,"top":0.09896249,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9740692,"top":0.09736632,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.98138297,"top":0.09736632,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"# **************************** HS **************************************\n\nselect * from teams where id = 2; # 2\nselect * from features; # 2\nselect * from team_features where team_id = 2; # 2\nselect * from crm_configurations where id = 2; # 2\nselect * from users where team_id = 2; #\nselect * from playbooks where team_id = 2; # event 38\nselect * from playbook_categories where playbook_id = 38; #\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;\nhttps://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624\n https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0\n\nSELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;\n# 609126 softphone tr. 11241\n\nSELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;\n# 608874 conference tr. 11226 crmId: 103422236596\n\nselect * from ai_prompts where transcription_id IN (11241, 11226);\nselect * from activity_summary_logs where activity_id = 608874;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nselect * from crm_field_data where activity_id = 1223;\n\nselect * from crm_layouts where crm_configuration_id = 2;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);\nselect * from crm_fields where crm_configuration_id = 11 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);\n\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u\n on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 2 and sa.provider = 'hubspot';\n\nselect * from opportunities where team_id = 2\nand crm_provider_id IN ('51317301383');\n\nselect * from contacts where id = 85;\n\nselect * from opportunities where team_id = 2 order by id desc;\nselect * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112\nselect * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112\nselect * from opportunity_contacts where opportunity_id = 5117;\nselect * from crm_field_data where object_id = 1365;\nSELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);\n\nselect * from features;\nselect * from team_features where team_id IN (1);\nselect * from team_features where feature_id IN (36);\n\nSHOW CREATE TABLE opportunity_contacts;\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';\n\n# $slug = 'HUBSPOT_WEBHOOK_SYNC';\n# $team = Jiminny\\Models\\Team::find(2);\n# $feature = Feature::query()->where('slug', $slug)->first();\n# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);\n\n# hubspot_webhook_metrics\n\nselect * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365\nSELECT * FROM opportunity_contacts WHERE opportunity_id = '414';\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';\nselect * from contacts where id in (414, 464);\n\nselect * from activities where crm_configuration_id = 2;\n\nselect settings from crm_configurations where id = 11;\n\nselect * from teams; # 1, 2\nselect * from users;\nselect * from crm_configurations where id = 39;\nselect * from team_features where team_id = 2;\nselect * from features;\n# SELECT * FROM opportunities WHERE crm_configuration_id = 2\n# order by id desc;\n# and crm_provider_id = '49908861993';\n\n\nselect * from activity_providers where id IN (443, 202, 203, 227);\n\nselect * from activity_imports where id = 795889;\n\nselect c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id\nwhere c.provider = 'hubspot';\n\nselect * from crm_configurations crm JOIN teams t on crm.team_id = t.id\nwhere provider = 'hubspot';\nSELECT * FROM teams WHERE id = 31;\nSELECT * FROM users WHERE id = 257;\nSELECT * FROM opportunities WHERE team_id = 2;\n\nselect * from opportunity_contacts where opportunity_id = 5124;\nselect * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)\n\nselect * from activities where crm_configuration_id = 13;\n\nSELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141\n\n\nselect id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;\nSELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 order by id desc;\nselect * from opportunity_contacts where contact_id = 6223;\nSELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;\n\nselect * from crm_profiles where crm_configuration_id = 2;\n\nselect * from activities where account_id = 46;","depth":4,"value":"# **************************** HS **************************************\n\nselect * from teams where id = 2; # 2\nselect * from features; # 2\nselect * from team_features where team_id = 2; # 2\nselect * from crm_configurations where id = 2; # 2\nselect * from users where team_id = 2; #\nselect * from playbooks where team_id = 2; # event 38\nselect * from playbook_categories where playbook_id = 38; #\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;\nhttps://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624\n https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0\n\nSELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;\n# 609126 softphone tr. 11241\n\nSELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;\n# 608874 conference tr. 11226 crmId: 103422236596\n\nselect * from ai_prompts where transcription_id IN (11241, 11226);\nselect * from activity_summary_logs where activity_id = 608874;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nselect * from crm_field_data where activity_id = 1223;\n\nselect * from crm_layouts where crm_configuration_id = 2;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);\nselect * from crm_fields where crm_configuration_id = 11 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);\n\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u\n on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 2 and sa.provider = 'hubspot';\n\nselect * from opportunities where team_id = 2\nand crm_provider_id IN ('51317301383');\n\nselect * from contacts where id = 85;\n\nselect * from opportunities where team_id = 2 order by id desc;\nselect * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112\nselect * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112\nselect * from opportunity_contacts where opportunity_id = 5117;\nselect * from crm_field_data where object_id = 1365;\nSELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);\n\nselect * from features;\nselect * from team_features where team_id IN (1);\nselect * from team_features where feature_id IN (36);\n\nSHOW CREATE TABLE opportunity_contacts;\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';\n\n# $slug = 'HUBSPOT_WEBHOOK_SYNC';\n# $team = Jiminny\\Models\\Team::find(2);\n# $feature = Feature::query()->where('slug', $slug)->first();\n# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);\n\n# hubspot_webhook_metrics\n\nselect * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365\nSELECT * FROM opportunity_contacts WHERE opportunity_id = '414';\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';\nselect * from contacts where id in (414, 464);\n\nselect * from activities where crm_configuration_id = 2;\n\nselect settings from crm_configurations where id = 11;\n\nselect * from teams; # 1, 2\nselect * from users;\nselect * from crm_configurations where id = 39;\nselect * from team_features where team_id = 2;\nselect * from features;\n# SELECT * FROM opportunities WHERE crm_configuration_id = 2\n# order by id desc;\n# and crm_provider_id = '49908861993';\n\n\nselect * from activity_providers where id IN (443, 202, 203, 227);\n\nselect * from activity_imports where id = 795889;\n\nselect c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id\nwhere c.provider = 'hubspot';\n\nselect * from crm_configurations crm JOIN teams t on crm.team_id = t.id\nwhere provider = 'hubspot';\nSELECT * FROM teams WHERE id = 31;\nSELECT * FROM users WHERE id = 257;\nSELECT * FROM opportunities WHERE team_id = 2;\n\nselect * from opportunity_contacts where opportunity_id = 5124;\nselect * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)\n\nselect * from activities where crm_configuration_id = 13;\n\nSELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141\n\n\nselect id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;\nSELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 order by id desc;\nselect * from opportunity_contacts where contact_id = 6223;\nSELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;\n\nselect * from crm_profiles where crm_configuration_id = 2;\n\nselect * from activities where account_id = 46;","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-7827763017813047052
|
1048134296968532324
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#11976 on JY-20553-debug- Project: faVsco.js, menu
#11976 on JY-20553-debug-crm-sync-delays, menu
Start Listening for PHP Debug Connections
RequestGenerateAskJiminnyReportJobTest
Run 'RequestGenerateAskJiminnyReportJobTest'
Debug 'RequestGenerateAskJiminnyReportJobTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
33
2
19
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot\ServiceTraits;
use Carbon\Carbon;
use HubSpot\Client\Crm\Deals\Model\CollectionResponseAssociatedId;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Exception;
use Jiminny\Component\DealInsights\Forecast\Forecast;
use Jiminny\Jobs\Crm\MatchActivitiesToNewOpportunity;
use Jiminny\Models\Contact;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Exceptions\CrmException;
use Jiminny\Models\Opportunity;
use Illuminate\Support\Collection;
use Jiminny\Models\Stage;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Services\Crm\Hubspot\DealFieldsService;
use Jiminny\Services\Crm\Hubspot\OpportunitySyncStrategy\HubspotSingleSyncStrategy;
use Jiminny\Services\Crm\Hubspot\WebhookSyncBatchProcessor;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Utils\CurrencyFormatter;
/**
* Optimized sync methods for better performance
* These methods can be integrated into SyncCrmEntitiesTrait for significant performance gains
*/
trait OpportunitySyncTrait
{
private const int BATCH_SIZE = 100;
private const int BATCH_PROCESS_SIZE = 800;
protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;
protected CrmEntityRepository $crmEntityRepository;
protected DealFieldsService $dealFieldsService;
private ?array $cachedClosedDealStages = null;
private array $cachedBusinessProcesses = [];
private array $cachedStages = [];
public function syncOpportunities(array $parameters, ?string $strategy = null): int
{
$startTime = microtime(true);
$strategies = $this->opportunitySyncStrategyResolver->getStrategies($this->config, $strategy);
$parameters['config'] = $this->config;
$syncCount = 0;
$reportedTotal = 0;
$lastSyncedId = [];
$strategyNames = [];
try {
foreach ($strategies as $strategyName => $syncStrategy) {
$strategyNames[] = $strategyName;
$this->logger->info(
'[' . $this->getDisplayName() . '] Syncing opportunities using strategy: ' . $strategyName,
['team' => $this->team->getId()]
);
$total = 0;
$lastId = null;
$buffer = [];
// HubspotWebhookBatchSyncStrategy returns empty generator, this is for other strategies
foreach ($syncStrategy->fetchOpportunities($parameters, $total, $lastId) as $hsOpportunity) {
$buffer[] = $hsOpportunity;
// process every 800 rows (fits < 1 000 association limit)
if (\count($buffer) >= self::BATCH_PROCESS_SIZE) {
$syncCount += $this->processOpportunityBatch($buffer);
$buffer = [];
}
}
// leftovers
if ($buffer) {
$syncCount += $this->processOpportunityBatch($buffer);
}
$reportedTotal += $total;
$lastSyncedId = $lastId;
}
} catch (\HubSpot\Client\Crm\Deals\ApiException | CrmException $e) {
$this->handleSyncException($e, $parameters);
}
$durationMs = round((microtime(true) - $startTime) * 1000, 2);
$this->logger->info(
'[HubSpot] Synced opportunities',
[
'team' => $this->team->getId(),
'strategies' => implode(',', $strategyNames),
'sync_count' => $syncCount,
'total' => $reportedTotal,
'last_synced_id' => $lastSyncedId,
'duration_ms' => $durationMs,
]
);
return $reportedTotal;
}
private function handleSyncException(\Throwable $e, array $parameters): void
{
if (($parameters['since'] ?? null) instanceof Carbon) {
$parameters['since'] = $parameters['since']->toDateTimeString();
}
$parameters['config'] = $this->config->getId();
$this->logger->warning('[' . $this->getDisplayName() . '] Sync opportunities failed', [
'teamId' => $this->team->getUuid(),
'parameters' => $parameters,
'reason' => $e->getMessage(),
]);
}
/**
* @inheritdoc
*/
public function syncOpportunity(string $crmId): ?Opportunity
{
$strategy = $this->opportunitySyncStrategyResolver->resolve(
$this->config,
OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY,
);
$parameters = [
'config' => $this->config,
'crm_id' => $crmId,
];
try {
if (! $strategy instanceof HubspotSingleSyncStrategy) {
throw new InvalidArgumentException('Strategy must by HubspotSingleSyncStrategy');
}
$hsOpportunity = $strategy->fetchOpportunity($parameters);
} catch (\HubSpot\Client\Crm\Deals\ApiException $e) {
$this->logger->info('[' . $this->getDisplayName() . '] Opportunity not found', [
'teamId' => $this->team->getUuid(),
'crmId' => $crmId,
'reason' => $e->getMessage(),
]);
return null;
}
$hsOpportunity['associations'] = $this->convertDealAssociations($hsOpportunity['associations'] ?? []);
return $this->importOrUpdateOpportunity($hsOpportunity);
}
/**
* Process webhook-collected opportunity batches.
*
* Drains Redis sets containing company CRM IDs collected from webhook events
* and dispatches ImportOpportunityBatch jobs for batch processing.
*
* @return int Number of opportunity IDs dispatched to jobs
*/
public function batchSyncOpportunities(): int
{
$configId = $this->team->getCrmConfiguration()->getId();
return $this->batchProcessor->processBatchesForObjectType(
WebhookSyncBatchProcessor::OBJECT_TYPE_DEAL,
$configId
);
}
/**
* Import a batch of opportunities by their CRM IDs.
* Fetches opportunity data from HubSpot API and delegates to importOpportunityBatch().
*
* @param array<string> $crmIds HubSpot deal CRM IDs
*
* @return array{success: array, failed_ids: array, errors?: array<string, string>}
*/
public function importOpportunityBatchByIds(array $crmIds): array
{
$fields = $this->dealFieldsService->getFieldsForConfiguration($this->config);
$allDeals = [];
foreach (array_chunk($crmIds, self::BATCH_SIZE) as $chunk) {
$deals = $this->client->getOpportunitiesByIds($chunk, $fields);
foreach ($deals as $deal) {
$allDeals[] = $deal;
}
}
// IDs not returned by HubSpot are likely deleted or inaccessible deals.
// These are not failures — retrying won't bring them back.
$fetchedIds = array_map('strval', array_column($allDeals, 'id'));
$notFoundIds = array_values(array_diff(array_map('strval', $crmIds), $fetchedIds));
if (! empty($notFoundIds)) {
$this->logger->info('[' . $this->getDisplayName() . '] CRM IDs not found in HubSpot (likely deleted)', [
'teamId' => $this->team->getId(),
'notFoundCount' => \count($notFoundIds),
'notFoundIds' => $notFoundIds,
'requestedCount' => \count($crmIds),
'fetchedCount' => \count($allDeals),
]);
}
if (empty($allDeals)) {
return ['success' => [], 'failed_ids' => []];
}
return $this->importOpportunityBatch($allDeals);
}
private function getClosedDealStages(): array
{
if ($this->cachedClosedDealStages !== null) {
return $this->cachedClosedDealStages;
}
$stages = $this->crmEntityRepository->getOpportunityClosedStages($this->config);
$data = [
'lost' => [],
'won' => [],
];
foreach ($stages as $stage) {
if ($stage->probability == 0.00) {
$data['lost'][] = $stage->crm_provider_id;
}
if ($stage->probability == 100.00) {
$data['won'][] = $stage->crm_provider_id;
}
}
$this->cachedClosedDealStages = $data;
return $data;
}
/**
* Import deals into the database with pre-fetched associations.
*
* API calls here (getAssociationsData, getExistingOpportunityCrmIds) are NOT
* caught — if they throw, the exception propagates to ImportOpportunityBatch::handle()
* where Laravel retries the whole job with backoff. After all retries exhausted,
* failed() requeues all IDs to Redis.
*
* The per-deal loop catches exceptions individually. A deal can end up in three states:
* - success: imported/updated successfully
* - failed_ids: exception thrown (DB constraint violation, corrupt data, etc.)
* These are permanent issues — retrying won't fix them.
* - skipped (null): missing dependencies (no account, unknown pipeline/stage).
* This is acceptable — the deal cannot be imported until those exist.
*/
private function importOpportunityBatch(array $deals): array
{
$syncedOpportunities = [
'success' => [],
'failed_ids' => [],
];
$dealIds = array_column($deals, 'id');
// Shared association/existing-ID preparation is batch-level state. If it fails, rethrow so the
// queue job retries the whole batch and eventually requeues all deal IDs back to Redis.
try {
$companyAssociations = $this->client->getAssociationsData($dealIds, 'deals', 'companies');
$contactAssociations = $this->client->getAssociationsData($dealIds, 'deals', 'contacts');
$associationsData = $this->prepareAssociatedEntities($companyAssociations, $contactAssociations);
$existingCrmIds = $this->crmEntityRepository->getExistingOpportunityCrmIds(
$this->config,
array_map('strval', $dealIds)
);
$existingCrmIdSet = array_flip($existingCrmIds);
} catch (\Throwable $e) {
$this->logger->error('[' . $this->getDisplayName() . '] Failed to fetch associations or existing IDs', [
'teamId' => $this->team->getId(),
'dealCount' => count($dealIds),
'error' => $e->getMessage(),
]);
throw $e;
}
foreach ($deals as $deal) {
try {
$deal['associations'] = $this->prepareAssociationsForOpportunity(
$deal['id'],
$companyAssociations,
$contactAssociations,
$associationsData
);
$syncedOpportunity = $this->importOrUpdateOpportunity(
$deal,
isset($existingCrmIdSet[(string) $deal['id']])
);
if ($syncedOpportunity) {
$syncedOpportunities['success'][] = $syncedOpportunity;
}
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Failed to import opportunity', [
'teamId' => $this->team->getId(),
'crmId' => $deal['id'],
'error' => $e->getMessage(),
]);
$syncedOpportunities['failed_ids'][] = $deal['id'];
$syncedOpportunities['errors'][$deal['id']] = $e->getMessage();
}
}
return $syncedOpportunities;
}
/**
* Prepare associated entities for opportunities with optimized batch processing
* Returns structured data with CRM ID to DB ID mappings for each opportunity
*/
private function prepareAssociatedEntities(array $companyAssociations, array $contactAssociations): array
{
// Step 1: Collect all unique company and contact IDs from associations
$allCompanyIds = $this->flattenAssociationIds($companyAssociations);
$allContactIds = $this->flattenAssociationIds($contactAssociations);
// Step 2: Batch sync missing entities and get CRM ID to DB ID mappings
$companyIdMappings = [];
$contactIdMappings = [];
if (! empty($allCompanyIds)) {
$companyIdMappings = $this->prepareAssociatedAccounts($allCompanyIds);
}
if (! empty($allContactIds)) {
$contactIdMappings = $this->prepareAssociatedContacts($allContactIds);
}
return [
'company_id_mappings' => $companyIdMappings,
'contact_id_mappings' => $contactIdMappings,
];
}
/**
* Flatten association data to get unique IDs
*/
private function flattenAssociationIds(array $associations): array
{
$ids = [];
foreach ($associations as $dealAssociations) {
if (is_array($dealAssociations)) {
foreach ($dealAssociations as $id) {
$ids[$id] = true;
}
}
}
return array_keys($ids);
}
/**
* Batch sync missing accounts
*/
private function prepareAssociatedAccounts(array $companyIds): array
{
// Find which accounts already exist
$existingAccounts = $this->crmEntityRepository
->findAccountsByExternalIds($this->config, $companyIds);
$existingCompanyIds = $existingAccounts->pluck('crm_provider_id')->toArray();
$existingAccountsData = $existingAccounts->mapWithKeys(function ($account) {
return [$account->getCrmProviderId() => $account->getId()];
})->toArray();
$missingCompanyIds = array_diff($companyIds, $existingCompanyIds);
if (empty($missingCompanyIds)) {
return $existingAccountsData;
}
$this->logger->info('[' . $this->getDisplayName() . '] Batch syncing missing accounts', [
'teamId' => $this->team->getUuid(),
'total_companies' => count($companyIds),
'existing_companies' => count($existingCompanyIds),
'missing_companies' => count($missingCompanyIds),
]);
// we already have limit on opportunity ids count
// Initialize variable before try block
$syncedAccountsData = [];
try {
$syncedAccountsData = $this->batchSyncCrmObjects('companies', $missingCompanyIds);
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Failed to sync missing accounts', [
'size' => count($missingCompanyIds),
'error' => $e->getMessage(),
]);
$syncedAccountsData = [];
}
return $existingAccountsData + $syncedAccountsData;
}
/**
* Prepare associated contacts - find existing and sync missing ones
* Returns mapping of CRM ID to DB ID
*/
private function prepareAssociatedContacts(array $contactIds): array
{
// Find which contacts already exist
$existingContacts = $this->crmEntityRepository
->findContactsByExternalIds($this->config, $contactIds);
$existingContactIds = $existingContacts->pluck('crm_provider_id')->toArray();
// Create mapping for existing contacts
$existingContactsData = $existingContacts->mapWithKeys(function ($contact) {
return [$contact->getCrmProviderId() => $contact->getId()];
})->toArray();
$missingContactIds = array_diff($contactIds, $existingContactIds);
if (empty($missingContactIds)) {
return $existingContactsData;
}
$this->logger->info('[' . $this->getDisplayName() . '] Batch syncing missing contacts', [
'teamId' => $this->team->getUuid(),
'total_contacts' => count($contactIds),
'existing_contacts' => count($existingContactIds),
'missing_contacts' => count($missingContactIds),
]);
// Sync missing contacts using batch API
try {
$syncedContactsData = $this->batchSyncCrmObjects('contacts', $missingContactIds);
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Failed to sync missing contacts', [
'size' => count($missingContactIds),
'error' => $e->getMessage(),
]);
$syncedContactsData = [];
}
return $existingContactsData + $syncedContactsData;
}
private function batchSyncCrmObjects(string $objectType, array $crmIds): array
{
$syncObjects = [];
$crmObjectIds = array_values($crmIds);
foreach (array_chunk($crmObjectIds, self::BATCH_SIZE) as $chunk) {
try {
$objects = $objectType === 'companies' ?
$this->client->getCompaniesByIds($chunk, $this->getCompanyFields()) :
$this->client->getContactsByIds($chunk, $this->getContactFields());
foreach ($objects as $objectId => $objectData) {
$this->importCrmObject($objectType, (string) $objectId, $objectData, $syncObjects);
}
$this->logger->info('[' . $this->getDisplayName() . '] Batch synced ' . $objectType, [
'requested_count' => count($chunk),
'synced_count' => count($objects),
]);
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Batch ' . $objectType . ' sync failed', [
'ids' => $chunk,
'error' => $e->getMessage(),
]);
}
}
return $syncObjects;
}
private function importCrmObject(string $objectType, string $objectId, mixed $objectData, array &$syncObjects): void
{
try {
$object = $objectType === 'companies' ?
$this->importAccount($objectData) :
$this->importContact($objectData);
if ($object) {
$syncObjects[$object->getCrmProviderId()] = $object->getId();
}
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Failed to import batch ' . $objectType, [
'id' => $objectId,
'error' => $e->getMessage(),
]);
}
}
/**
* Prepare associations for a single opportunity
*
* The return value is an array with the following structure:
* [
* 'companies' => [
* $companyCrmId => $companyId,
* ...
* ],
* 'contacts' => [
* $contactCrmId => $contactId,
* ...
* ],
* 'account_id' => $accountId,
* ]
*/
private function prepareAssociationsForOpportunity(
string $oppCrmId,
array $companyAssociations,
array $contactAssociations,
array $associationsData
): array {
$associations = [
'companies' => [],
'contacts' => [],
'account_id' => null, // Primary account for opportunity
];
$oppCompanyIds = $companyAssociations[$oppCrmId] ?? [];
foreach ($oppCompanyIds as $companyCrmId) {
if (isset($associationsData['company_id_mappings'][$companyCrmId])) {
$associations['companies'][$companyCrmId] = $associationsData['company_id_mappings'][$companyCrmId];
// Set primary account (first company becomes primary account)
if ($associations['account_id'] === null) {
$associations['account_id'] = $associationsData['company_id_mappings'][$companyCrmId];
}
}
}
$oppContactIds = $contactAssociations[$oppCrmId] ?? [];
foreach ($oppContactIds as $contactCrmId) {
if (isset($associationsData['contact_id_mappings'][$contactCrmId])) {
$associations['contacts'][$contactCrmId] = $associationsData['contact_id_mappings'][$contactCrmId];
}
}
return $associations;
}
/**
* Update only associations for an opportunity
*/
private function updateOpportunityAssociations(Opportunity $opportunity, array $associations): void
{
// Update contact associations
$this->importOpportunityContacts($opportunity, $associations['contacts']);
// Update company (account) associations
$this->updateOpportunityAccount($opportunity, $associations['account_id']);
}
/**
* Remove all contact associations from an opportunity
*/
private function removeAllOpportunityContacts(Opportunity $opportunity): void
{
$currentCount = (int) $opportunity->contacts()->count();
if ($currentCount > 0) {
$opportunity->contacts()->detach();
$this->logger->info('[' . $this->getDisplayName() . '] Removed all contact associations', [
'opportunity_id' => $opportunity->getId(),
'removed_count' => $currentCount,
]);
}
}
private function updateOpportunityAccount(Opportunity $opportunity, ?int $accountId): void
{
if ($accountId === null) {
// No account ID provided - keep current account
return;
}
$currentAccountId = $opportunity->getAccountId();
// Only update if account has changed
if ($currentAccountId !== $accountId) {
$opportunity->account_id = $accountId;
$opportunity->save();
$this->logger->info('[' . $this->getDisplayName() . '] Updated opportunity account association', [
'opportunity_id' => $opportunity->getId(),
'old_account_id' => $currentAccountId,
'new_account_id' => $accountId,
]);
}
}
/**
* Find existing opportunities by external IDs (OPTIMIZED VERSION)
* Uses batch query for better performance
*/
private function findExistingOpportunities(array $crmIds): Collection
{
return $this->crmEntityRepository
->findOpportunitiesByExternalIds($this->config, $crmIds);
}
private function processOpportunityBatch(array $opportunities): int
{
$syncedOpportunities = $this->importOpportunityBatch($opportunities);
return count($syncedOpportunities['success'] ?? []);
}
/**
* Convert single deal associations from HubSpot format to internal format
* Handles both HubSpot SDK objects and array formats
*
* @param array $opportunityAssociations Raw associations from HubSpot API or pre-processed
*
* @return array Processed associations with DB IDs
*/
private function convertDealAssociations(array $opportunityAssociations): array
{
$associations = $this->initializeAssociationsStructure();
if (empty($opportunityAssociations)) {
return $associations;
}
$associationIds = $this->extractAssociationIds($opportunityAssociations);
$this->processCompanyAssociations($associationIds, $associations);
$this->processContactAssociations($associationIds, $associations);
return $associations;
}
private function initializeAssociationsStructure(): array
{
return [
'companies' => [],
'contacts' => [],
'account_id' => null, // Primary account for opportunity
];
}
private function extractAssociationIds(array $opportunityAssociations): array
{
$associationIds = [];
foreach ($opportunityAssociations as $type => $associationData) {
if (! empty($associationData)) {
$associationIds[$type] = $this->convertSingleDealAssociations($associationData);
}
}
return $associationIds;
}
private function processCompanyAssociations(array $associationIds, array &$associations): void
{
if (empty($associationIds['companies'])) {
return;
}
$companyId = $associationIds['companies'][0];
$account = $this->findOrSyncAccount($companyId);
if ($account instanceof Account) {
$associations['companies'][$companyId] = $account->getId();
$associations['account_id'] = $account->getId();
}
}
private function processContactAssociations(array $associationIds, array &$associations): void
{
if (empty($associationIds['contacts'])) {
return;
}
foreach ($associationIds['contacts'] as $contactId) {
$contact = $this->findOrSyncContact($contactId);
if ($contact instanceof Contact) {
$associations['contacts'][$contactId] = $contact->getId();
}
}
}
private function findOrSyncAccount(string $companyId): ?Account
{
$account = $this->crmEntityRepository->findAccountByExternalId($this->config, $companyId);
if (! $account instanceof Account) {
$account = $this->syncAccount($companyId);
}
return $account;
}
private function findOrSyncContact(string $contactId): ?Contact
{
$contact = $this->crmEntityRepository->findContactByExternalId($this->config, $contactId);
if (! $contact instanceof Contact) {
$contact = $this->syncContact($contactId);
}
return $contact;
}
private function convertSingleDealAssociations($opportunityAssociations = null): array
{
$associationData = [];
if ($opportunityAssociations === null) {
return $associationData;
}
// Handle array input (from extractAssociationIds)
if (is_array($opportunityAssociations)) {
return $opportunityAssociations;
}
// Handle CollectionResponseAssociatedId object
if ($opportunityAssociations instanceof CollectionResponseAssociatedId) {
foreach ($opportunityAssociations->getResults() as $association) {
$associationData[] = $association->getId();
}
}
return $associationData;
}
private function importOrUpdateOpportunity($crmData, ?bool $exists = null): ?Opportunity
{
if (empty($crmData['properties'])) {
return null;
}
$crmId = (string) $crmData['id'];
$properties = $crmData['properties'];
$associations = $crmData['associations'] ?? [];
$opportunityExists = $exists ?? (bool) $this->crmEntityRepository->findOpportunityByExternalId(
$this->config,
$crmId
);
if ($opportunityExists) {
return $this->updateOpportunity($crmId, $properties, $associations);
}
return $this->createOpportunity($crmId, $properties, $associations);
}
/**
* Create new opportunity
*/
private function createOpportunity(string $crmId, array $properties, array $associations): ?Opportunity
{
$accountId = $this->resolveAccountId($associations);
if (! $accountId) {
return null;
}
$businessProcess = $this->resolveBusinessProcess($properties['pipeline'] ?? null);
if (! $businessProcess) {
return null;
}
$stage = $this->resolveStage($businessProcess, $properties['dealstage'] ?? null);
if (! $stage) {
return null;
}
$data = $this->buildOpportunityData($properties, $accountId, $businessProcess, $stage);
$attributes = [
'crm_configuration_id' => $this->config->getId(),
'crm_provider_id' => $crmId,
];
$values = array_merge($attributes, $data);
$opportunity = $this->crmEntityRepository->upsertOpportunity($attributes, $values);
$this->importExternalFieldData($properties, $opportunity->getId());
$this->importOpportunityContacts($opportunity, $associations['contacts']);
if ($opportunity->wasRecentlyCreated) {
MatchActivitiesToNewOpportunity::dispatch($opportunity->getId());
}
return $opportunity;
}
/**
* Update existing opportunity
*/
private function updateOpportunity(string $crmId, array $properties, array $associations): Opportunity
{
$accountId = $this->resolveAccountId($associations);
$businessProcess = $this->resolveBusinessProcess($properties['pipeline'] ?? null);
$stage = $businessProcess ? $this->resolveStage($businessProcess, $properties['dealstage'] ?? null) : null;
$data = $this->buildOpportunityData($properties, $accountId, $businessProcess, $stage);
$attributes = [
'crm_configuration_id' => $this->config->getId(),
'crm_provider_id' => $crmId,
];
$values = array_merge($attributes, $data);
$opportunity = $this->crmEntityRepository->upsertOpportunity($attributes, $values);
$this->importExternalFieldData($properties, $opportunity->getId());
$this->updateOpportunityAssociations($opportunity, $associations);
return $opportunity;
}
private function resolveAccountId(array $associations): ?int
{
if (! empty($associations['account_id'])) {
return $associations['account_id'];
}
if (empty($associations)) {
return null;
}
// Fallback: use first company as account (currently SDK returns one company)
foreach ($associations['companies'] as $accountId) {
return $accountId;
}
return null;
}
private function buildOpportunityData(
array $properties,
?int $accountId,
?BusinessProcess $businessProcess,
?Stage $stage
): array {
$ownerId = null;
$profile = null;
if (! empty($properties['hubspot_owner_id'])) {
$ownerId = $properties['hubspot_owner_id'];
$profile = $this->crmEntityRepository->findProfileByExternalId($this->config, (string) $ownerId);
}
$name = 'Unknown';
if (isset($properties['dealname'])) {
$name = mb_strimwidth($properties['dealname'], 0, 128);
}
$amount = $this->resolveAmount($properties);
$currency = $properties['deal_currency_code'] ?? null;
$closeDate = null;
if (! empty($properties['closedate'])) {
$closeDate = Carbon::parse($properties['closedate'])->format('Y-m-d');
}
$remotelyCreatedAt = null;
if (! empty($properties['createdate']) && strtotime($properties['createdate'])) {
$date = $this->parseCleanDatetime($properties['createdate']);
$remotelyCreatedAt = $date?->format('Y-m-d H:i:s');
}
$closedStages = $this->getClosedDealStages();
$isWon = in_array($properties['dealstage'], $closedStages['won']);
$isLost = in_array($properties['dealstage'], $closedStages['lost']);
$data = [
'team_id' => $this->team->getId(),
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $ownerId,
'name' => $name,
'value' => ! empty($amount) ? $amount : null,
'currency_code' => CurrencyFormatter::formatCode($currency),
'close_date' => $closeDate,
'is_closed' => $isWon || $isLost,
'is_won' => $isWon,
'remotely_created_at' => $remotelyCreatedAt,
'probability' => $this->resolveDealProbability($properties['hs_deal_stage_probability']),
'forecast_category' => $this->resolveForecastCategory($properties['hs_manual_forecast_category']),
];
if ($accountId) {
$data['account_id'] = $accountId;
}
if ($stage) {
$data['stage_id'] = $stage->id;
}
if ($businessProcess) {
$recordType = $this->crmEntityRepository->getBusinessProcessRecordType($businessProcess);
if ($recordType) {
$data['record_type_id'] = $recordType->id;
}
}
return $data;
}
private function resolveBusinessProcess(?string $pipelineId): ?BusinessProcess
{
if ($pipelineId === null) {
return null;
}
$cacheKey = $this->getBusinessProcessCacheKey($pipelineId);
if (isset($this->cachedBusinessProcesses[$cacheKey])) {
return $this->cachedBusinessProcesses[$cacheKey];
}
$businessProcess = $this->getBusinessProcess($pipelineId);
if (! $businessProcess instanceof BusinessProcess) {
$this->importStages();
$businessProcess = $this->getBusinessProcess($pipelineId);
}
if (! $businessProcess instanceof BusinessProcess) {
$this->logger->info(
'[HubSpot] Deal is not attached to a pipeline',
[
'pipeline' => $pipelineId]
);
}
$this->cachedBusinessProcesses[$cacheKey] = $businessProcess;
return $businessProcess;
}
private function getBusinessProcess(string $pipelineId): ?BusinessProcess
{
return $this->crmEntityRepository->findBusinessProcessesByExternalId($this->config, $pipelineId);
}
private function getBusinessProcessCacheKey(string $pipelineId): string
{
return $this->config->getId() . '_' . $pipelineId;
}
private function resolveStage(BusinessProcess $businessProcess, ?string $stageId): ?Stage
{
if (empty($stageId)) {
return null;
}
$cacheKey = $businessProcess->getId() . ':' . $stageId;
if (isset($this->cachedStages[$cacheKey])) {
return $this->cachedStages[$cacheKey];
}
$stage = $this->crmEntityRepository->getPipelineStageByConditions(
$businessProcess,
[
'crm_provider_id' => $stageId,
'type' => Stage::TYPE_OPPORTUNITY,
]
);
if ($stage === null) {
$this->importStages(null, $stageId);
}
if ($stage === null) {
$this->logger->info('[HubSpot] Stage does not exist => ' . $stageId);
}
$this->cachedStages[$cacheKey] = $stage;
return $stage;
}
private function resolveAmount(array $properties): ?string
{
$amount = null;
if (! empty($properties['amount'])) {
$amount = str_replace(',', '', $properties['amount']);
}
if ($this->config->hasDefaultCurrencyFieldSet()) {
$valueFieldName = $this->config->getDefaultCurrencyField()->getCrmProviderId();
$amount = $properties[$valueFieldName] ?? $amount;
}
return $amount;
}
private function parseCleanDatetime(string $datetime): ?Carbon
{
// Treat pre-1980 values as invalid
$minValidDate = Carbon::parse('1980-01-01 00:00:00');
try {
$date = Carbon::parse($datetime);
if ($minValidDate->gt($date)) {
return null;
}
return $date;
} catch (Exception) {
return null; // On parse error, treat as null
}
}
private function resolveDealProbability(?string $stageProbability): int
{
if ($stageProbability === null) {
return 0;
}
$probability = (float) $stageProbability;
return $probability > 1 ? 0 : (int) ($probability * 100);
}
private function resolveForecastCategory(?string $forecastCategory): string
{
if (! $forecastCategory) {
return Forecast::FORECAST_CATEGORY_UNCATEGORIZED;
}
$forecastCategory = str_replace('_', ' ', $forecastCategory);
return ucwords(strtolower($forecastCategory));
}
private function importExternalFieldData(array $properties, int $opportunityId): void
{
$crmFields = $this->getOpportunitySyncableFields();
$this->importOpportunityCrmFieldData($properties, $crmFields, $opportunityId);
}
private function importOpportunityContacts(Opportunity $opportunity, array $associations): void
{
// Handle empty or missing contact associations
if (empty($associations)) {
// Remove all existing contact associations if none provided
$this->removeAllOpportunityContacts($opportunity);
return;
}
// Use differential sync approach for better performance and accuracy
$this->syncOpportunityContactsDifferential($opportunity, $associations);
}
/**
* Sync opportunity contacts using differential approach
* This compares current vs new associations and only makes necessary changes
*/
private function syncOpportunityContactsDifferential(Opportunity $opportunity, array $contactAssociations): void
{
$currentContactCrmIds = $this->getCurrentContactCrmIds($opportunity);
$contactAssociationIds = array_keys($contactAssociations);
$contactsToAdd = array_diff($contactAssociationIds, $currentContactCrmIds);
$contactsToRemove = array_diff($currentContactCrmIds, $contactAssociationIds);
if (empty($contactsToAdd) && empty($contactsToRemove)) {
return;
}
$this->logContactAssociationChanges($opportunity, $currentContactCrmIds, $contactAssociations, $contactsToAdd, $contactsToRemove);
$this->removeContactAssociations($opportunity, $contactsToRemove);
$this->addContactAssociations($opportunity, $contactsToAdd, $contactAssociations);
}
private function getCurrentContactCrmIds(Opportunity $opportunity): array
{
return $opportunity->contacts()
->pluck('contacts.crm_provider_id')
->toArray();
}
private function logContactAssociationChanges(
Opportunity $opportunity,
array $currentContactCrmIds,
array $contactAssociations,
array $contactsToAdd,
array $contactsToRemove
): void {
$this->logger->info('[' . $this->getDisplayName() . '] Contact association changes', [
'opportunity_id' => $opportunity->getId(),
'current_contacts' => $currentContactCrmIds,
'new_contacts' => $contactAssociations,
'contacts_to_add' => $contactsToAdd,
'contacts_to_remove' => $contactsToRemove,
]);
}
private function removeContactAssociations(Opportunity $opportunity, array $contactsToRemove): void
{
if (empty($contactsToRemove)) {
return;
}
$contactsToDetach = $opportunity->contacts()
->whereIn('contacts.crm_provider_id', $contactsToRemove)
->pluck('contacts.id')
->toArray();
if (! empty($contactsToDetach)) {
$opportunity->contacts()->detach($contactsToDetach);
$this->logger->info('[' . $this->getDisplayName() . '] Removed contact associations', [
'opportunity_id' => $opportunity->getId(),
'removed_contact_crm_ids' => $contactsToRemove,
'removed_contact_count' => count($contactsToDetach),
]);
}
}
private function addContactAssociations(Opportunity $opportunity, array $contactsToAdd, array $contactAssociations): void
{
if (empty($contactsToAdd)) {
return;
}
$contactsAdded = [];
foreach ($contactsToAdd as $crmId) {
$id = $contactAssociations[$crmId];
if ($this->attachSingleContact($opportunity, (string) $crmId, $id)) {
$contactsAdded[] = $crmId;
}
}
$this->logAddedContacts($opportunity, $contactsAdded);
}
private function attachSingleContact(Opportunity $opportunity, string $crmId, int $id): bool
{
try {
$contact = $this->crmEntityRepository->findContactByConfigurationAndId($this->config, $id);
if (! $contact) {
return false;
}
return $this->performContactAttachment($opportunity, $contact, $crmId);
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Failed to add contact association', [
'opportunity_id' => $opportunity->getId(),
'contact_crm_id' => $crmId,
'error' => $e->getMessage(),
]);
return false;
}
}
private function performContactAttachment(Opportunity $opportunity, Contact $contact, string $crmId): bool
{
try {
$opportunity->contacts()->attach($contact->getId(), [
'crm_provider_id' => $crmId,
]);
return true;
} catch (\Illuminate\Database\QueryException $e) {
if (str_contains($e->getMessage(), 'Duplicate entry')) {
$this->logger->info('[' . $this->getDisplayName() . '] Contact association already exists', [
'contact_id' => $contact->getId(),
'contact_crm_id' => $crmId,
'opportunity_id' => $opportunity->getId(),
]);
return false;
}
throw $e;
}
}
private function logAddedContacts(Opportunity $opportunity, array $contactsAdded): void
{
if (! empty($contactsAdded)) {
$this->logger->info('[' . $this->getDisplayName() . '] Added contact associations', [
'opportunity_id' => $opportunity->getId(),
'added_contact_crm_ids' => $contactsAdded,
'added_contacts_count' => count($contactsAdded),
]);
}
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
6
1
6
Previous Highlighted Error
Next Highlighted Error
# [PASSWORD_DOTS] HS [PASSWORD_DOTS]
select * from teams where id = 2; # 2
select * from features; # 2
select * from team_features where team_id = 2; # 2
select * from crm_configurations where id = 2; # 2
select * from users where team_id = 2; #
select * from playbooks where team_id = 2; # event 38
select * from playbook_categories where playbook_id = 38; #
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;
https://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624
https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0
SELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;
# 609126 softphone tr. 11241
SELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;
# 608874 conference tr. 11226 crmId: 103422236596
select * from ai_prompts where transcription_id IN (11241, 11226);
select * from activity_summary_logs where activity_id = 608874;
select * from sidekick_settings;
select * from default_activity_types;
select * from crm_field_data where activity_id = 1223;
select * from crm_layouts where crm_configuration_id = 2;
SELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);
select * from crm_fields where crm_configuration_id = 11 and object_type = 'event';
SELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);
SELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;
SELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u
on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 2 and sa.provider = 'hubspot';
select * from opportunities where team_id = 2
and crm_provider_id IN ('51317301383');
select * from contacts where id = 85;
select * from opportunities where team_id = 2 order by id desc;
select * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112
select * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112
select * from opportunity_contacts where opportunity_id = 5117;
select * from crm_field_data where object_id = 1365;
SELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);
select * from features;
select * from team_features where team_id IN (1);
select * from team_features where feature_id IN (36);
SHOW CREATE TABLE opportunity_contacts;
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';
# $slug = 'HUBSPOT_WEBHOOK_SYNC';
# $team = Jiminny\Models\Team::find(2);
# $feature = Feature::query()->where('slug', $slug)->first();
# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);
# hubspot_webhook_metrics
select * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365
SELECT * FROM opportunity_contacts WHERE opportunity_id = '414';
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';
select * from contacts where id in (414, 464);
select * from activities where crm_configuration_id = 2;
select settings from crm_configurations where id = 11;
select * from teams; # 1, 2
select * from users;
select * from crm_configurations where id = 39;
select * from team_features where team_id = 2;
select * from features;
# SELECT * FROM opportunities WHERE crm_configuration_id = 2
# order by id desc;
# and crm_provider_id = '49908861993';
select * from activity_providers where id IN (443, 202, 203, 227);
select * from activity_imports where id = 795889;
select c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id
where c.provider = 'hubspot';
select * from crm_configurations crm JOIN teams t on crm.team_id = t.id
where provider = 'hubspot';
SELECT * FROM teams WHERE id = 31;
SELECT * FROM users WHERE id = 257;
SELECT * FROM opportunities WHERE team_id = 2;
select * from opportunity_contacts where opportunity_id = 5124;
select * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)
select * from activities where crm_configuration_id = 13;
SELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141
select id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;
SELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;
SELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;
SELECT * FROM contacts WHERE team_id = 2 order by id desc;
select * from opportunity_contacts where contact_id = 6223;
SELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;
select * from crm_profiles where crm_configuration_id = 2;
select * from activities where account_id = 46;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
55530
|
|
55532
|
NULL
|
0
|
2026-04-20T09:53:20.937516+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776678800937_m1.jpg...
|
PhpStorm
|
faVsco.js – OpportunitySyncTrait.php
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#11976 on JY-20553-debug- Project: faVsco.js, menu
#11976 on JY-20553-debug-crm-sync-delays, menu
Start Listening for PHP Debug Connections
RequestGenerateAskJiminnyReportJobTest
Run 'RequestGenerateAskJiminnyReportJobTest'
Debug 'RequestGenerateAskJiminnyReportJobTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
33
2
19
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot\ServiceTraits;
use Carbon\Carbon;
use HubSpot\Client\Crm\Deals\Model\CollectionResponseAssociatedId;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Exception;
use Jiminny\Component\DealInsights\Forecast\Forecast;
use Jiminny\Jobs\Crm\MatchActivitiesToNewOpportunity;
use Jiminny\Models\Contact;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Exceptions\CrmException;
use Jiminny\Models\Opportunity;
use Illuminate\Support\Collection;
use Jiminny\Models\Stage;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Services\Crm\Hubspot\DealFieldsService;
use Jiminny\Services\Crm\Hubspot\OpportunitySyncStrategy\HubspotSingleSyncStrategy;
use Jiminny\Services\Crm\Hubspot\WebhookSyncBatchProcessor;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Utils\CurrencyFormatter;
/**
* Optimized sync methods for better performance
* These methods can be integrated into SyncCrmEntitiesTrait for significant performance gains
*/
trait OpportunitySyncTrait
{
private const int BATCH_SIZE = 100;
private const int BATCH_PROCESS_SIZE = 800;
protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;
protected CrmEntityRepository $crmEntityRepository;
protected DealFieldsService $dealFieldsService;
private ?array $cachedClosedDealStages = null;
private array $cachedBusinessProcesses = [];
private array $cachedStages = [];
public function syncOpportunities(array $parameters, ?string $strategy = null): int
{
$startTime = microtime(true);
$strategies = $this->opportunitySyncStrategyResolver->getStrategies($this->config, $strategy);
$parameters['config'] = $this->config;
$syncCount = 0;
$reportedTotal = 0;
$lastSyncedId = [];
$strategyNames = [];
try {
foreach ($strategies as $strategyName => $syncStrategy) {
$strategyNames[] = $strategyName;
$this->logger->info(
'[' . $this->getDisplayName() . '] Syncing opportunities using strategy: ' . $strategyName,
['team' => $this->team->getId()]
);
$total = 0;
$lastId = null;
$buffer = [];
// HubspotWebhookBatchSyncStrategy returns empty generator, this is for other strategies
foreach ($syncStrategy->fetchOpportunities($parameters, $total, $lastId) as $hsOpportunity) {
$buffer[] = $hsOpportunity;
// process every 800 rows (fits < 1 000 association limit)
if (\count($buffer) >= self::BATCH_PROCESS_SIZE) {
$syncCount += $this->processOpportunityBatch($buffer);
$buffer = [];
}
}
// leftovers
if ($buffer) {
$syncCount += $this->processOpportunityBatch($buffer);
}
$reportedTotal += $total;
$lastSyncedId = $lastId;
}
} catch (\HubSpot\Client\Crm\Deals\ApiException | CrmException $e) {
$this->handleSyncException($e, $parameters);
}
$durationMs = round((microtime(true) - $startTime) * 1000, 2);
$this->logger->info(
'[HubSpot] Synced opportunities',
[
'team' => $this->team->getId(),
'strategies' => implode(',', $strategyNames),
'sync_count' => $syncCount,
'total' => $reportedTotal,
'last_synced_id' => $lastSyncedId,
'duration_ms' => $durationMs,
]
);
return $reportedTotal;
}
private function handleSyncException(\Throwable $e, array $parameters): void
{
if (($parameters['since'] ?? null) instanceof Carbon) {
$parameters['since'] = $parameters['since']->toDateTimeString();
}
$parameters['config'] = $this->config->getId();
$this->logger->warning('[' . $this->getDisplayName() . '] Sync opportunities failed', [
'teamId' => $this->team->getUuid(),
'parameters' => $parameters,
'reason' => $e->getMessage(),
]);
}
/**
* @inheritdoc
*/
public function syncOpportunity(string $crmId): ?Opportunity
{
$strategy = $this->opportunitySyncStrategyResolver->resolve(
$this->config,
OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY,
);
$parameters = [
'config' => $this->config,
'crm_id' => $crmId,
];
try {
if (! $strategy instanceof HubspotSingleSyncStrategy) {
throw new InvalidArgumentException('Strategy must by HubspotSingleSyncStrategy');
}
$hsOpportunity = $strategy->fetchOpportunity($parameters);
} catch (\HubSpot\Client\Crm\Deals\ApiException $e) {
$this->logger->info('[' . $this->getDisplayName() . '] Opportunity not found', [
'teamId' => $this->team->getUuid(),
'crmId' => $crmId,
'reason' => $e->getMessage(),
]);
return null;
}
$hsOpportunity['associations'] = $this->convertDealAssociations($hsOpportunity['associations'] ?? []);
return $this->importOrUpdateOpportunity($hsOpportunity);
}
/**
* Process webhook-collected opportunity batches.
*
* Drains Redis sets containing company CRM IDs collected from webhook events
* and dispatches ImportOpportunityBatch jobs for batch processing.
*
* @return int Number of opportunity IDs dispatched to jobs
*/
public function batchSyncOpportunities(): int
{
$configId = $this->team->getCrmConfiguration()->getId();
return $this->batchProcessor->processBatchesForObjectType(
WebhookSyncBatchProcessor::OBJECT_TYPE_DEAL,
$configId
);
}
/**
* Import a batch of opportunities by their CRM IDs.
* Fetches opportunity data from HubSpot API and delegates to importOpportunityBatch().
*
* @param array<string> $crmIds HubSpot deal CRM IDs
*
* @return array{success: array, failed_ids: array, errors?: array<string, string>}
*/
public function importOpportunityBatchByIds(array $crmIds): array
{
$fields = $this->dealFieldsService->getFieldsForConfiguration($this->config);
$allDeals = [];
foreach (array_chunk($crmIds, self::BATCH_SIZE) as $chunk) {
$deals = $this->client->getOpportunitiesByIds($chunk, $fields);
foreach ($deals as $deal) {
$allDeals[] = $deal;
}
}
// IDs not returned by HubSpot are likely deleted or inaccessible deals.
// These are not failures — retrying won't bring them back.
$fetchedIds = array_map('strval', array_column($allDeals, 'id'));
$notFoundIds = array_values(array_diff(array_map('strval', $crmIds), $fetchedIds));
if (! empty($notFoundIds)) {
$this->logger->info('[' . $this->getDisplayName() . '] CRM IDs not found in HubSpot (likely deleted)', [
'teamId' => $this->team->getId(),
'notFoundCount' => \count($notFoundIds),
'notFoundIds' => $notFoundIds,
'requestedCount' => \count($crmIds),
'fetchedCount' => \count($allDeals),
]);
}
if (empty($allDeals)) {
return ['success' => [], 'failed_ids' => []];
}
return $this->importOpportunityBatch($allDeals);
}
private function getClosedDealStages(): array
{
if ($this->cachedClosedDealStages !== null) {
return $this->cachedClosedDealStages;
}
$stages = $this->crmEntityRepository->getOpportunityClosedStages($this->config);
$data = [
'lost' => [],
'won' => [],
];
foreach ($stages as $stage) {
if ($stage->probability == 0.00) {
$data['lost'][] = $stage->crm_provider_id;
}
if ($stage->probability == 100.00) {
$data['won'][] = $stage->crm_provider_id;
}
}
$this->cachedClosedDealStages = $data;
return $data;
}
/**
* Import deals into the database with pre-fetched associations.
*
* API calls here (getAssociationsData, getExistingOpportunityCrmIds) are NOT
* caught — if they throw, the exception propagates to ImportOpportunityBatch::handle()
* where Laravel retries the whole job with backoff. After all retries exhausted,
* failed() requeues all IDs to Redis.
*
* The per-deal loop catches exceptions individually. A deal can end up in three states:
* - success: imported/updated successfully
* - failed_ids: exception thrown (DB constraint violation, corrupt data, etc.)
* These are permanent issues — retrying won't fix them.
* - skipped (null): missing dependencies (no account, unknown pipeline/stage).
* This is acceptable — the deal cannot be imported until those exist.
*/
private function importOpportunityBatch(array $deals): array
{
$syncedOpportunities = [
'success' => [],
'failed_ids' => [],
];
$dealIds = array_column($deals, 'id');
// Shared association/existing-ID preparation is batch-level state. If it fails, rethrow so the
// queue job retries the whole batch and eventually requeues all deal IDs back to Redis.
try {
$companyAssociations = $this->client->getAssociationsData($dealIds, 'deals', 'companies');
$contactAssociations = $this->client->getAssociationsData($dealIds, 'deals', 'contacts');
$associationsData = $this->prepareAssociatedEntities($companyAssociations, $contactAssociations);
$existingCrmIds = $this->crmEntityRepository->getExistingOpportunityCrmIds(
$this->config,
array_map('strval', $dealIds)
);
$existingCrmIdSet = array_flip($existingCrmIds);
} catch (\Throwable $e) {
$this->logger->error('[' . $this->getDisplayName() . '] Failed to fetch associations or existing IDs', [
'teamId' => $this->team->getId(),
'dealCount' => count($dealIds),
'error' => $e->getMessage(),
]);
throw $e;
}
foreach ($deals as $deal) {
try {
$deal['associations'] = $this->prepareAssociationsForOpportunity(
$deal['id'],
$companyAssociations,
$contactAssociations,
$associationsData
);
$syncedOpportunity = $this->importOrUpdateOpportunity(
$deal,
isset($existingCrmIdSet[(string) $deal['id']])
);
if ($syncedOpportunity) {
$syncedOpportunities['success'][] = $syncedOpportunity;
}
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Failed to import opportunity', [
'teamId' => $this->team->getId(),
'crmId' => $deal['id'],
'error' => $e->getMessage(),
]);
$syncedOpportunities['failed_ids'][] = $deal['id'];
$syncedOpportunities['errors'][$deal['id']] = $e->getMessage();
}
}
return $syncedOpportunities;
}
/**
* Prepare associated entities for opportunities with optimized batch processing
* Returns structured data with CRM ID to DB ID mappings for each opportunity
*/
private function prepareAssociatedEntities(array $companyAssociations, array $contactAssociations): array
{
// Step 1: Collect all unique company and contact IDs from associations
$allCompanyIds = $this->flattenAssociationIds($companyAssociations);
$allContactIds = $this->flattenAssociationIds($contactAssociations);
// Step 2: Batch sync missing entities and get CRM ID to DB ID mappings
$companyIdMappings = [];
$contactIdMappings = [];
if (! empty($allCompanyIds)) {
$companyIdMappings = $this->prepareAssociatedAccounts($allCompanyIds);
}
if (! empty($allContactIds)) {
$contactIdMappings = $this->prepareAssociatedContacts($allContactIds);
}
return [
'company_id_mappings' => $companyIdMappings,
'contact_id_mappings' => $contactIdMappings,
];
}
/**
* Flatten association data to get unique IDs
*/
private function flattenAssociationIds(array $associations): array
{
$ids = [];
foreach ($associations as $dealAssociations) {
if (is_array($dealAssociations)) {
foreach ($dealAssociations as $id) {
$ids[$id] = true;
}
}
}
return array_keys($ids);
}
/**
* Batch sync missing accounts
*/
private function prepareAssociatedAccounts(array $companyIds): array
{
// Find which accounts already exist
$existingAccounts = $this->crmEntityRepository
->findAccountsByExternalIds($this->config, $companyIds);
$existingCompanyIds = $existingAccounts->pluck('crm_provider_id')->toArray();
$existingAccountsData = $existingAccounts->mapWithKeys(function ($account) {
return [$account->getCrmProviderId() => $account->getId()];
})->toArray();
$missingCompanyIds = array_diff($companyIds, $existingCompanyIds);
if (empty($missingCompanyIds)) {
return $existingAccountsData;
}
$this->logger->info('[' . $this->getDisplayName() . '] Batch syncing missing accounts', [
'teamId' => $this->team->getUuid(),
'total_companies' => count($companyIds),
'existing_companies' => count($existingCompanyIds),
'missing_companies' => count($missingCompanyIds),
]);
// we already have limit on opportunity ids count
// Initialize variable before try block
$syncedAccountsData = [];
try {
$syncedAccountsData = $this->batchSyncCrmObjects('companies', $missingCompanyIds);
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Failed to sync missing accounts', [
'size' => count($missingCompanyIds),
'error' => $e->getMessage(),
]);
$syncedAccountsData = [];
}
return $existingAccountsData + $syncedAccountsData;
}
/**
* Prepare associated contacts - find existing and sync missing ones
* Returns mapping of CRM ID to DB ID
*/
private function prepareAssociatedContacts(array $contactIds): array
{
// Find which contacts already exist
$existingContacts = $this->crmEntityRepository
->findContactsByExternalIds($this->config, $contactIds);
$existingContactIds = $existingContacts->pluck('crm_provider_id')->toArray();
// Create mapping for existing contacts
$existingContactsData = $existingContacts->mapWithKeys(function ($contact) {
return [$contact->getCrmProviderId() => $contact->getId()];
})->toArray();
$missingContactIds = array_diff($contactIds, $existingContactIds);
if (empty($missingContactIds)) {
return $existingContactsData;
}
$this->logger->info('[' . $this->getDisplayName() . '] Batch syncing missing contacts', [
'teamId' => $this->team->getUuid(),
'total_contacts' => count($contactIds),
'existing_contacts' => count($existingContactIds),
'missing_contacts' => count($missingContactIds),
]);
// Sync missing contacts using batch API
try {
$syncedContactsData = $this->batchSyncCrmObjects('contacts', $missingContactIds);
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Failed to sync missing contacts', [
'size' => count($missingContactIds),
'error' => $e->getMessage(),
]);
$syncedContactsData = [];
}
return $existingContactsData + $syncedContactsData;
}
private function batchSyncCrmObjects(string $objectType, array $crmIds): array
{
$syncObjects = [];
$crmObjectIds = array_values($crmIds);
foreach (array_chunk($crmObjectIds, self::BATCH_SIZE) as $chunk) {
try {
$objects = $objectType === 'companies' ?
$this->client->getCompaniesByIds($chunk, $this->getCompanyFields()) :
$this->client->getContactsByIds($chunk, $this->getContactFields());
foreach ($objects as $objectId => $objectData) {
$this->importCrmObject($objectType, (string) $objectId, $objectData, $syncObjects);
}
$this->logger->info('[' . $this->getDisplayName() . '] Batch synced ' . $objectType, [
'requested_count' => count($chunk),
'synced_count' => count($objects),
]);
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Batch ' . $objectType . ' sync failed', [
'ids' => $chunk,
'error' => $e->getMessage(),
]);
}
}
return $syncObjects;
}
private function importCrmObject(string $objectType, string $objectId, mixed $objectData, array &$syncObjects): void
{
try {
$object = $objectType === 'companies' ?
$this->importAccount($objectData) :
$this->importContact($objectData);
if ($object) {
$syncObjects[$object->getCrmProviderId()] = $object->getId();
}
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Failed to import batch ' . $objectType, [
'id' => $objectId,
'error' => $e->getMessage(),
]);
}
}
/**
* Prepare associations for a single opportunity
*
* The return value is an array with the following structure:
* [
* 'companies' => [
* $companyCrmId => $companyId,
* ...
* ],
* 'contacts' => [
* $contactCrmId => $contactId,
* ...
* ],
* 'account_id' => $accountId,
* ]
*/
private function prepareAssociationsForOpportunity(
string $oppCrmId,
array $companyAssociations,
array $contactAssociations,
array $associationsData
): array {
$associations = [
'companies' => [],
'contacts' => [],
'account_id' => null, // Primary account for opportunity
];
$oppCompanyIds = $companyAssociations[$oppCrmId] ?? [];
foreach ($oppCompanyIds as $companyCrmId) {
if (isset($associationsData['company_id_mappings'][$companyCrmId])) {
$associations['companies'][$companyCrmId] = $associationsData['company_id_mappings'][$companyCrmId];
// Set primary account (first company becomes primary account)
if ($associations['account_id'] === null) {
$associations['account_id'] = $associationsData['company_id_mappings'][$companyCrmId];
}
}
}
$oppContactIds = $contactAssociations[$oppCrmId] ?? [];
foreach ($oppContactIds as $contactCrmId) {
if (isset($associationsData['contact_id_mappings'][$contactCrmId])) {
$associations['contacts'][$contactCrmId] = $associationsData['contact_id_mappings'][$contactCrmId];
}
}
return $associations;
}
/**
* Update only associations for an opportunity
*/
private function updateOpportunityAssociations(Opportunity $opportunity, array $associations): void
{
// Update contact associations
$this->importOpportunityContacts($opportunity, $associations['contacts']);
// Update company (account) associations
$this->updateOpportunityAccount($opportunity, $associations['account_id']);
}
/**
* Remove all contact associations from an opportunity
*/
private function removeAllOpportunityContacts(Opportunity $opportunity): void
{
$currentCount = (int) $opportunity->contacts()->count();
if ($currentCount > 0) {
$opportunity->contacts()->detach();
$this->logger->info('[' . $this->getDisplayName() . '] Removed all contact associations', [
'opportunity_id' => $opportunity->getId(),
'removed_count' => $currentCount,
]);
}
}
private function updateOpportunityAccount(Opportunity $opportunity, ?int $accountId): void
{
if ($accountId === null) {
// No account ID provided - keep current account
return;
}
$currentAccountId = $opportunity->getAccountId();
// Only update if account has changed
if ($currentAccountId !== $accountId) {
$opportunity->account_id = $accountId;
$opportunity->save();
$this->logger->info('[' . $this->getDisplayName() . '] Updated opportunity account association', [
'opportunity_id' => $opportunity->getId(),
'old_account_id' => $currentAccountId,
'new_account_id' => $accountId,
]);
}
}
/**
* Find existing opportunities by external IDs (OPTIMIZED VERSION)
* Uses batch query for better performance
*/
private function findExistingOpportunities(array $crmIds): Collection
{
return $this->crmEntityRepository
->findOpportunitiesByExternalIds($this->config, $crmIds);
}
private function processOpportunityBatch(array $opportunities): int
{
$syncedOpportunities = $this->importOpportunityBatch($opportunities);
return count($syncedOpportunities['success'] ?? []);
}
/**
* Convert single deal associations from HubSpot format to internal format
* Handles both HubSpot SDK objects and array formats
*
* @param array $opportunityAssociations Raw associations from HubSpot API or pre-processed
*
* @return array Processed associations with DB IDs
*/
private function convertDealAssociations(array $opportunityAssociations): array
{
$associations = $this->initializeAssociationsStructure();
if (empty($opportunityAssociations)) {
return $associations;
}
$associationIds = $this->extractAssociationIds($opportunityAssociations);
$this->processCompanyAssociations($associationIds, $associations);
$this->processContactAssociations($associationIds, $associations);
return $associations;
}
private function initializeAssociationsStructure(): array
{
return [
'companies' => [],
'contacts' => [],
'account_id' => null, // Primary account for opportunity
];
}
private function extractAssociationIds(array $opportunityAssociations): array
{
$associationIds = [];
foreach ($opportunityAssociations as $type => $associationData) {
if (! empty($associationData)) {
$associationIds[$type] = $this->convertSingleDealAssociations($associationData);
}
}
return $associationIds;
}
private function processCompanyAssociations(array $associationIds, array &$associations): void
{
if (empty($associationIds['companies'])) {
return;
}
$companyId = $associationIds['companies'][0];
$account = $this->findOrSyncAccount($companyId);
if ($account instanceof Account) {
$associations['companies'][$companyId] = $account->getId();
$associations['account_id'] = $account->getId();
}
}
private function processContactAssociations(array $associationIds, array &$associations): void
{
if (empty($associationIds['contacts'])) {
return;
}
foreach ($associationIds['contacts'] as $contactId) {
$contact = $this->findOrSyncContact($contactId);
if ($contact instanceof Contact) {
$associations['contacts'][$contactId] = $contact->getId();
}
}
}
private function findOrSyncAccount(string $companyId): ?Account
{
$account = $this->crmEntityRepository->findAccountByExternalId($this->config, $companyId);
if (! $account instanceof Account) {
$account = $this->syncAccount($companyId);
}
return $account;
}
private function findOrSyncContact(string $contactId): ?Contact
{
$contact = $this->crmEntityRepository->findContactByExternalId($this->config, $contactId);
if (! $contact instanceof Contact) {
$contact = $this->syncContact($contactId);
}
return $contact;
}
private function convertSingleDealAssociations($opportunityAssociations = null): array
{
$associationData = [];
if ($opportunityAssociations === null) {
return $associationData;
}
// Handle array input (from extractAssociationIds)
if (is_array($opportunityAssociations)) {
return $opportunityAssociations;
}
// Handle CollectionResponseAssociatedId object
if ($opportunityAssociations instanceof CollectionResponseAssociatedId) {
foreach ($opportunityAssociations->getResults() as $association) {
$associationData[] = $association->getId();
}
}
return $associationData;
}
private function importOrUpdateOpportunity($crmData, ?bool $exists = null): ?Opportunity
{
if (empty($crmData['properties'])) {
return null;
}
$crmId = (string) $crmData['id'];
$properties = $crmData['properties'];
$associations = $crmData['associations'] ?? [];
$opportunityExists = $exists ?? (bool) $this->crmEntityRepository->findOpportunityByExternalId(
$this->config,
$crmId
);
if ($opportunityExists) {
return $this->updateOpportunity($crmId, $properties, $associations);
}
return $this->createOpportunity($crmId, $properties, $associations);
}
/**
* Create new opportunity
*/
private function createOpportunity(string $crmId, array $properties, array $associations): ?Opportunity
{
$accountId = $this->resolveAccountId($associations);
if (! $accountId) {
return null;
}
$businessProcess = $this->resolveBusinessProcess($properties['pipeline'] ?? null);
if (! $businessProcess) {
return null;
}
$stage = $this->resolveStage($businessProcess, $properties['dealstage'] ?? null);
if (! $stage) {
return null;
}
$data = $this->buildOpportunityData($properties, $accountId, $businessProcess, $stage);
$attributes = [
'crm_configuration_id' => $this->config->getId(),
'crm_provider_id' => $crmId,
];
$values = array_merge($attributes, $data);
$opportunity = $this->crmEntityRepository->upsertOpportunity($attributes, $values);
$this->importExternalFieldData($properties, $opportunity->getId());
$this->importOpportunityContacts($opportunity, $associations['contacts']);
if ($opportunity->wasRecentlyCreated) {
MatchActivitiesToNewOpportunity::dispatch($opportunity->getId());
}
return $opportunity;
}
/**
* Update existing opportunity
*/
private function updateOpportunity(string $crmId, array $properties, array $associations): Opportunity
{
$accountId = $this->resolveAccountId($associations);
$businessProcess = $this->resolveBusinessProcess($properties['pipeline'] ?? null);
$stage = $businessProcess ? $this->resolveStage($businessProcess, $properties['dealstage'] ?? null) : null;
$data = $this->buildOpportunityData($properties, $accountId, $businessProcess, $stage);
$attributes = [
'crm_configuration_id' => $this->config->getId(),
'crm_provider_id' => $crmId,
];
$values = array_merge($attributes, $data);
$opportunity = $this->crmEntityRepository->upsertOpportunity($attributes, $values);
$this->importExternalFieldData($properties, $opportunity->getId());
$this->updateOpportunityAssociations($opportunity, $associations);
return $opportunity;
}
private function resolveAccountId(array $associations): ?int
{
if (! empty($associations['account_id'])) {
return $associations['account_id'];
}
if (empty($associations)) {
return null;
}
// Fallback: use first company as account (currently SDK returns one company)
foreach ($associations['companies'] as $accountId) {
return $accountId;
}
return null;
}
private function buildOpportunityData(
array $properties,
?int $accountId,
?BusinessProcess $businessProcess,
?Stage $stage
): array {
$ownerId = null;
$profile = null;
if (! empty($properties['hubspot_owner_id'])) {
$ownerId = $properties['hubspot_owner_id'];
$profile = $this->crmEntityRepository->findProfileByExternalId($this->config, (string) $ownerId);
}
$name = 'Unknown';
if (isset($properties['dealname'])) {
$name = mb_strimwidth($properties['dealname'], 0, 128);
}
$amount = $this->resolveAmount($properties);
$currency = $properties['deal_currency_code'] ?? null;
$closeDate = null;
if (! empty($properties['closedate'])) {
$closeDate = Carbon::parse($properties['closedate'])->format('Y-m-d');
}
$remotelyCreatedAt = null;
if (! empty($properties['createdate']) && strtotime($properties['createdate'])) {
$date = $this->parseCleanDatetime($properties['createdate']);
$remotelyCreatedAt = $date?->format('Y-m-d H:i:s');
}
$closedStages = $this->getClosedDealStages();
$isWon = in_array($properties['dealstage'], $closedStages['won']);
$isLost = in_array($properties['dealstage'], $closedStages['lost']);
$data = [
'team_id' => $this->team->getId(),
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $ownerId,
'name' => $name,
'value' => ! empty($amount) ? $amount : null,
'currency_code' => CurrencyFormatter::formatCode($currency),
'close_date' => $closeDate,
'is_closed' => $isWon || $isLost,
'is_won' => $isWon,
'remotely_created_at' => $remotelyCreatedAt,
'probability' => $this->resolveDealProbability($properties['hs_deal_stage_probability']),
'forecast_category' => $this->resolveForecastCategory($properties['hs_manual_forecast_category']),
];
if ($accountId) {
$data['account_id'] = $accountId;
}
if ($stage) {
$data['stage_id'] = $stage->id;
}
if ($businessProcess) {
$recordType = $this->crmEntityRepository->getBusinessProcessRecordType($businessProcess);
if ($recordType) {
$data['record_type_id'] = $recordType->id;
}
}
return $data;
}
private function resolveBusinessProcess(?string $pipelineId): ?BusinessProcess
{
if ($pipelineId === null) {
return null;
}
$cacheKey = $this->getBusinessProcessCacheKey($pipelineId);
if (isset($this->cachedBusinessProcesses[$cacheKey])) {
return $this->cachedBusinessProcesses[$cacheKey];
}
$businessProcess = $this->getBusinessProcess($pipelineId);
if (! $businessProcess instanceof BusinessProcess) {
$this->importStages();
$businessProcess = $this->getBusinessProcess($pipelineId);
}
if (! $businessProcess instanceof BusinessProcess) {
$this->logger->info(
'[HubSpot] Deal is not attached to a pipeline',
[
'pipeline' => $pipelineId]
);
}
$this->cachedBusinessProcesses[$cacheKey] = $businessProcess;
return $businessProcess;
}
private function getBusinessProcess(string $pipelineId): ?BusinessProcess
{
return $this->crmEntityRepository->findBusinessProcessesByExternalId($this->config, $pipelineId);
}
private function getBusinessProcessCacheKey(string $pipelineId): string
{
return $this->config->getId() . '_' . $pipelineId;
}
private function resolveStage(BusinessProcess $businessProcess, ?string $stageId): ?Stage
{
if (empty($stageId)) {
return null;
}
$cacheKey = $businessProcess->getId() . ':' . $stageId;
if (isset($this->cachedStages[$cacheKey])) {
return $this->cachedStages[$cacheKey];
}
$stage = $this->crmEntityRepository->getPipelineStageByConditions(
$businessProcess,
[
'crm_provider_id' => $stageId,
'type' => Stage::TYPE_OPPORTUNITY,
]
);
if ($stage === null) {
$this->importStages(null, $stageId);
}
if ($stage === null) {
$this->logger->info('[HubSpot] Stage does not exist => ' . $stageId);
}
$this->cachedStages[$cacheKey] = $stage;
return $stage;
}
private function resolveAmount(array $properties): ?string
{
$amount = null;
if (! empty($properties['amount'])) {
$amount = str_replace(',', '', $properties['amount']);
}
if ($this->config->hasDefaultCurrencyFieldSet()) {
$valueFieldName = $this->config->getDefaultCurrencyField()->getCrmProviderId();
$amount = $properties[$valueFieldName] ?? $amount;
}
return $amount;
}
private function parseCleanDatetime(string $datetime): ?Carbon
{
// Treat pre-1980 values as invalid
$minValidDate = Carbon::parse('1980-01-01 00:00:00');
try {
$date = Carbon::parse($datetime);
if ($minValidDate->gt($date)) {
return null;
}
return $date;
} catch (Exception) {
return null; // On parse error, treat as null
}
}
private function resolveDealProbability(?string $stageProbability): int
{
if ($stageProbability === null) {
return 0;
}
$probability = (float) $stageProbability;
return $probability > 1 ? 0 : (int) ($probability * 100);
}
private function resolveForecastCategory(?string $forecastCategory): string
{
if (! $forecastCategory) {
return Forecast::FORECAST_CATEGORY_UNCATEGORIZED;
}
$forecastCategory = str_replace('_', ' ', $forecastCategory);
return ucwords(strtolower($forecastCategory));
}
private function importExternalFieldData(array $properties, int $opportunityId): void
{
$crmFields = $this->getOpportunitySyncableFields();
$this->importOpportunityCrmFieldData($properties, $crmFields, $opportunityId);
}
private function importOpportunityContacts(Opportunity $opportunity, array $associations): void
{
// Handle empty or missing contact associations
if (empty($associations)) {
// Remove all existing contact associations if none provided
$this->removeAllOpportunityContacts($opportunity);
return;
}
// Use differential sync approach for better performance and accuracy
$this->syncOpportunityContactsDifferential($opportunity, $associations);
}
/**
* Sync opportunity contacts using differential approach
* This compares current vs new associations and only makes necessary changes
*/
private function syncOpportunityContactsDifferential(Opportunity $opportunity, array $contactAssociations): void
{
$currentContactCrmIds = $this->getCurrentContactCrmIds($opportunity);
$contactAssociationIds = array_keys($contactAssociations);
$contactsToAdd = array_diff($contactAssociationIds, $currentContactCrmIds);
$contactsToRemove = array_diff($currentContactCrmIds, $contactAssociationIds);
if (empty($contactsToAdd) && empty($contactsToRemove)) {
return;
}
$this->logContactAssociationChanges($opportunity, $currentContactCrmIds, $contactAssociations, $contactsToAdd, $contactsToRemove);
$this->removeContactAssociations($opportunity, $contactsToRemove);
$this->addContactAssociations($opportunity, $contactsToAdd, $contactAssociations);
}
private function getCurrentContactCrmIds(Opportunity $opportunity): array
{
return $opportunity->contacts()
->pluck('contacts.crm_provider_id')
->toArray();
}
private function logContactAssociationChanges(
Opportunity $opportunity,
array $currentContactCrmIds,
array $contactAssociations,
array $contactsToAdd,
array $contactsToRemove
): void {
$this->logger->info('[' . $this->getDisplayName() . '] Contact association changes', [
'opportunity_id' => $opportunity->getId(),
'current_contacts' => $currentContactCrmIds,
'new_contacts' => $contactAssociations,
'contacts_to_add' => $contactsToAdd,
'contacts_to_remove' => $contactsToRemove,
]);
}
private function removeContactAssociations(Opportunity $opportunity, array $contactsToRemove): void
{
if (empty($contactsToRemove)) {
return;
}
$contactsToDetach = $opportunity->contacts()
->whereIn('contacts.crm_provider_id', $contactsToRemove)
->pluck('contacts.id')
->toArray();
if (! empty($contactsToDetach)) {
$opportunity->contacts()->detach($contactsToDetach);
$this->logger->info('[' . $this->getDisplayName() . '] Removed contact associations', [
'opportunity_id' => $opportunity->getId(),
'removed_contact_crm_ids' => $contactsToRemove,
'removed_contact_count' => count($contactsToDetach),
]);
}
}
private function addContactAssociations(Opportunity $opportunity, array $contactsToAdd, array $contactAssociations): void
{
if (empty($contactsToAdd)) {
return;
}
$contactsAdded = [];
foreach ($contactsToAdd as $crmId) {
$id = $contactAssociations[$crmId];
if ($this->attachSingleContact($opportunity, (string) $crmId, $id)) {
$contactsAdded[] = $crmId;
}
}
$this->logAddedContacts($opportunity, $contactsAdded);
}
private function attachSingleContact(Opportunity $opportunity, string $crmId, int $id): bool
{
try {
$contact = $this->crmEntityRepository->findContactByConfigurationAndId($this->config, $id);
if (! $contact) {
return false;
}
return $this->performContactAttachment($opportunity, $contact, $crmId);
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Failed to add contact association', [
'opportunity_id' => $opportunity->getId(),
'contact_crm_id' => $crmId,
'error' => $e->getMessage(),
]);
return false;
}
}
private function performContactAttachment(Opportunity $opportunity, Contact $contact, string $crmId): bool
{
try {
$opportunity->contacts()->attach($contact->getId(), [
'crm_provider_id' => $crmId,
]);
return true;
} catch (\Illuminate\Database\QueryException $e) {
if (str_contains($e->getMessage(), 'Duplicate entry')) {
$this->logger->info('[' . $this->getDisplayName() . '] Contact association already exists', [
'contact_id' => $contact->getId(),
'contact_crm_id' => $crmId,
'opportunity_id' => $opportunity->getId(),
]);
return false;
}
throw $e;
}
}
private function logAddedContacts(Opportunity $opportunity, array $contactsAdded): void
{
if (! empty($contactsAdded)) {
$this->logger->info('[' . $this->getDisplayName() . '] Added contact associations', [
'opportunity_id' => $opportunity->getId(),
'added_contact_crm_ids' => $contactsAdded,
'added_contacts_count' => count($contactsAdded),
]);
}
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
6
1
6
Previous Highlighted Error
Next Highlighted Error
# [PASSWORD_DOTS] HS [PASSWORD_DOTS]
select * from teams where id = 2; # 2
select * from features; # 2
select * from team_features where team_id = 2; # 2
select * from crm_configurations where id = 2; # 2
select * from users where team_id = 2; #
select * from playbooks where team_id = 2; # event 38
select * from playbook_categories where playbook_id = 38; #
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;
https://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624
https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0
SELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;
# 609126 softphone tr. 11241
SELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;
# 608874 conference tr. 11226 crmId: 103422236596
select * from ai_prompts where transcription_id IN (11241, 11226);
select * from activity_summary_logs where activity_id = 608874;
select * from sidekick_settings;
select * from default_activity_types;
select * from crm_field_data where activity_id = 1223;
select * from crm_layouts where crm_configuration_id = 2;
SELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);
select * from crm_fields where crm_configuration_id = 11 and object_type = 'event';
SELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);
SELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;
SELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u
on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 2 and sa.provider = 'hubspot';
select * from opportunities where team_id = 2
and crm_provider_id IN ('51317301383');
select * from contacts where id = 85;
select * from opportunities where team_id = 2 order by id desc;
select * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112
select * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112
select * from opportunity_contacts where opportunity_id = 5117;
select * from crm_field_data where object_id = 1365;
SELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);
select * from features;
select * from team_features where team_id IN (1);
select * from team_features where feature_id IN (36);
SHOW CREATE TABLE opportunity_contacts;
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';
# $slug = 'HUBSPOT_WEBHOOK_SYNC';
# $team = Jiminny\Models\Team::find(2);
# $feature = Feature::query()->where('slug', $slug)->first();
# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);
# hubspot_webhook_metrics
select * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365
SELECT * FROM opportunity_contacts WHERE opportunity_id = '414';
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';
select * from contacts where id in (414, 464);
select * from activities where crm_configuration_id = 2;
select settings from crm_configurations where id = 11;
select * from teams; # 1, 2
select * from users;
select * from crm_configurations where id = 39;
select * from team_features where team_id = 2;
select * from features;
# SELECT * FROM opportunities WHERE crm_configuration_id = 2
# order by id desc;
# and crm_provider_id = '49908861993';
select * from activity_providers where id IN (443, 202, 203, 227);
select * from activity_imports where id = 795889;
select c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id
where c.provider = 'hubspot';
select * from crm_configurations crm JOIN teams t on crm.team_id = t.id
where provider = 'hubspot';
SELECT * FROM teams WHERE id = 31;
SELECT * FROM users WHERE id = 257;
SELECT * FROM opportunities WHERE team_id = 2;
select * from opportunity_contacts where opportunity_id = 5124;
select * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)
select * from activities where crm_configuration_id = 13;
SELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141
select id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;
SELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;
SELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;
SELECT * FROM contacts WHERE team_id = 2 order by id desc;
select * from opportunity_contacts where contact_id = 6223;
SELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;
select * from crm_profiles where crm_configuration_id = 2;
select * from activities where account_id = 46;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11976 on JY-20553-debug-crm-sync-delays, menu","depth":5,"help_text":"Pull request #11976 exists for current branch JY-20553-debug-crm-sync-delays","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"RequestGenerateAskJiminnyReportJobTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'RequestGenerateAskJiminnyReportJobTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'RequestGenerateAskJiminnyReportJobTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"33","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"19","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits;\n\nuse Carbon\\Carbon;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\CollectionResponseAssociatedId;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Exception;\nuse Jiminny\\Component\\DealInsights\\Forecast\\Forecast;\nuse Jiminny\\Jobs\\Crm\\MatchActivitiesToNewOpportunity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Models\\Opportunity;\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Services\\Crm\\Hubspot\\DealFieldsService;\nuse Jiminny\\Services\\Crm\\Hubspot\\OpportunitySyncStrategy\\HubspotSingleSyncStrategy;\nuse Jiminny\\Services\\Crm\\Hubspot\\WebhookSyncBatchProcessor;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Utils\\CurrencyFormatter;\n\n/**\n * Optimized sync methods for better performance\n * These methods can be integrated into SyncCrmEntitiesTrait for significant performance gains\n */\ntrait OpportunitySyncTrait\n{\n private const int BATCH_SIZE = 100;\n private const int BATCH_PROCESS_SIZE = 800;\n\n protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;\n protected CrmEntityRepository $crmEntityRepository;\n protected DealFieldsService $dealFieldsService;\n\n private ?array $cachedClosedDealStages = null;\n private array $cachedBusinessProcesses = [];\n private array $cachedStages = [];\n\n public function syncOpportunities(array $parameters, ?string $strategy = null): int\n {\n $startTime = microtime(true);\n $strategies = $this->opportunitySyncStrategyResolver->getStrategies($this->config, $strategy);\n $parameters['config'] = $this->config;\n $syncCount = 0;\n $reportedTotal = 0;\n $lastSyncedId = [];\n $strategyNames = [];\n\n try {\n foreach ($strategies as $strategyName => $syncStrategy) {\n $strategyNames[] = $strategyName;\n $this->logger->info(\n '[' . $this->getDisplayName() . '] Syncing opportunities using strategy: ' . $strategyName,\n ['team' => $this->team->getId()]\n );\n\n $total = 0;\n $lastId = null;\n $buffer = [];\n\n // HubspotWebhookBatchSyncStrategy returns empty generator, this is for other strategies\n foreach ($syncStrategy->fetchOpportunities($parameters, $total, $lastId) as $hsOpportunity) {\n $buffer[] = $hsOpportunity;\n\n // process every 800 rows (fits < 1 000 association limit)\n if (\\count($buffer) >= self::BATCH_PROCESS_SIZE) {\n $syncCount += $this->processOpportunityBatch($buffer);\n $buffer = [];\n }\n }\n\n // leftovers\n if ($buffer) {\n $syncCount += $this->processOpportunityBatch($buffer);\n }\n\n $reportedTotal += $total;\n $lastSyncedId = $lastId;\n }\n } catch (\\HubSpot\\Client\\Crm\\Deals\\ApiException | CrmException $e) {\n $this->handleSyncException($e, $parameters);\n }\n\n $durationMs = round((microtime(true) - $startTime) * 1000, 2);\n $this->logger->info(\n '[HubSpot] Synced opportunities',\n [\n 'team' => $this->team->getId(),\n 'strategies' => implode(',', $strategyNames),\n 'sync_count' => $syncCount,\n 'total' => $reportedTotal,\n 'last_synced_id' => $lastSyncedId,\n 'duration_ms' => $durationMs,\n ]\n );\n\n return $reportedTotal;\n }\n\n private function handleSyncException(\\Throwable $e, array $parameters): void\n {\n if (($parameters['since'] ?? null) instanceof Carbon) {\n $parameters['since'] = $parameters['since']->toDateTimeString();\n }\n $parameters['config'] = $this->config->getId();\n\n $this->logger->warning('[' . $this->getDisplayName() . '] Sync opportunities failed', [\n 'teamId' => $this->team->getUuid(),\n 'parameters' => $parameters,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n /**\n * @inheritdoc\n */\n public function syncOpportunity(string $crmId): ?Opportunity\n {\n $strategy = $this->opportunitySyncStrategyResolver->resolve(\n $this->config,\n OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY,\n );\n\n $parameters = [\n 'config' => $this->config,\n 'crm_id' => $crmId,\n ];\n\n try {\n if (! $strategy instanceof HubspotSingleSyncStrategy) {\n throw new InvalidArgumentException('Strategy must by HubspotSingleSyncStrategy');\n }\n\n $hsOpportunity = $strategy->fetchOpportunity($parameters);\n } catch (\\HubSpot\\Client\\Crm\\Deals\\ApiException $e) {\n $this->logger->info('[' . $this->getDisplayName() . '] Opportunity not found', [\n 'teamId' => $this->team->getUuid(),\n 'crmId' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n return null;\n }\n\n $hsOpportunity['associations'] = $this->convertDealAssociations($hsOpportunity['associations'] ?? []);\n\n return $this->importOrUpdateOpportunity($hsOpportunity);\n }\n\n /**\n * Process webhook-collected opportunity batches.\n *\n * Drains Redis sets containing company CRM IDs collected from webhook events\n * and dispatches ImportOpportunityBatch jobs for batch processing.\n *\n * @return int Number of opportunity IDs dispatched to jobs\n */\n public function batchSyncOpportunities(): int\n {\n $configId = $this->team->getCrmConfiguration()->getId();\n\n return $this->batchProcessor->processBatchesForObjectType(\n WebhookSyncBatchProcessor::OBJECT_TYPE_DEAL,\n $configId\n );\n }\n\n /**\n * Import a batch of opportunities by their CRM IDs.\n * Fetches opportunity data from HubSpot API and delegates to importOpportunityBatch().\n *\n * @param array<string> $crmIds HubSpot deal CRM IDs\n *\n * @return array{success: array, failed_ids: array, errors?: array<string, string>}\n */\n public function importOpportunityBatchByIds(array $crmIds): array\n {\n $fields = $this->dealFieldsService->getFieldsForConfiguration($this->config);\n\n $allDeals = [];\n foreach (array_chunk($crmIds, self::BATCH_SIZE) as $chunk) {\n $deals = $this->client->getOpportunitiesByIds($chunk, $fields);\n foreach ($deals as $deal) {\n $allDeals[] = $deal;\n }\n }\n\n // IDs not returned by HubSpot are likely deleted or inaccessible deals.\n // These are not failures — retrying won't bring them back.\n $fetchedIds = array_map('strval', array_column($allDeals, 'id'));\n $notFoundIds = array_values(array_diff(array_map('strval', $crmIds), $fetchedIds));\n\n if (! empty($notFoundIds)) {\n $this->logger->info('[' . $this->getDisplayName() . '] CRM IDs not found in HubSpot (likely deleted)', [\n 'teamId' => $this->team->getId(),\n 'notFoundCount' => \\count($notFoundIds),\n 'notFoundIds' => $notFoundIds,\n 'requestedCount' => \\count($crmIds),\n 'fetchedCount' => \\count($allDeals),\n ]);\n }\n\n if (empty($allDeals)) {\n return ['success' => [], 'failed_ids' => []];\n }\n\n return $this->importOpportunityBatch($allDeals);\n }\n\n private function getClosedDealStages(): array\n {\n if ($this->cachedClosedDealStages !== null) {\n return $this->cachedClosedDealStages;\n }\n\n $stages = $this->crmEntityRepository->getOpportunityClosedStages($this->config);\n $data = [\n 'lost' => [],\n 'won' => [],\n ];\n\n foreach ($stages as $stage) {\n if ($stage->probability == 0.00) {\n $data['lost'][] = $stage->crm_provider_id;\n }\n if ($stage->probability == 100.00) {\n $data['won'][] = $stage->crm_provider_id;\n }\n }\n\n $this->cachedClosedDealStages = $data;\n\n return $data;\n }\n\n /**\n * Import deals into the database with pre-fetched associations.\n *\n * API calls here (getAssociationsData, getExistingOpportunityCrmIds) are NOT\n * caught — if they throw, the exception propagates to ImportOpportunityBatch::handle()\n * where Laravel retries the whole job with backoff. After all retries exhausted,\n * failed() requeues all IDs to Redis.\n *\n * The per-deal loop catches exceptions individually. A deal can end up in three states:\n * - success: imported/updated successfully\n * - failed_ids: exception thrown (DB constraint violation, corrupt data, etc.)\n * These are permanent issues — retrying won't fix them.\n * - skipped (null): missing dependencies (no account, unknown pipeline/stage).\n * This is acceptable — the deal cannot be imported until those exist.\n */\n private function importOpportunityBatch(array $deals): array\n {\n $syncedOpportunities = [\n 'success' => [],\n 'failed_ids' => [],\n ];\n $dealIds = array_column($deals, 'id');\n\n // Shared association/existing-ID preparation is batch-level state. If it fails, rethrow so the\n // queue job retries the whole batch and eventually requeues all deal IDs back to Redis.\n try {\n $companyAssociations = $this->client->getAssociationsData($dealIds, 'deals', 'companies');\n $contactAssociations = $this->client->getAssociationsData($dealIds, 'deals', 'contacts');\n\n $associationsData = $this->prepareAssociatedEntities($companyAssociations, $contactAssociations);\n\n $existingCrmIds = $this->crmEntityRepository->getExistingOpportunityCrmIds(\n $this->config,\n array_map('strval', $dealIds)\n );\n $existingCrmIdSet = array_flip($existingCrmIds);\n } catch (\\Throwable $e) {\n $this->logger->error('[' . $this->getDisplayName() . '] Failed to fetch associations or existing IDs', [\n 'teamId' => $this->team->getId(),\n 'dealCount' => count($dealIds),\n 'error' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n foreach ($deals as $deal) {\n try {\n $deal['associations'] = $this->prepareAssociationsForOpportunity(\n $deal['id'],\n $companyAssociations,\n $contactAssociations,\n $associationsData\n );\n\n $syncedOpportunity = $this->importOrUpdateOpportunity(\n $deal,\n isset($existingCrmIdSet[(string) $deal['id']])\n );\n if ($syncedOpportunity) {\n $syncedOpportunities['success'][] = $syncedOpportunity;\n }\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Failed to import opportunity', [\n 'teamId' => $this->team->getId(),\n 'crmId' => $deal['id'],\n 'error' => $e->getMessage(),\n ]);\n $syncedOpportunities['failed_ids'][] = $deal['id'];\n $syncedOpportunities['errors'][$deal['id']] = $e->getMessage();\n }\n }\n\n return $syncedOpportunities;\n }\n\n /**\n * Prepare associated entities for opportunities with optimized batch processing\n * Returns structured data with CRM ID to DB ID mappings for each opportunity\n */\n private function prepareAssociatedEntities(array $companyAssociations, array $contactAssociations): array\n {\n // Step 1: Collect all unique company and contact IDs from associations\n $allCompanyIds = $this->flattenAssociationIds($companyAssociations);\n $allContactIds = $this->flattenAssociationIds($contactAssociations);\n\n // Step 2: Batch sync missing entities and get CRM ID to DB ID mappings\n $companyIdMappings = [];\n $contactIdMappings = [];\n\n if (! empty($allCompanyIds)) {\n $companyIdMappings = $this->prepareAssociatedAccounts($allCompanyIds);\n }\n\n if (! empty($allContactIds)) {\n $contactIdMappings = $this->prepareAssociatedContacts($allContactIds);\n }\n\n return [\n 'company_id_mappings' => $companyIdMappings,\n 'contact_id_mappings' => $contactIdMappings,\n ];\n }\n\n /**\n * Flatten association data to get unique IDs\n */\n private function flattenAssociationIds(array $associations): array\n {\n $ids = [];\n foreach ($associations as $dealAssociations) {\n if (is_array($dealAssociations)) {\n foreach ($dealAssociations as $id) {\n $ids[$id] = true;\n }\n }\n }\n\n return array_keys($ids);\n }\n\n /**\n * Batch sync missing accounts\n */\n private function prepareAssociatedAccounts(array $companyIds): array\n {\n // Find which accounts already exist\n $existingAccounts = $this->crmEntityRepository\n ->findAccountsByExternalIds($this->config, $companyIds);\n\n $existingCompanyIds = $existingAccounts->pluck('crm_provider_id')->toArray();\n\n $existingAccountsData = $existingAccounts->mapWithKeys(function ($account) {\n return [$account->getCrmProviderId() => $account->getId()];\n })->toArray();\n\n $missingCompanyIds = array_diff($companyIds, $existingCompanyIds);\n\n if (empty($missingCompanyIds)) {\n return $existingAccountsData;\n }\n\n $this->logger->info('[' . $this->getDisplayName() . '] Batch syncing missing accounts', [\n 'teamId' => $this->team->getUuid(),\n 'total_companies' => count($companyIds),\n 'existing_companies' => count($existingCompanyIds),\n 'missing_companies' => count($missingCompanyIds),\n ]);\n\n // we already have limit on opportunity ids count\n // Initialize variable before try block\n $syncedAccountsData = [];\n\n try {\n $syncedAccountsData = $this->batchSyncCrmObjects('companies', $missingCompanyIds);\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Failed to sync missing accounts', [\n 'size' => count($missingCompanyIds),\n 'error' => $e->getMessage(),\n ]);\n $syncedAccountsData = [];\n }\n\n return $existingAccountsData + $syncedAccountsData;\n }\n\n /**\n * Prepare associated contacts - find existing and sync missing ones\n * Returns mapping of CRM ID to DB ID\n */\n private function prepareAssociatedContacts(array $contactIds): array\n {\n // Find which contacts already exist\n $existingContacts = $this->crmEntityRepository\n ->findContactsByExternalIds($this->config, $contactIds);\n\n $existingContactIds = $existingContacts->pluck('crm_provider_id')->toArray();\n\n // Create mapping for existing contacts\n $existingContactsData = $existingContacts->mapWithKeys(function ($contact) {\n return [$contact->getCrmProviderId() => $contact->getId()];\n })->toArray();\n\n $missingContactIds = array_diff($contactIds, $existingContactIds);\n\n if (empty($missingContactIds)) {\n return $existingContactsData;\n }\n\n $this->logger->info('[' . $this->getDisplayName() . '] Batch syncing missing contacts', [\n 'teamId' => $this->team->getUuid(),\n 'total_contacts' => count($contactIds),\n 'existing_contacts' => count($existingContactIds),\n 'missing_contacts' => count($missingContactIds),\n ]);\n\n // Sync missing contacts using batch API\n try {\n $syncedContactsData = $this->batchSyncCrmObjects('contacts', $missingContactIds);\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Failed to sync missing contacts', [\n 'size' => count($missingContactIds),\n 'error' => $e->getMessage(),\n ]);\n $syncedContactsData = [];\n }\n\n return $existingContactsData + $syncedContactsData;\n }\n\n private function batchSyncCrmObjects(string $objectType, array $crmIds): array\n {\n $syncObjects = [];\n $crmObjectIds = array_values($crmIds);\n\n foreach (array_chunk($crmObjectIds, self::BATCH_SIZE) as $chunk) {\n try {\n $objects = $objectType === 'companies' ?\n $this->client->getCompaniesByIds($chunk, $this->getCompanyFields()) :\n $this->client->getContactsByIds($chunk, $this->getContactFields());\n\n foreach ($objects as $objectId => $objectData) {\n $this->importCrmObject($objectType, (string) $objectId, $objectData, $syncObjects);\n }\n\n $this->logger->info('[' . $this->getDisplayName() . '] Batch synced ' . $objectType, [\n 'requested_count' => count($chunk),\n 'synced_count' => count($objects),\n ]);\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Batch ' . $objectType . ' sync failed', [\n 'ids' => $chunk,\n 'error' => $e->getMessage(),\n ]);\n }\n }\n\n return $syncObjects;\n }\n\n private function importCrmObject(string $objectType, string $objectId, mixed $objectData, array &$syncObjects): void\n {\n try {\n $object = $objectType === 'companies' ?\n $this->importAccount($objectData) :\n $this->importContact($objectData);\n\n if ($object) {\n $syncObjects[$object->getCrmProviderId()] = $object->getId();\n }\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Failed to import batch ' . $objectType, [\n 'id' => $objectId,\n 'error' => $e->getMessage(),\n ]);\n }\n }\n\n /**\n * Prepare associations for a single opportunity\n *\n * The return value is an array with the following structure:\n * [\n * 'companies' => [\n * $companyCrmId => $companyId,\n * ...\n * ],\n * 'contacts' => [\n * $contactCrmId => $contactId,\n * ...\n * ],\n * 'account_id' => $accountId,\n * ]\n */\n private function prepareAssociationsForOpportunity(\n string $oppCrmId,\n array $companyAssociations,\n array $contactAssociations,\n array $associationsData\n ): array {\n $associations = [\n 'companies' => [],\n 'contacts' => [],\n 'account_id' => null, // Primary account for opportunity\n ];\n\n $oppCompanyIds = $companyAssociations[$oppCrmId] ?? [];\n foreach ($oppCompanyIds as $companyCrmId) {\n if (isset($associationsData['company_id_mappings'][$companyCrmId])) {\n $associations['companies'][$companyCrmId] = $associationsData['company_id_mappings'][$companyCrmId];\n\n // Set primary account (first company becomes primary account)\n if ($associations['account_id'] === null) {\n $associations['account_id'] = $associationsData['company_id_mappings'][$companyCrmId];\n }\n }\n }\n\n $oppContactIds = $contactAssociations[$oppCrmId] ?? [];\n foreach ($oppContactIds as $contactCrmId) {\n if (isset($associationsData['contact_id_mappings'][$contactCrmId])) {\n $associations['contacts'][$contactCrmId] = $associationsData['contact_id_mappings'][$contactCrmId];\n }\n }\n\n return $associations;\n }\n\n /**\n * Update only associations for an opportunity\n */\n private function updateOpportunityAssociations(Opportunity $opportunity, array $associations): void\n {\n // Update contact associations\n $this->importOpportunityContacts($opportunity, $associations['contacts']);\n\n // Update company (account) associations\n $this->updateOpportunityAccount($opportunity, $associations['account_id']);\n }\n\n /**\n * Remove all contact associations from an opportunity\n */\n private function removeAllOpportunityContacts(Opportunity $opportunity): void\n {\n $currentCount = (int) $opportunity->contacts()->count();\n\n if ($currentCount > 0) {\n $opportunity->contacts()->detach();\n\n $this->logger->info('[' . $this->getDisplayName() . '] Removed all contact associations', [\n 'opportunity_id' => $opportunity->getId(),\n 'removed_count' => $currentCount,\n ]);\n }\n }\n\n private function updateOpportunityAccount(Opportunity $opportunity, ?int $accountId): void\n {\n if ($accountId === null) {\n // No account ID provided - keep current account\n return;\n }\n\n $currentAccountId = $opportunity->getAccountId();\n\n // Only update if account has changed\n if ($currentAccountId !== $accountId) {\n $opportunity->account_id = $accountId;\n $opportunity->save();\n\n $this->logger->info('[' . $this->getDisplayName() . '] Updated opportunity account association', [\n 'opportunity_id' => $opportunity->getId(),\n 'old_account_id' => $currentAccountId,\n 'new_account_id' => $accountId,\n ]);\n }\n }\n\n /**\n * Find existing opportunities by external IDs (OPTIMIZED VERSION)\n * Uses batch query for better performance\n */\n private function findExistingOpportunities(array $crmIds): Collection\n {\n return $this->crmEntityRepository\n ->findOpportunitiesByExternalIds($this->config, $crmIds);\n }\n\n private function processOpportunityBatch(array $opportunities): int\n {\n $syncedOpportunities = $this->importOpportunityBatch($opportunities);\n\n return count($syncedOpportunities['success'] ?? []);\n }\n\n /**\n * Convert single deal associations from HubSpot format to internal format\n * Handles both HubSpot SDK objects and array formats\n *\n * @param array $opportunityAssociations Raw associations from HubSpot API or pre-processed\n *\n * @return array Processed associations with DB IDs\n */\n private function convertDealAssociations(array $opportunityAssociations): array\n {\n $associations = $this->initializeAssociationsStructure();\n\n if (empty($opportunityAssociations)) {\n return $associations;\n }\n\n $associationIds = $this->extractAssociationIds($opportunityAssociations);\n\n $this->processCompanyAssociations($associationIds, $associations);\n $this->processContactAssociations($associationIds, $associations);\n\n return $associations;\n }\n\n private function initializeAssociationsStructure(): array\n {\n return [\n 'companies' => [],\n 'contacts' => [],\n 'account_id' => null, // Primary account for opportunity\n ];\n }\n\n private function extractAssociationIds(array $opportunityAssociations): array\n {\n $associationIds = [];\n\n foreach ($opportunityAssociations as $type => $associationData) {\n if (! empty($associationData)) {\n $associationIds[$type] = $this->convertSingleDealAssociations($associationData);\n }\n }\n\n return $associationIds;\n }\n\n private function processCompanyAssociations(array $associationIds, array &$associations): void\n {\n if (empty($associationIds['companies'])) {\n return;\n }\n\n $companyId = $associationIds['companies'][0];\n $account = $this->findOrSyncAccount($companyId);\n\n if ($account instanceof Account) {\n $associations['companies'][$companyId] = $account->getId();\n $associations['account_id'] = $account->getId();\n }\n }\n\n private function processContactAssociations(array $associationIds, array &$associations): void\n {\n if (empty($associationIds['contacts'])) {\n return;\n }\n\n foreach ($associationIds['contacts'] as $contactId) {\n $contact = $this->findOrSyncContact($contactId);\n\n if ($contact instanceof Contact) {\n $associations['contacts'][$contactId] = $contact->getId();\n }\n }\n }\n\n private function findOrSyncAccount(string $companyId): ?Account\n {\n $account = $this->crmEntityRepository->findAccountByExternalId($this->config, $companyId);\n\n if (! $account instanceof Account) {\n $account = $this->syncAccount($companyId);\n }\n\n return $account;\n }\n\n private function findOrSyncContact(string $contactId): ?Contact\n {\n $contact = $this->crmEntityRepository->findContactByExternalId($this->config, $contactId);\n\n if (! $contact instanceof Contact) {\n $contact = $this->syncContact($contactId);\n }\n\n return $contact;\n }\n\n private function convertSingleDealAssociations($opportunityAssociations = null): array\n {\n $associationData = [];\n\n if ($opportunityAssociations === null) {\n return $associationData;\n }\n\n // Handle array input (from extractAssociationIds)\n if (is_array($opportunityAssociations)) {\n return $opportunityAssociations;\n }\n\n // Handle CollectionResponseAssociatedId object\n if ($opportunityAssociations instanceof CollectionResponseAssociatedId) {\n foreach ($opportunityAssociations->getResults() as $association) {\n $associationData[] = $association->getId();\n }\n }\n\n return $associationData;\n }\n\n private function importOrUpdateOpportunity($crmData, ?bool $exists = null): ?Opportunity\n {\n if (empty($crmData['properties'])) {\n return null;\n }\n\n $crmId = (string) $crmData['id'];\n $properties = $crmData['properties'];\n $associations = $crmData['associations'] ?? [];\n\n $opportunityExists = $exists ?? (bool) $this->crmEntityRepository->findOpportunityByExternalId(\n $this->config,\n $crmId\n );\n\n if ($opportunityExists) {\n return $this->updateOpportunity($crmId, $properties, $associations);\n }\n\n return $this->createOpportunity($crmId, $properties, $associations);\n }\n\n /**\n * Create new opportunity\n */\n private function createOpportunity(string $crmId, array $properties, array $associations): ?Opportunity\n {\n $accountId = $this->resolveAccountId($associations);\n if (! $accountId) {\n return null;\n }\n\n $businessProcess = $this->resolveBusinessProcess($properties['pipeline'] ?? null);\n if (! $businessProcess) {\n return null;\n }\n\n $stage = $this->resolveStage($businessProcess, $properties['dealstage'] ?? null);\n if (! $stage) {\n return null;\n }\n\n $data = $this->buildOpportunityData($properties, $accountId, $businessProcess, $stage);\n\n $attributes = [\n 'crm_configuration_id' => $this->config->getId(),\n 'crm_provider_id' => $crmId,\n ];\n\n $values = array_merge($attributes, $data);\n\n $opportunity = $this->crmEntityRepository->upsertOpportunity($attributes, $values);\n\n $this->importExternalFieldData($properties, $opportunity->getId());\n $this->importOpportunityContacts($opportunity, $associations['contacts']);\n\n if ($opportunity->wasRecentlyCreated) {\n MatchActivitiesToNewOpportunity::dispatch($opportunity->getId());\n }\n\n return $opportunity;\n }\n\n /**\n * Update existing opportunity\n */\n private function updateOpportunity(string $crmId, array $properties, array $associations): Opportunity\n {\n $accountId = $this->resolveAccountId($associations);\n $businessProcess = $this->resolveBusinessProcess($properties['pipeline'] ?? null);\n $stage = $businessProcess ? $this->resolveStage($businessProcess, $properties['dealstage'] ?? null) : null;\n\n $data = $this->buildOpportunityData($properties, $accountId, $businessProcess, $stage);\n\n $attributes = [\n 'crm_configuration_id' => $this->config->getId(),\n 'crm_provider_id' => $crmId,\n ];\n\n $values = array_merge($attributes, $data);\n $opportunity = $this->crmEntityRepository->upsertOpportunity($attributes, $values);\n\n $this->importExternalFieldData($properties, $opportunity->getId());\n $this->updateOpportunityAssociations($opportunity, $associations);\n\n return $opportunity;\n }\n\n private function resolveAccountId(array $associations): ?int\n {\n if (! empty($associations['account_id'])) {\n return $associations['account_id'];\n }\n\n if (empty($associations)) {\n return null;\n }\n\n // Fallback: use first company as account (currently SDK returns one company)\n foreach ($associations['companies'] as $accountId) {\n return $accountId;\n }\n\n return null;\n }\n\n private function buildOpportunityData(\n array $properties,\n ?int $accountId,\n ?BusinessProcess $businessProcess,\n ?Stage $stage\n ): array {\n $ownerId = null;\n $profile = null;\n if (! empty($properties['hubspot_owner_id'])) {\n $ownerId = $properties['hubspot_owner_id'];\n $profile = $this->crmEntityRepository->findProfileByExternalId($this->config, (string) $ownerId);\n }\n\n $name = 'Unknown';\n if (isset($properties['dealname'])) {\n $name = mb_strimwidth($properties['dealname'], 0, 128);\n }\n\n $amount = $this->resolveAmount($properties);\n $currency = $properties['deal_currency_code'] ?? null;\n\n $closeDate = null;\n if (! empty($properties['closedate'])) {\n $closeDate = Carbon::parse($properties['closedate'])->format('Y-m-d');\n }\n\n $remotelyCreatedAt = null;\n if (! empty($properties['createdate']) && strtotime($properties['createdate'])) {\n $date = $this->parseCleanDatetime($properties['createdate']);\n $remotelyCreatedAt = $date?->format('Y-m-d H:i:s');\n }\n\n $closedStages = $this->getClosedDealStages();\n $isWon = in_array($properties['dealstage'], $closedStages['won']);\n $isLost = in_array($properties['dealstage'], $closedStages['lost']);\n\n $data = [\n 'team_id' => $this->team->getId(),\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $ownerId,\n 'name' => $name,\n 'value' => ! empty($amount) ? $amount : null,\n 'currency_code' => CurrencyFormatter::formatCode($currency),\n 'close_date' => $closeDate,\n 'is_closed' => $isWon || $isLost,\n 'is_won' => $isWon,\n 'remotely_created_at' => $remotelyCreatedAt,\n 'probability' => $this->resolveDealProbability($properties['hs_deal_stage_probability']),\n 'forecast_category' => $this->resolveForecastCategory($properties['hs_manual_forecast_category']),\n ];\n\n if ($accountId) {\n $data['account_id'] = $accountId;\n }\n\n if ($stage) {\n $data['stage_id'] = $stage->id;\n }\n\n if ($businessProcess) {\n $recordType = $this->crmEntityRepository->getBusinessProcessRecordType($businessProcess);\n if ($recordType) {\n $data['record_type_id'] = $recordType->id;\n }\n }\n\n return $data;\n }\n\n private function resolveBusinessProcess(?string $pipelineId): ?BusinessProcess\n {\n if ($pipelineId === null) {\n return null;\n }\n\n $cacheKey = $this->getBusinessProcessCacheKey($pipelineId);\n if (isset($this->cachedBusinessProcesses[$cacheKey])) {\n return $this->cachedBusinessProcesses[$cacheKey];\n }\n\n $businessProcess = $this->getBusinessProcess($pipelineId);\n\n if (! $businessProcess instanceof BusinessProcess) {\n $this->importStages();\n $businessProcess = $this->getBusinessProcess($pipelineId);\n }\n\n if (! $businessProcess instanceof BusinessProcess) {\n $this->logger->info(\n '[HubSpot] Deal is not attached to a pipeline',\n [\n 'pipeline' => $pipelineId]\n );\n }\n\n $this->cachedBusinessProcesses[$cacheKey] = $businessProcess;\n\n return $businessProcess;\n }\n\n private function getBusinessProcess(string $pipelineId): ?BusinessProcess\n {\n return $this->crmEntityRepository->findBusinessProcessesByExternalId($this->config, $pipelineId);\n }\n\n private function getBusinessProcessCacheKey(string $pipelineId): string\n {\n return $this->config->getId() . '_' . $pipelineId;\n }\n\n private function resolveStage(BusinessProcess $businessProcess, ?string $stageId): ?Stage\n {\n if (empty($stageId)) {\n return null;\n }\n\n $cacheKey = $businessProcess->getId() . ':' . $stageId;\n if (isset($this->cachedStages[$cacheKey])) {\n return $this->cachedStages[$cacheKey];\n }\n\n $stage = $this->crmEntityRepository->getPipelineStageByConditions(\n $businessProcess,\n [\n 'crm_provider_id' => $stageId,\n 'type' => Stage::TYPE_OPPORTUNITY,\n ]\n );\n\n if ($stage === null) {\n $this->importStages(null, $stageId);\n }\n\n if ($stage === null) {\n $this->logger->info('[HubSpot] Stage does not exist => ' . $stageId);\n }\n\n $this->cachedStages[$cacheKey] = $stage;\n\n return $stage;\n }\n\n private function resolveAmount(array $properties): ?string\n {\n $amount = null;\n if (! empty($properties['amount'])) {\n $amount = str_replace(',', '', $properties['amount']);\n }\n\n if ($this->config->hasDefaultCurrencyFieldSet()) {\n $valueFieldName = $this->config->getDefaultCurrencyField()->getCrmProviderId();\n $amount = $properties[$valueFieldName] ?? $amount;\n }\n\n return $amount;\n }\n\n private function parseCleanDatetime(string $datetime): ?Carbon\n {\n // Treat pre-1980 values as invalid\n $minValidDate = Carbon::parse('1980-01-01 00:00:00');\n\n try {\n $date = Carbon::parse($datetime);\n\n if ($minValidDate->gt($date)) {\n return null;\n }\n\n return $date;\n } catch (Exception) {\n return null; // On parse error, treat as null\n }\n }\n\n private function resolveDealProbability(?string $stageProbability): int\n {\n if ($stageProbability === null) {\n return 0;\n }\n\n $probability = (float) $stageProbability;\n\n return $probability > 1 ? 0 : (int) ($probability * 100);\n }\n\n private function resolveForecastCategory(?string $forecastCategory): string\n {\n if (! $forecastCategory) {\n return Forecast::FORECAST_CATEGORY_UNCATEGORIZED;\n }\n\n $forecastCategory = str_replace('_', ' ', $forecastCategory);\n\n return ucwords(strtolower($forecastCategory));\n }\n\n private function importExternalFieldData(array $properties, int $opportunityId): void\n {\n $crmFields = $this->getOpportunitySyncableFields();\n $this->importOpportunityCrmFieldData($properties, $crmFields, $opportunityId);\n }\n\n private function importOpportunityContacts(Opportunity $opportunity, array $associations): void\n {\n // Handle empty or missing contact associations\n if (empty($associations)) {\n // Remove all existing contact associations if none provided\n $this->removeAllOpportunityContacts($opportunity);\n\n return;\n }\n\n // Use differential sync approach for better performance and accuracy\n $this->syncOpportunityContactsDifferential($opportunity, $associations);\n }\n\n /**\n * Sync opportunity contacts using differential approach\n * This compares current vs new associations and only makes necessary changes\n */\n private function syncOpportunityContactsDifferential(Opportunity $opportunity, array $contactAssociations): void\n {\n $currentContactCrmIds = $this->getCurrentContactCrmIds($opportunity);\n $contactAssociationIds = array_keys($contactAssociations);\n\n $contactsToAdd = array_diff($contactAssociationIds, $currentContactCrmIds);\n $contactsToRemove = array_diff($currentContactCrmIds, $contactAssociationIds);\n\n if (empty($contactsToAdd) && empty($contactsToRemove)) {\n return;\n }\n\n $this->logContactAssociationChanges($opportunity, $currentContactCrmIds, $contactAssociations, $contactsToAdd, $contactsToRemove);\n\n $this->removeContactAssociations($opportunity, $contactsToRemove);\n $this->addContactAssociations($opportunity, $contactsToAdd, $contactAssociations);\n }\n\n private function getCurrentContactCrmIds(Opportunity $opportunity): array\n {\n return $opportunity->contacts()\n ->pluck('contacts.crm_provider_id')\n ->toArray();\n }\n\n private function logContactAssociationChanges(\n Opportunity $opportunity,\n array $currentContactCrmIds,\n array $contactAssociations,\n array $contactsToAdd,\n array $contactsToRemove\n ): void {\n $this->logger->info('[' . $this->getDisplayName() . '] Contact association changes', [\n 'opportunity_id' => $opportunity->getId(),\n 'current_contacts' => $currentContactCrmIds,\n 'new_contacts' => $contactAssociations,\n 'contacts_to_add' => $contactsToAdd,\n 'contacts_to_remove' => $contactsToRemove,\n ]);\n }\n\n private function removeContactAssociations(Opportunity $opportunity, array $contactsToRemove): void\n {\n if (empty($contactsToRemove)) {\n return;\n }\n\n $contactsToDetach = $opportunity->contacts()\n ->whereIn('contacts.crm_provider_id', $contactsToRemove)\n ->pluck('contacts.id')\n ->toArray();\n\n if (! empty($contactsToDetach)) {\n $opportunity->contacts()->detach($contactsToDetach);\n\n $this->logger->info('[' . $this->getDisplayName() . '] Removed contact associations', [\n 'opportunity_id' => $opportunity->getId(),\n 'removed_contact_crm_ids' => $contactsToRemove,\n 'removed_contact_count' => count($contactsToDetach),\n ]);\n }\n }\n\n private function addContactAssociations(Opportunity $opportunity, array $contactsToAdd, array $contactAssociations): void\n {\n if (empty($contactsToAdd)) {\n return;\n }\n\n $contactsAdded = [];\n foreach ($contactsToAdd as $crmId) {\n $id = $contactAssociations[$crmId];\n\n if ($this->attachSingleContact($opportunity, (string) $crmId, $id)) {\n $contactsAdded[] = $crmId;\n }\n }\n\n $this->logAddedContacts($opportunity, $contactsAdded);\n }\n\n private function attachSingleContact(Opportunity $opportunity, string $crmId, int $id): bool\n {\n try {\n $contact = $this->crmEntityRepository->findContactByConfigurationAndId($this->config, $id);\n\n if (! $contact) {\n return false;\n }\n\n return $this->performContactAttachment($opportunity, $contact, $crmId);\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Failed to add contact association', [\n 'opportunity_id' => $opportunity->getId(),\n 'contact_crm_id' => $crmId,\n 'error' => $e->getMessage(),\n ]);\n\n return false;\n }\n }\n\n private function performContactAttachment(Opportunity $opportunity, Contact $contact, string $crmId): bool\n {\n try {\n $opportunity->contacts()->attach($contact->getId(), [\n 'crm_provider_id' => $crmId,\n ]);\n\n return true;\n } catch (\\Illuminate\\Database\\QueryException $e) {\n if (str_contains($e->getMessage(), 'Duplicate entry')) {\n $this->logger->info('[' . $this->getDisplayName() . '] Contact association already exists', [\n 'contact_id' => $contact->getId(),\n 'contact_crm_id' => $crmId,\n 'opportunity_id' => $opportunity->getId(),\n ]);\n\n return false;\n }\n\n throw $e;\n }\n }\n\n private function logAddedContacts(Opportunity $opportunity, array $contactsAdded): void\n {\n if (! empty($contactsAdded)) {\n $this->logger->info('[' . $this->getDisplayName() . '] Added contact associations', [\n 'opportunity_id' => $opportunity->getId(),\n 'added_contact_crm_ids' => $contactsAdded,\n 'added_contacts_count' => count($contactsAdded),\n ]);\n }\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Crm\\Hubspot\\ServiceTraits;\n\nuse Carbon\\Carbon;\nuse HubSpot\\Client\\Crm\\Deals\\Model\\CollectionResponseAssociatedId;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Models\\Account;\nuse Exception;\nuse Jiminny\\Component\\DealInsights\\Forecast\\Forecast;\nuse Jiminny\\Jobs\\Crm\\MatchActivitiesToNewOpportunity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Models\\Opportunity;\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Services\\Crm\\Hubspot\\DealFieldsService;\nuse Jiminny\\Services\\Crm\\Hubspot\\OpportunitySyncStrategy\\HubspotSingleSyncStrategy;\nuse Jiminny\\Services\\Crm\\Hubspot\\WebhookSyncBatchProcessor;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Utils\\CurrencyFormatter;\n\n/**\n * Optimized sync methods for better performance\n * These methods can be integrated into SyncCrmEntitiesTrait for significant performance gains\n */\ntrait OpportunitySyncTrait\n{\n private const int BATCH_SIZE = 100;\n private const int BATCH_PROCESS_SIZE = 800;\n\n protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;\n protected CrmEntityRepository $crmEntityRepository;\n protected DealFieldsService $dealFieldsService;\n\n private ?array $cachedClosedDealStages = null;\n private array $cachedBusinessProcesses = [];\n private array $cachedStages = [];\n\n public function syncOpportunities(array $parameters, ?string $strategy = null): int\n {\n $startTime = microtime(true);\n $strategies = $this->opportunitySyncStrategyResolver->getStrategies($this->config, $strategy);\n $parameters['config'] = $this->config;\n $syncCount = 0;\n $reportedTotal = 0;\n $lastSyncedId = [];\n $strategyNames = [];\n\n try {\n foreach ($strategies as $strategyName => $syncStrategy) {\n $strategyNames[] = $strategyName;\n $this->logger->info(\n '[' . $this->getDisplayName() . '] Syncing opportunities using strategy: ' . $strategyName,\n ['team' => $this->team->getId()]\n );\n\n $total = 0;\n $lastId = null;\n $buffer = [];\n\n // HubspotWebhookBatchSyncStrategy returns empty generator, this is for other strategies\n foreach ($syncStrategy->fetchOpportunities($parameters, $total, $lastId) as $hsOpportunity) {\n $buffer[] = $hsOpportunity;\n\n // process every 800 rows (fits < 1 000 association limit)\n if (\\count($buffer) >= self::BATCH_PROCESS_SIZE) {\n $syncCount += $this->processOpportunityBatch($buffer);\n $buffer = [];\n }\n }\n\n // leftovers\n if ($buffer) {\n $syncCount += $this->processOpportunityBatch($buffer);\n }\n\n $reportedTotal += $total;\n $lastSyncedId = $lastId;\n }\n } catch (\\HubSpot\\Client\\Crm\\Deals\\ApiException | CrmException $e) {\n $this->handleSyncException($e, $parameters);\n }\n\n $durationMs = round((microtime(true) - $startTime) * 1000, 2);\n $this->logger->info(\n '[HubSpot] Synced opportunities',\n [\n 'team' => $this->team->getId(),\n 'strategies' => implode(',', $strategyNames),\n 'sync_count' => $syncCount,\n 'total' => $reportedTotal,\n 'last_synced_id' => $lastSyncedId,\n 'duration_ms' => $durationMs,\n ]\n );\n\n return $reportedTotal;\n }\n\n private function handleSyncException(\\Throwable $e, array $parameters): void\n {\n if (($parameters['since'] ?? null) instanceof Carbon) {\n $parameters['since'] = $parameters['since']->toDateTimeString();\n }\n $parameters['config'] = $this->config->getId();\n\n $this->logger->warning('[' . $this->getDisplayName() . '] Sync opportunities failed', [\n 'teamId' => $this->team->getUuid(),\n 'parameters' => $parameters,\n 'reason' => $e->getMessage(),\n ]);\n }\n\n /**\n * @inheritdoc\n */\n public function syncOpportunity(string $crmId): ?Opportunity\n {\n $strategy = $this->opportunitySyncStrategyResolver->resolve(\n $this->config,\n OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY,\n );\n\n $parameters = [\n 'config' => $this->config,\n 'crm_id' => $crmId,\n ];\n\n try {\n if (! $strategy instanceof HubspotSingleSyncStrategy) {\n throw new InvalidArgumentException('Strategy must by HubspotSingleSyncStrategy');\n }\n\n $hsOpportunity = $strategy->fetchOpportunity($parameters);\n } catch (\\HubSpot\\Client\\Crm\\Deals\\ApiException $e) {\n $this->logger->info('[' . $this->getDisplayName() . '] Opportunity not found', [\n 'teamId' => $this->team->getUuid(),\n 'crmId' => $crmId,\n 'reason' => $e->getMessage(),\n ]);\n\n return null;\n }\n\n $hsOpportunity['associations'] = $this->convertDealAssociations($hsOpportunity['associations'] ?? []);\n\n return $this->importOrUpdateOpportunity($hsOpportunity);\n }\n\n /**\n * Process webhook-collected opportunity batches.\n *\n * Drains Redis sets containing company CRM IDs collected from webhook events\n * and dispatches ImportOpportunityBatch jobs for batch processing.\n *\n * @return int Number of opportunity IDs dispatched to jobs\n */\n public function batchSyncOpportunities(): int\n {\n $configId = $this->team->getCrmConfiguration()->getId();\n\n return $this->batchProcessor->processBatchesForObjectType(\n WebhookSyncBatchProcessor::OBJECT_TYPE_DEAL,\n $configId\n );\n }\n\n /**\n * Import a batch of opportunities by their CRM IDs.\n * Fetches opportunity data from HubSpot API and delegates to importOpportunityBatch().\n *\n * @param array<string> $crmIds HubSpot deal CRM IDs\n *\n * @return array{success: array, failed_ids: array, errors?: array<string, string>}\n */\n public function importOpportunityBatchByIds(array $crmIds): array\n {\n $fields = $this->dealFieldsService->getFieldsForConfiguration($this->config);\n\n $allDeals = [];\n foreach (array_chunk($crmIds, self::BATCH_SIZE) as $chunk) {\n $deals = $this->client->getOpportunitiesByIds($chunk, $fields);\n foreach ($deals as $deal) {\n $allDeals[] = $deal;\n }\n }\n\n // IDs not returned by HubSpot are likely deleted or inaccessible deals.\n // These are not failures — retrying won't bring them back.\n $fetchedIds = array_map('strval', array_column($allDeals, 'id'));\n $notFoundIds = array_values(array_diff(array_map('strval', $crmIds), $fetchedIds));\n\n if (! empty($notFoundIds)) {\n $this->logger->info('[' . $this->getDisplayName() . '] CRM IDs not found in HubSpot (likely deleted)', [\n 'teamId' => $this->team->getId(),\n 'notFoundCount' => \\count($notFoundIds),\n 'notFoundIds' => $notFoundIds,\n 'requestedCount' => \\count($crmIds),\n 'fetchedCount' => \\count($allDeals),\n ]);\n }\n\n if (empty($allDeals)) {\n return ['success' => [], 'failed_ids' => []];\n }\n\n return $this->importOpportunityBatch($allDeals);\n }\n\n private function getClosedDealStages(): array\n {\n if ($this->cachedClosedDealStages !== null) {\n return $this->cachedClosedDealStages;\n }\n\n $stages = $this->crmEntityRepository->getOpportunityClosedStages($this->config);\n $data = [\n 'lost' => [],\n 'won' => [],\n ];\n\n foreach ($stages as $stage) {\n if ($stage->probability == 0.00) {\n $data['lost'][] = $stage->crm_provider_id;\n }\n if ($stage->probability == 100.00) {\n $data['won'][] = $stage->crm_provider_id;\n }\n }\n\n $this->cachedClosedDealStages = $data;\n\n return $data;\n }\n\n /**\n * Import deals into the database with pre-fetched associations.\n *\n * API calls here (getAssociationsData, getExistingOpportunityCrmIds) are NOT\n * caught — if they throw, the exception propagates to ImportOpportunityBatch::handle()\n * where Laravel retries the whole job with backoff. After all retries exhausted,\n * failed() requeues all IDs to Redis.\n *\n * The per-deal loop catches exceptions individually. A deal can end up in three states:\n * - success: imported/updated successfully\n * - failed_ids: exception thrown (DB constraint violation, corrupt data, etc.)\n * These are permanent issues — retrying won't fix them.\n * - skipped (null): missing dependencies (no account, unknown pipeline/stage).\n * This is acceptable — the deal cannot be imported until those exist.\n */\n private function importOpportunityBatch(array $deals): array\n {\n $syncedOpportunities = [\n 'success' => [],\n 'failed_ids' => [],\n ];\n $dealIds = array_column($deals, 'id');\n\n // Shared association/existing-ID preparation is batch-level state. If it fails, rethrow so the\n // queue job retries the whole batch and eventually requeues all deal IDs back to Redis.\n try {\n $companyAssociations = $this->client->getAssociationsData($dealIds, 'deals', 'companies');\n $contactAssociations = $this->client->getAssociationsData($dealIds, 'deals', 'contacts');\n\n $associationsData = $this->prepareAssociatedEntities($companyAssociations, $contactAssociations);\n\n $existingCrmIds = $this->crmEntityRepository->getExistingOpportunityCrmIds(\n $this->config,\n array_map('strval', $dealIds)\n );\n $existingCrmIdSet = array_flip($existingCrmIds);\n } catch (\\Throwable $e) {\n $this->logger->error('[' . $this->getDisplayName() . '] Failed to fetch associations or existing IDs', [\n 'teamId' => $this->team->getId(),\n 'dealCount' => count($dealIds),\n 'error' => $e->getMessage(),\n ]);\n\n throw $e;\n }\n\n foreach ($deals as $deal) {\n try {\n $deal['associations'] = $this->prepareAssociationsForOpportunity(\n $deal['id'],\n $companyAssociations,\n $contactAssociations,\n $associationsData\n );\n\n $syncedOpportunity = $this->importOrUpdateOpportunity(\n $deal,\n isset($existingCrmIdSet[(string) $deal['id']])\n );\n if ($syncedOpportunity) {\n $syncedOpportunities['success'][] = $syncedOpportunity;\n }\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Failed to import opportunity', [\n 'teamId' => $this->team->getId(),\n 'crmId' => $deal['id'],\n 'error' => $e->getMessage(),\n ]);\n $syncedOpportunities['failed_ids'][] = $deal['id'];\n $syncedOpportunities['errors'][$deal['id']] = $e->getMessage();\n }\n }\n\n return $syncedOpportunities;\n }\n\n /**\n * Prepare associated entities for opportunities with optimized batch processing\n * Returns structured data with CRM ID to DB ID mappings for each opportunity\n */\n private function prepareAssociatedEntities(array $companyAssociations, array $contactAssociations): array\n {\n // Step 1: Collect all unique company and contact IDs from associations\n $allCompanyIds = $this->flattenAssociationIds($companyAssociations);\n $allContactIds = $this->flattenAssociationIds($contactAssociations);\n\n // Step 2: Batch sync missing entities and get CRM ID to DB ID mappings\n $companyIdMappings = [];\n $contactIdMappings = [];\n\n if (! empty($allCompanyIds)) {\n $companyIdMappings = $this->prepareAssociatedAccounts($allCompanyIds);\n }\n\n if (! empty($allContactIds)) {\n $contactIdMappings = $this->prepareAssociatedContacts($allContactIds);\n }\n\n return [\n 'company_id_mappings' => $companyIdMappings,\n 'contact_id_mappings' => $contactIdMappings,\n ];\n }\n\n /**\n * Flatten association data to get unique IDs\n */\n private function flattenAssociationIds(array $associations): array\n {\n $ids = [];\n foreach ($associations as $dealAssociations) {\n if (is_array($dealAssociations)) {\n foreach ($dealAssociations as $id) {\n $ids[$id] = true;\n }\n }\n }\n\n return array_keys($ids);\n }\n\n /**\n * Batch sync missing accounts\n */\n private function prepareAssociatedAccounts(array $companyIds): array\n {\n // Find which accounts already exist\n $existingAccounts = $this->crmEntityRepository\n ->findAccountsByExternalIds($this->config, $companyIds);\n\n $existingCompanyIds = $existingAccounts->pluck('crm_provider_id')->toArray();\n\n $existingAccountsData = $existingAccounts->mapWithKeys(function ($account) {\n return [$account->getCrmProviderId() => $account->getId()];\n })->toArray();\n\n $missingCompanyIds = array_diff($companyIds, $existingCompanyIds);\n\n if (empty($missingCompanyIds)) {\n return $existingAccountsData;\n }\n\n $this->logger->info('[' . $this->getDisplayName() . '] Batch syncing missing accounts', [\n 'teamId' => $this->team->getUuid(),\n 'total_companies' => count($companyIds),\n 'existing_companies' => count($existingCompanyIds),\n 'missing_companies' => count($missingCompanyIds),\n ]);\n\n // we already have limit on opportunity ids count\n // Initialize variable before try block\n $syncedAccountsData = [];\n\n try {\n $syncedAccountsData = $this->batchSyncCrmObjects('companies', $missingCompanyIds);\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Failed to sync missing accounts', [\n 'size' => count($missingCompanyIds),\n 'error' => $e->getMessage(),\n ]);\n $syncedAccountsData = [];\n }\n\n return $existingAccountsData + $syncedAccountsData;\n }\n\n /**\n * Prepare associated contacts - find existing and sync missing ones\n * Returns mapping of CRM ID to DB ID\n */\n private function prepareAssociatedContacts(array $contactIds): array\n {\n // Find which contacts already exist\n $existingContacts = $this->crmEntityRepository\n ->findContactsByExternalIds($this->config, $contactIds);\n\n $existingContactIds = $existingContacts->pluck('crm_provider_id')->toArray();\n\n // Create mapping for existing contacts\n $existingContactsData = $existingContacts->mapWithKeys(function ($contact) {\n return [$contact->getCrmProviderId() => $contact->getId()];\n })->toArray();\n\n $missingContactIds = array_diff($contactIds, $existingContactIds);\n\n if (empty($missingContactIds)) {\n return $existingContactsData;\n }\n\n $this->logger->info('[' . $this->getDisplayName() . '] Batch syncing missing contacts', [\n 'teamId' => $this->team->getUuid(),\n 'total_contacts' => count($contactIds),\n 'existing_contacts' => count($existingContactIds),\n 'missing_contacts' => count($missingContactIds),\n ]);\n\n // Sync missing contacts using batch API\n try {\n $syncedContactsData = $this->batchSyncCrmObjects('contacts', $missingContactIds);\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Failed to sync missing contacts', [\n 'size' => count($missingContactIds),\n 'error' => $e->getMessage(),\n ]);\n $syncedContactsData = [];\n }\n\n return $existingContactsData + $syncedContactsData;\n }\n\n private function batchSyncCrmObjects(string $objectType, array $crmIds): array\n {\n $syncObjects = [];\n $crmObjectIds = array_values($crmIds);\n\n foreach (array_chunk($crmObjectIds, self::BATCH_SIZE) as $chunk) {\n try {\n $objects = $objectType === 'companies' ?\n $this->client->getCompaniesByIds($chunk, $this->getCompanyFields()) :\n $this->client->getContactsByIds($chunk, $this->getContactFields());\n\n foreach ($objects as $objectId => $objectData) {\n $this->importCrmObject($objectType, (string) $objectId, $objectData, $syncObjects);\n }\n\n $this->logger->info('[' . $this->getDisplayName() . '] Batch synced ' . $objectType, [\n 'requested_count' => count($chunk),\n 'synced_count' => count($objects),\n ]);\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Batch ' . $objectType . ' sync failed', [\n 'ids' => $chunk,\n 'error' => $e->getMessage(),\n ]);\n }\n }\n\n return $syncObjects;\n }\n\n private function importCrmObject(string $objectType, string $objectId, mixed $objectData, array &$syncObjects): void\n {\n try {\n $object = $objectType === 'companies' ?\n $this->importAccount($objectData) :\n $this->importContact($objectData);\n\n if ($object) {\n $syncObjects[$object->getCrmProviderId()] = $object->getId();\n }\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Failed to import batch ' . $objectType, [\n 'id' => $objectId,\n 'error' => $e->getMessage(),\n ]);\n }\n }\n\n /**\n * Prepare associations for a single opportunity\n *\n * The return value is an array with the following structure:\n * [\n * 'companies' => [\n * $companyCrmId => $companyId,\n * ...\n * ],\n * 'contacts' => [\n * $contactCrmId => $contactId,\n * ...\n * ],\n * 'account_id' => $accountId,\n * ]\n */\n private function prepareAssociationsForOpportunity(\n string $oppCrmId,\n array $companyAssociations,\n array $contactAssociations,\n array $associationsData\n ): array {\n $associations = [\n 'companies' => [],\n 'contacts' => [],\n 'account_id' => null, // Primary account for opportunity\n ];\n\n $oppCompanyIds = $companyAssociations[$oppCrmId] ?? [];\n foreach ($oppCompanyIds as $companyCrmId) {\n if (isset($associationsData['company_id_mappings'][$companyCrmId])) {\n $associations['companies'][$companyCrmId] = $associationsData['company_id_mappings'][$companyCrmId];\n\n // Set primary account (first company becomes primary account)\n if ($associations['account_id'] === null) {\n $associations['account_id'] = $associationsData['company_id_mappings'][$companyCrmId];\n }\n }\n }\n\n $oppContactIds = $contactAssociations[$oppCrmId] ?? [];\n foreach ($oppContactIds as $contactCrmId) {\n if (isset($associationsData['contact_id_mappings'][$contactCrmId])) {\n $associations['contacts'][$contactCrmId] = $associationsData['contact_id_mappings'][$contactCrmId];\n }\n }\n\n return $associations;\n }\n\n /**\n * Update only associations for an opportunity\n */\n private function updateOpportunityAssociations(Opportunity $opportunity, array $associations): void\n {\n // Update contact associations\n $this->importOpportunityContacts($opportunity, $associations['contacts']);\n\n // Update company (account) associations\n $this->updateOpportunityAccount($opportunity, $associations['account_id']);\n }\n\n /**\n * Remove all contact associations from an opportunity\n */\n private function removeAllOpportunityContacts(Opportunity $opportunity): void\n {\n $currentCount = (int) $opportunity->contacts()->count();\n\n if ($currentCount > 0) {\n $opportunity->contacts()->detach();\n\n $this->logger->info('[' . $this->getDisplayName() . '] Removed all contact associations', [\n 'opportunity_id' => $opportunity->getId(),\n 'removed_count' => $currentCount,\n ]);\n }\n }\n\n private function updateOpportunityAccount(Opportunity $opportunity, ?int $accountId): void\n {\n if ($accountId === null) {\n // No account ID provided - keep current account\n return;\n }\n\n $currentAccountId = $opportunity->getAccountId();\n\n // Only update if account has changed\n if ($currentAccountId !== $accountId) {\n $opportunity->account_id = $accountId;\n $opportunity->save();\n\n $this->logger->info('[' . $this->getDisplayName() . '] Updated opportunity account association', [\n 'opportunity_id' => $opportunity->getId(),\n 'old_account_id' => $currentAccountId,\n 'new_account_id' => $accountId,\n ]);\n }\n }\n\n /**\n * Find existing opportunities by external IDs (OPTIMIZED VERSION)\n * Uses batch query for better performance\n */\n private function findExistingOpportunities(array $crmIds): Collection\n {\n return $this->crmEntityRepository\n ->findOpportunitiesByExternalIds($this->config, $crmIds);\n }\n\n private function processOpportunityBatch(array $opportunities): int\n {\n $syncedOpportunities = $this->importOpportunityBatch($opportunities);\n\n return count($syncedOpportunities['success'] ?? []);\n }\n\n /**\n * Convert single deal associations from HubSpot format to internal format\n * Handles both HubSpot SDK objects and array formats\n *\n * @param array $opportunityAssociations Raw associations from HubSpot API or pre-processed\n *\n * @return array Processed associations with DB IDs\n */\n private function convertDealAssociations(array $opportunityAssociations): array\n {\n $associations = $this->initializeAssociationsStructure();\n\n if (empty($opportunityAssociations)) {\n return $associations;\n }\n\n $associationIds = $this->extractAssociationIds($opportunityAssociations);\n\n $this->processCompanyAssociations($associationIds, $associations);\n $this->processContactAssociations($associationIds, $associations);\n\n return $associations;\n }\n\n private function initializeAssociationsStructure(): array\n {\n return [\n 'companies' => [],\n 'contacts' => [],\n 'account_id' => null, // Primary account for opportunity\n ];\n }\n\n private function extractAssociationIds(array $opportunityAssociations): array\n {\n $associationIds = [];\n\n foreach ($opportunityAssociations as $type => $associationData) {\n if (! empty($associationData)) {\n $associationIds[$type] = $this->convertSingleDealAssociations($associationData);\n }\n }\n\n return $associationIds;\n }\n\n private function processCompanyAssociations(array $associationIds, array &$associations): void\n {\n if (empty($associationIds['companies'])) {\n return;\n }\n\n $companyId = $associationIds['companies'][0];\n $account = $this->findOrSyncAccount($companyId);\n\n if ($account instanceof Account) {\n $associations['companies'][$companyId] = $account->getId();\n $associations['account_id'] = $account->getId();\n }\n }\n\n private function processContactAssociations(array $associationIds, array &$associations): void\n {\n if (empty($associationIds['contacts'])) {\n return;\n }\n\n foreach ($associationIds['contacts'] as $contactId) {\n $contact = $this->findOrSyncContact($contactId);\n\n if ($contact instanceof Contact) {\n $associations['contacts'][$contactId] = $contact->getId();\n }\n }\n }\n\n private function findOrSyncAccount(string $companyId): ?Account\n {\n $account = $this->crmEntityRepository->findAccountByExternalId($this->config, $companyId);\n\n if (! $account instanceof Account) {\n $account = $this->syncAccount($companyId);\n }\n\n return $account;\n }\n\n private function findOrSyncContact(string $contactId): ?Contact\n {\n $contact = $this->crmEntityRepository->findContactByExternalId($this->config, $contactId);\n\n if (! $contact instanceof Contact) {\n $contact = $this->syncContact($contactId);\n }\n\n return $contact;\n }\n\n private function convertSingleDealAssociations($opportunityAssociations = null): array\n {\n $associationData = [];\n\n if ($opportunityAssociations === null) {\n return $associationData;\n }\n\n // Handle array input (from extractAssociationIds)\n if (is_array($opportunityAssociations)) {\n return $opportunityAssociations;\n }\n\n // Handle CollectionResponseAssociatedId object\n if ($opportunityAssociations instanceof CollectionResponseAssociatedId) {\n foreach ($opportunityAssociations->getResults() as $association) {\n $associationData[] = $association->getId();\n }\n }\n\n return $associationData;\n }\n\n private function importOrUpdateOpportunity($crmData, ?bool $exists = null): ?Opportunity\n {\n if (empty($crmData['properties'])) {\n return null;\n }\n\n $crmId = (string) $crmData['id'];\n $properties = $crmData['properties'];\n $associations = $crmData['associations'] ?? [];\n\n $opportunityExists = $exists ?? (bool) $this->crmEntityRepository->findOpportunityByExternalId(\n $this->config,\n $crmId\n );\n\n if ($opportunityExists) {\n return $this->updateOpportunity($crmId, $properties, $associations);\n }\n\n return $this->createOpportunity($crmId, $properties, $associations);\n }\n\n /**\n * Create new opportunity\n */\n private function createOpportunity(string $crmId, array $properties, array $associations): ?Opportunity\n {\n $accountId = $this->resolveAccountId($associations);\n if (! $accountId) {\n return null;\n }\n\n $businessProcess = $this->resolveBusinessProcess($properties['pipeline'] ?? null);\n if (! $businessProcess) {\n return null;\n }\n\n $stage = $this->resolveStage($businessProcess, $properties['dealstage'] ?? null);\n if (! $stage) {\n return null;\n }\n\n $data = $this->buildOpportunityData($properties, $accountId, $businessProcess, $stage);\n\n $attributes = [\n 'crm_configuration_id' => $this->config->getId(),\n 'crm_provider_id' => $crmId,\n ];\n\n $values = array_merge($attributes, $data);\n\n $opportunity = $this->crmEntityRepository->upsertOpportunity($attributes, $values);\n\n $this->importExternalFieldData($properties, $opportunity->getId());\n $this->importOpportunityContacts($opportunity, $associations['contacts']);\n\n if ($opportunity->wasRecentlyCreated) {\n MatchActivitiesToNewOpportunity::dispatch($opportunity->getId());\n }\n\n return $opportunity;\n }\n\n /**\n * Update existing opportunity\n */\n private function updateOpportunity(string $crmId, array $properties, array $associations): Opportunity\n {\n $accountId = $this->resolveAccountId($associations);\n $businessProcess = $this->resolveBusinessProcess($properties['pipeline'] ?? null);\n $stage = $businessProcess ? $this->resolveStage($businessProcess, $properties['dealstage'] ?? null) : null;\n\n $data = $this->buildOpportunityData($properties, $accountId, $businessProcess, $stage);\n\n $attributes = [\n 'crm_configuration_id' => $this->config->getId(),\n 'crm_provider_id' => $crmId,\n ];\n\n $values = array_merge($attributes, $data);\n $opportunity = $this->crmEntityRepository->upsertOpportunity($attributes, $values);\n\n $this->importExternalFieldData($properties, $opportunity->getId());\n $this->updateOpportunityAssociations($opportunity, $associations);\n\n return $opportunity;\n }\n\n private function resolveAccountId(array $associations): ?int\n {\n if (! empty($associations['account_id'])) {\n return $associations['account_id'];\n }\n\n if (empty($associations)) {\n return null;\n }\n\n // Fallback: use first company as account (currently SDK returns one company)\n foreach ($associations['companies'] as $accountId) {\n return $accountId;\n }\n\n return null;\n }\n\n private function buildOpportunityData(\n array $properties,\n ?int $accountId,\n ?BusinessProcess $businessProcess,\n ?Stage $stage\n ): array {\n $ownerId = null;\n $profile = null;\n if (! empty($properties['hubspot_owner_id'])) {\n $ownerId = $properties['hubspot_owner_id'];\n $profile = $this->crmEntityRepository->findProfileByExternalId($this->config, (string) $ownerId);\n }\n\n $name = 'Unknown';\n if (isset($properties['dealname'])) {\n $name = mb_strimwidth($properties['dealname'], 0, 128);\n }\n\n $amount = $this->resolveAmount($properties);\n $currency = $properties['deal_currency_code'] ?? null;\n\n $closeDate = null;\n if (! empty($properties['closedate'])) {\n $closeDate = Carbon::parse($properties['closedate'])->format('Y-m-d');\n }\n\n $remotelyCreatedAt = null;\n if (! empty($properties['createdate']) && strtotime($properties['createdate'])) {\n $date = $this->parseCleanDatetime($properties['createdate']);\n $remotelyCreatedAt = $date?->format('Y-m-d H:i:s');\n }\n\n $closedStages = $this->getClosedDealStages();\n $isWon = in_array($properties['dealstage'], $closedStages['won']);\n $isLost = in_array($properties['dealstage'], $closedStages['lost']);\n\n $data = [\n 'team_id' => $this->team->getId(),\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $ownerId,\n 'name' => $name,\n 'value' => ! empty($amount) ? $amount : null,\n 'currency_code' => CurrencyFormatter::formatCode($currency),\n 'close_date' => $closeDate,\n 'is_closed' => $isWon || $isLost,\n 'is_won' => $isWon,\n 'remotely_created_at' => $remotelyCreatedAt,\n 'probability' => $this->resolveDealProbability($properties['hs_deal_stage_probability']),\n 'forecast_category' => $this->resolveForecastCategory($properties['hs_manual_forecast_category']),\n ];\n\n if ($accountId) {\n $data['account_id'] = $accountId;\n }\n\n if ($stage) {\n $data['stage_id'] = $stage->id;\n }\n\n if ($businessProcess) {\n $recordType = $this->crmEntityRepository->getBusinessProcessRecordType($businessProcess);\n if ($recordType) {\n $data['record_type_id'] = $recordType->id;\n }\n }\n\n return $data;\n }\n\n private function resolveBusinessProcess(?string $pipelineId): ?BusinessProcess\n {\n if ($pipelineId === null) {\n return null;\n }\n\n $cacheKey = $this->getBusinessProcessCacheKey($pipelineId);\n if (isset($this->cachedBusinessProcesses[$cacheKey])) {\n return $this->cachedBusinessProcesses[$cacheKey];\n }\n\n $businessProcess = $this->getBusinessProcess($pipelineId);\n\n if (! $businessProcess instanceof BusinessProcess) {\n $this->importStages();\n $businessProcess = $this->getBusinessProcess($pipelineId);\n }\n\n if (! $businessProcess instanceof BusinessProcess) {\n $this->logger->info(\n '[HubSpot] Deal is not attached to a pipeline',\n [\n 'pipeline' => $pipelineId]\n );\n }\n\n $this->cachedBusinessProcesses[$cacheKey] = $businessProcess;\n\n return $businessProcess;\n }\n\n private function getBusinessProcess(string $pipelineId): ?BusinessProcess\n {\n return $this->crmEntityRepository->findBusinessProcessesByExternalId($this->config, $pipelineId);\n }\n\n private function getBusinessProcessCacheKey(string $pipelineId): string\n {\n return $this->config->getId() . '_' . $pipelineId;\n }\n\n private function resolveStage(BusinessProcess $businessProcess, ?string $stageId): ?Stage\n {\n if (empty($stageId)) {\n return null;\n }\n\n $cacheKey = $businessProcess->getId() . ':' . $stageId;\n if (isset($this->cachedStages[$cacheKey])) {\n return $this->cachedStages[$cacheKey];\n }\n\n $stage = $this->crmEntityRepository->getPipelineStageByConditions(\n $businessProcess,\n [\n 'crm_provider_id' => $stageId,\n 'type' => Stage::TYPE_OPPORTUNITY,\n ]\n );\n\n if ($stage === null) {\n $this->importStages(null, $stageId);\n }\n\n if ($stage === null) {\n $this->logger->info('[HubSpot] Stage does not exist => ' . $stageId);\n }\n\n $this->cachedStages[$cacheKey] = $stage;\n\n return $stage;\n }\n\n private function resolveAmount(array $properties): ?string\n {\n $amount = null;\n if (! empty($properties['amount'])) {\n $amount = str_replace(',', '', $properties['amount']);\n }\n\n if ($this->config->hasDefaultCurrencyFieldSet()) {\n $valueFieldName = $this->config->getDefaultCurrencyField()->getCrmProviderId();\n $amount = $properties[$valueFieldName] ?? $amount;\n }\n\n return $amount;\n }\n\n private function parseCleanDatetime(string $datetime): ?Carbon\n {\n // Treat pre-1980 values as invalid\n $minValidDate = Carbon::parse('1980-01-01 00:00:00');\n\n try {\n $date = Carbon::parse($datetime);\n\n if ($minValidDate->gt($date)) {\n return null;\n }\n\n return $date;\n } catch (Exception) {\n return null; // On parse error, treat as null\n }\n }\n\n private function resolveDealProbability(?string $stageProbability): int\n {\n if ($stageProbability === null) {\n return 0;\n }\n\n $probability = (float) $stageProbability;\n\n return $probability > 1 ? 0 : (int) ($probability * 100);\n }\n\n private function resolveForecastCategory(?string $forecastCategory): string\n {\n if (! $forecastCategory) {\n return Forecast::FORECAST_CATEGORY_UNCATEGORIZED;\n }\n\n $forecastCategory = str_replace('_', ' ', $forecastCategory);\n\n return ucwords(strtolower($forecastCategory));\n }\n\n private function importExternalFieldData(array $properties, int $opportunityId): void\n {\n $crmFields = $this->getOpportunitySyncableFields();\n $this->importOpportunityCrmFieldData($properties, $crmFields, $opportunityId);\n }\n\n private function importOpportunityContacts(Opportunity $opportunity, array $associations): void\n {\n // Handle empty or missing contact associations\n if (empty($associations)) {\n // Remove all existing contact associations if none provided\n $this->removeAllOpportunityContacts($opportunity);\n\n return;\n }\n\n // Use differential sync approach for better performance and accuracy\n $this->syncOpportunityContactsDifferential($opportunity, $associations);\n }\n\n /**\n * Sync opportunity contacts using differential approach\n * This compares current vs new associations and only makes necessary changes\n */\n private function syncOpportunityContactsDifferential(Opportunity $opportunity, array $contactAssociations): void\n {\n $currentContactCrmIds = $this->getCurrentContactCrmIds($opportunity);\n $contactAssociationIds = array_keys($contactAssociations);\n\n $contactsToAdd = array_diff($contactAssociationIds, $currentContactCrmIds);\n $contactsToRemove = array_diff($currentContactCrmIds, $contactAssociationIds);\n\n if (empty($contactsToAdd) && empty($contactsToRemove)) {\n return;\n }\n\n $this->logContactAssociationChanges($opportunity, $currentContactCrmIds, $contactAssociations, $contactsToAdd, $contactsToRemove);\n\n $this->removeContactAssociations($opportunity, $contactsToRemove);\n $this->addContactAssociations($opportunity, $contactsToAdd, $contactAssociations);\n }\n\n private function getCurrentContactCrmIds(Opportunity $opportunity): array\n {\n return $opportunity->contacts()\n ->pluck('contacts.crm_provider_id')\n ->toArray();\n }\n\n private function logContactAssociationChanges(\n Opportunity $opportunity,\n array $currentContactCrmIds,\n array $contactAssociations,\n array $contactsToAdd,\n array $contactsToRemove\n ): void {\n $this->logger->info('[' . $this->getDisplayName() . '] Contact association changes', [\n 'opportunity_id' => $opportunity->getId(),\n 'current_contacts' => $currentContactCrmIds,\n 'new_contacts' => $contactAssociations,\n 'contacts_to_add' => $contactsToAdd,\n 'contacts_to_remove' => $contactsToRemove,\n ]);\n }\n\n private function removeContactAssociations(Opportunity $opportunity, array $contactsToRemove): void\n {\n if (empty($contactsToRemove)) {\n return;\n }\n\n $contactsToDetach = $opportunity->contacts()\n ->whereIn('contacts.crm_provider_id', $contactsToRemove)\n ->pluck('contacts.id')\n ->toArray();\n\n if (! empty($contactsToDetach)) {\n $opportunity->contacts()->detach($contactsToDetach);\n\n $this->logger->info('[' . $this->getDisplayName() . '] Removed contact associations', [\n 'opportunity_id' => $opportunity->getId(),\n 'removed_contact_crm_ids' => $contactsToRemove,\n 'removed_contact_count' => count($contactsToDetach),\n ]);\n }\n }\n\n private function addContactAssociations(Opportunity $opportunity, array $contactsToAdd, array $contactAssociations): void\n {\n if (empty($contactsToAdd)) {\n return;\n }\n\n $contactsAdded = [];\n foreach ($contactsToAdd as $crmId) {\n $id = $contactAssociations[$crmId];\n\n if ($this->attachSingleContact($opportunity, (string) $crmId, $id)) {\n $contactsAdded[] = $crmId;\n }\n }\n\n $this->logAddedContacts($opportunity, $contactsAdded);\n }\n\n private function attachSingleContact(Opportunity $opportunity, string $crmId, int $id): bool\n {\n try {\n $contact = $this->crmEntityRepository->findContactByConfigurationAndId($this->config, $id);\n\n if (! $contact) {\n return false;\n }\n\n return $this->performContactAttachment($opportunity, $contact, $crmId);\n } catch (\\Throwable $e) {\n $this->logger->warning('[' . $this->getDisplayName() . '] Failed to add contact association', [\n 'opportunity_id' => $opportunity->getId(),\n 'contact_crm_id' => $crmId,\n 'error' => $e->getMessage(),\n ]);\n\n return false;\n }\n }\n\n private function performContactAttachment(Opportunity $opportunity, Contact $contact, string $crmId): bool\n {\n try {\n $opportunity->contacts()->attach($contact->getId(), [\n 'crm_provider_id' => $crmId,\n ]);\n\n return true;\n } catch (\\Illuminate\\Database\\QueryException $e) {\n if (str_contains($e->getMessage(), 'Duplicate entry')) {\n $this->logger->info('[' . $this->getDisplayName() . '] Contact association already exists', [\n 'contact_id' => $contact->getId(),\n 'contact_crm_id' => $crmId,\n 'opportunity_id' => $opportunity->getId(),\n ]);\n\n return false;\n }\n\n throw $e;\n }\n }\n\n private function logAddedContacts(Opportunity $opportunity, array $contactsAdded): void\n {\n if (! empty($contactsAdded)) {\n $this->logger->info('[' . $this->getDisplayName() . '] Added contact associations', [\n 'opportunity_id' => $opportunity->getId(),\n 'added_contact_crm_ids' => $contactsAdded,\n 'added_contacts_count' => count($contactsAdded),\n ]);\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"6","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"# **************************** HS **************************************\n\nselect * from teams where id = 2; # 2\nselect * from features; # 2\nselect * from team_features where team_id = 2; # 2\nselect * from crm_configurations where id = 2; # 2\nselect * from users where team_id = 2; #\nselect * from playbooks where team_id = 2; # event 38\nselect * from playbook_categories where playbook_id = 38; #\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;\nhttps://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624\n https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0\n\nSELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;\n# 609126 softphone tr. 11241\n\nSELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;\n# 608874 conference tr. 11226 crmId: 103422236596\n\nselect * from ai_prompts where transcription_id IN (11241, 11226);\nselect * from activity_summary_logs where activity_id = 608874;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nselect * from crm_field_data where activity_id = 1223;\n\nselect * from crm_layouts where crm_configuration_id = 2;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);\nselect * from crm_fields where crm_configuration_id = 11 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);\n\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u\n on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 2 and sa.provider = 'hubspot';\n\nselect * from opportunities where team_id = 2\nand crm_provider_id IN ('51317301383');\n\nselect * from contacts where id = 85;\n\nselect * from opportunities where team_id = 2 order by id desc;\nselect * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112\nselect * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112\nselect * from opportunity_contacts where opportunity_id = 5117;\nselect * from crm_field_data where object_id = 1365;\nSELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);\n\nselect * from features;\nselect * from team_features where team_id IN (1);\nselect * from team_features where feature_id IN (36);\n\nSHOW CREATE TABLE opportunity_contacts;\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';\n\n# $slug = 'HUBSPOT_WEBHOOK_SYNC';\n# $team = Jiminny\\Models\\Team::find(2);\n# $feature = Feature::query()->where('slug', $slug)->first();\n# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);\n\n# hubspot_webhook_metrics\n\nselect * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365\nSELECT * FROM opportunity_contacts WHERE opportunity_id = '414';\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';\nselect * from contacts where id in (414, 464);\n\nselect * from activities where crm_configuration_id = 2;\n\nselect settings from crm_configurations where id = 11;\n\nselect * from teams; # 1, 2\nselect * from users;\nselect * from crm_configurations where id = 39;\nselect * from team_features where team_id = 2;\nselect * from features;\n# SELECT * FROM opportunities WHERE crm_configuration_id = 2\n# order by id desc;\n# and crm_provider_id = '49908861993';\n\n\nselect * from activity_providers where id IN (443, 202, 203, 227);\n\nselect * from activity_imports where id = 795889;\n\nselect c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id\nwhere c.provider = 'hubspot';\n\nselect * from crm_configurations crm JOIN teams t on crm.team_id = t.id\nwhere provider = 'hubspot';\nSELECT * FROM teams WHERE id = 31;\nSELECT * FROM users WHERE id = 257;\nSELECT * FROM opportunities WHERE team_id = 2;\n\nselect * from opportunity_contacts where opportunity_id = 5124;\nselect * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)\n\nselect * from activities where crm_configuration_id = 13;\n\nSELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141\n\n\nselect id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;\nSELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 order by id desc;\nselect * from opportunity_contacts where contact_id = 6223;\nSELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;\n\nselect * from crm_profiles where crm_configuration_id = 2;\n\nselect * from activities where account_id = 46;","depth":4,"value":"# **************************** HS **************************************\n\nselect * from teams where id = 2; # 2\nselect * from features; # 2\nselect * from team_features where team_id = 2; # 2\nselect * from crm_configurations where id = 2; # 2\nselect * from users where team_id = 2; #\nselect * from playbooks where team_id = 2; # event 38\nselect * from playbook_categories where playbook_id = 38; #\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;\nhttps://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624\n https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0\n\nSELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;\n# 609126 softphone tr. 11241\n\nSELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;\n# 608874 conference tr. 11226 crmId: 103422236596\n\nselect * from ai_prompts where transcription_id IN (11241, 11226);\nselect * from activity_summary_logs where activity_id = 608874;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nselect * from crm_field_data where activity_id = 1223;\n\nselect * from crm_layouts where crm_configuration_id = 2;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);\nselect * from crm_fields where crm_configuration_id = 11 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);\n\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;\nSELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u\n on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 2 and sa.provider = 'hubspot';\n\nselect * from opportunities where team_id = 2\nand crm_provider_id IN ('51317301383');\n\nselect * from contacts where id = 85;\n\nselect * from opportunities where team_id = 2 order by id desc;\nselect * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112\nselect * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112\nselect * from opportunity_contacts where opportunity_id = 5117;\nselect * from crm_field_data where object_id = 1365;\nSELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);\n\nselect * from features;\nselect * from team_features where team_id IN (1);\nselect * from team_features where feature_id IN (36);\n\nSHOW CREATE TABLE opportunity_contacts;\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';\n\n# $slug = 'HUBSPOT_WEBHOOK_SYNC';\n# $team = Jiminny\\Models\\Team::find(2);\n# $feature = Feature::query()->where('slug', $slug)->first();\n# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);\n\n# hubspot_webhook_metrics\n\nselect * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365\nSELECT * FROM opportunity_contacts WHERE opportunity_id = '414';\nSELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';\nselect * from contacts where id in (414, 464);\n\nselect * from activities where crm_configuration_id = 2;\n\nselect settings from crm_configurations where id = 11;\n\nselect * from teams; # 1, 2\nselect * from users;\nselect * from crm_configurations where id = 39;\nselect * from team_features where team_id = 2;\nselect * from features;\n# SELECT * FROM opportunities WHERE crm_configuration_id = 2\n# order by id desc;\n# and crm_provider_id = '49908861993';\n\n\nselect * from activity_providers where id IN (443, 202, 203, 227);\n\nselect * from activity_imports where id = 795889;\n\nselect c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id\nwhere c.provider = 'hubspot';\n\nselect * from crm_configurations crm JOIN teams t on crm.team_id = t.id\nwhere provider = 'hubspot';\nSELECT * FROM teams WHERE id = 31;\nSELECT * FROM users WHERE id = 257;\nSELECT * FROM opportunities WHERE team_id = 2;\n\nselect * from opportunity_contacts where opportunity_id = 5124;\nselect * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)\n\nselect * from activities where crm_configuration_id = 13;\n\nSELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141\n\n\nselect id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;\nSELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;\nSELECT * FROM contacts WHERE team_id = 2 order by id desc;\nselect * from opportunity_contacts where contact_id = 6223;\nSELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;\n\nselect * from crm_profiles where crm_configuration_id = 2;\n\nselect * from activities where account_id = 46;","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-7827763017813047052
|
1048134296968532324
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#11976 on JY-20553-debug- Project: faVsco.js, menu
#11976 on JY-20553-debug-crm-sync-delays, menu
Start Listening for PHP Debug Connections
RequestGenerateAskJiminnyReportJobTest
Run 'RequestGenerateAskJiminnyReportJobTest'
Debug 'RequestGenerateAskJiminnyReportJobTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
33
2
19
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Crm\Hubspot\ServiceTraits;
use Carbon\Carbon;
use HubSpot\Client\Crm\Deals\Model\CollectionResponseAssociatedId;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Models\Account;
use Exception;
use Jiminny\Component\DealInsights\Forecast\Forecast;
use Jiminny\Jobs\Crm\MatchActivitiesToNewOpportunity;
use Jiminny\Models\Contact;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Exceptions\CrmException;
use Jiminny\Models\Opportunity;
use Illuminate\Support\Collection;
use Jiminny\Models\Stage;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Services\Crm\Hubspot\DealFieldsService;
use Jiminny\Services\Crm\Hubspot\OpportunitySyncStrategy\HubspotSingleSyncStrategy;
use Jiminny\Services\Crm\Hubspot\WebhookSyncBatchProcessor;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Utils\CurrencyFormatter;
/**
* Optimized sync methods for better performance
* These methods can be integrated into SyncCrmEntitiesTrait for significant performance gains
*/
trait OpportunitySyncTrait
{
private const int BATCH_SIZE = 100;
private const int BATCH_PROCESS_SIZE = 800;
protected OpportunitySyncStrategyResolver $opportunitySyncStrategyResolver;
protected CrmEntityRepository $crmEntityRepository;
protected DealFieldsService $dealFieldsService;
private ?array $cachedClosedDealStages = null;
private array $cachedBusinessProcesses = [];
private array $cachedStages = [];
public function syncOpportunities(array $parameters, ?string $strategy = null): int
{
$startTime = microtime(true);
$strategies = $this->opportunitySyncStrategyResolver->getStrategies($this->config, $strategy);
$parameters['config'] = $this->config;
$syncCount = 0;
$reportedTotal = 0;
$lastSyncedId = [];
$strategyNames = [];
try {
foreach ($strategies as $strategyName => $syncStrategy) {
$strategyNames[] = $strategyName;
$this->logger->info(
'[' . $this->getDisplayName() . '] Syncing opportunities using strategy: ' . $strategyName,
['team' => $this->team->getId()]
);
$total = 0;
$lastId = null;
$buffer = [];
// HubspotWebhookBatchSyncStrategy returns empty generator, this is for other strategies
foreach ($syncStrategy->fetchOpportunities($parameters, $total, $lastId) as $hsOpportunity) {
$buffer[] = $hsOpportunity;
// process every 800 rows (fits < 1 000 association limit)
if (\count($buffer) >= self::BATCH_PROCESS_SIZE) {
$syncCount += $this->processOpportunityBatch($buffer);
$buffer = [];
}
}
// leftovers
if ($buffer) {
$syncCount += $this->processOpportunityBatch($buffer);
}
$reportedTotal += $total;
$lastSyncedId = $lastId;
}
} catch (\HubSpot\Client\Crm\Deals\ApiException | CrmException $e) {
$this->handleSyncException($e, $parameters);
}
$durationMs = round((microtime(true) - $startTime) * 1000, 2);
$this->logger->info(
'[HubSpot] Synced opportunities',
[
'team' => $this->team->getId(),
'strategies' => implode(',', $strategyNames),
'sync_count' => $syncCount,
'total' => $reportedTotal,
'last_synced_id' => $lastSyncedId,
'duration_ms' => $durationMs,
]
);
return $reportedTotal;
}
private function handleSyncException(\Throwable $e, array $parameters): void
{
if (($parameters['since'] ?? null) instanceof Carbon) {
$parameters['since'] = $parameters['since']->toDateTimeString();
}
$parameters['config'] = $this->config->getId();
$this->logger->warning('[' . $this->getDisplayName() . '] Sync opportunities failed', [
'teamId' => $this->team->getUuid(),
'parameters' => $parameters,
'reason' => $e->getMessage(),
]);
}
/**
* @inheritdoc
*/
public function syncOpportunity(string $crmId): ?Opportunity
{
$strategy = $this->opportunitySyncStrategyResolver->resolve(
$this->config,
OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY,
);
$parameters = [
'config' => $this->config,
'crm_id' => $crmId,
];
try {
if (! $strategy instanceof HubspotSingleSyncStrategy) {
throw new InvalidArgumentException('Strategy must by HubspotSingleSyncStrategy');
}
$hsOpportunity = $strategy->fetchOpportunity($parameters);
} catch (\HubSpot\Client\Crm\Deals\ApiException $e) {
$this->logger->info('[' . $this->getDisplayName() . '] Opportunity not found', [
'teamId' => $this->team->getUuid(),
'crmId' => $crmId,
'reason' => $e->getMessage(),
]);
return null;
}
$hsOpportunity['associations'] = $this->convertDealAssociations($hsOpportunity['associations'] ?? []);
return $this->importOrUpdateOpportunity($hsOpportunity);
}
/**
* Process webhook-collected opportunity batches.
*
* Drains Redis sets containing company CRM IDs collected from webhook events
* and dispatches ImportOpportunityBatch jobs for batch processing.
*
* @return int Number of opportunity IDs dispatched to jobs
*/
public function batchSyncOpportunities(): int
{
$configId = $this->team->getCrmConfiguration()->getId();
return $this->batchProcessor->processBatchesForObjectType(
WebhookSyncBatchProcessor::OBJECT_TYPE_DEAL,
$configId
);
}
/**
* Import a batch of opportunities by their CRM IDs.
* Fetches opportunity data from HubSpot API and delegates to importOpportunityBatch().
*
* @param array<string> $crmIds HubSpot deal CRM IDs
*
* @return array{success: array, failed_ids: array, errors?: array<string, string>}
*/
public function importOpportunityBatchByIds(array $crmIds): array
{
$fields = $this->dealFieldsService->getFieldsForConfiguration($this->config);
$allDeals = [];
foreach (array_chunk($crmIds, self::BATCH_SIZE) as $chunk) {
$deals = $this->client->getOpportunitiesByIds($chunk, $fields);
foreach ($deals as $deal) {
$allDeals[] = $deal;
}
}
// IDs not returned by HubSpot are likely deleted or inaccessible deals.
// These are not failures — retrying won't bring them back.
$fetchedIds = array_map('strval', array_column($allDeals, 'id'));
$notFoundIds = array_values(array_diff(array_map('strval', $crmIds), $fetchedIds));
if (! empty($notFoundIds)) {
$this->logger->info('[' . $this->getDisplayName() . '] CRM IDs not found in HubSpot (likely deleted)', [
'teamId' => $this->team->getId(),
'notFoundCount' => \count($notFoundIds),
'notFoundIds' => $notFoundIds,
'requestedCount' => \count($crmIds),
'fetchedCount' => \count($allDeals),
]);
}
if (empty($allDeals)) {
return ['success' => [], 'failed_ids' => []];
}
return $this->importOpportunityBatch($allDeals);
}
private function getClosedDealStages(): array
{
if ($this->cachedClosedDealStages !== null) {
return $this->cachedClosedDealStages;
}
$stages = $this->crmEntityRepository->getOpportunityClosedStages($this->config);
$data = [
'lost' => [],
'won' => [],
];
foreach ($stages as $stage) {
if ($stage->probability == 0.00) {
$data['lost'][] = $stage->crm_provider_id;
}
if ($stage->probability == 100.00) {
$data['won'][] = $stage->crm_provider_id;
}
}
$this->cachedClosedDealStages = $data;
return $data;
}
/**
* Import deals into the database with pre-fetched associations.
*
* API calls here (getAssociationsData, getExistingOpportunityCrmIds) are NOT
* caught — if they throw, the exception propagates to ImportOpportunityBatch::handle()
* where Laravel retries the whole job with backoff. After all retries exhausted,
* failed() requeues all IDs to Redis.
*
* The per-deal loop catches exceptions individually. A deal can end up in three states:
* - success: imported/updated successfully
* - failed_ids: exception thrown (DB constraint violation, corrupt data, etc.)
* These are permanent issues — retrying won't fix them.
* - skipped (null): missing dependencies (no account, unknown pipeline/stage).
* This is acceptable — the deal cannot be imported until those exist.
*/
private function importOpportunityBatch(array $deals): array
{
$syncedOpportunities = [
'success' => [],
'failed_ids' => [],
];
$dealIds = array_column($deals, 'id');
// Shared association/existing-ID preparation is batch-level state. If it fails, rethrow so the
// queue job retries the whole batch and eventually requeues all deal IDs back to Redis.
try {
$companyAssociations = $this->client->getAssociationsData($dealIds, 'deals', 'companies');
$contactAssociations = $this->client->getAssociationsData($dealIds, 'deals', 'contacts');
$associationsData = $this->prepareAssociatedEntities($companyAssociations, $contactAssociations);
$existingCrmIds = $this->crmEntityRepository->getExistingOpportunityCrmIds(
$this->config,
array_map('strval', $dealIds)
);
$existingCrmIdSet = array_flip($existingCrmIds);
} catch (\Throwable $e) {
$this->logger->error('[' . $this->getDisplayName() . '] Failed to fetch associations or existing IDs', [
'teamId' => $this->team->getId(),
'dealCount' => count($dealIds),
'error' => $e->getMessage(),
]);
throw $e;
}
foreach ($deals as $deal) {
try {
$deal['associations'] = $this->prepareAssociationsForOpportunity(
$deal['id'],
$companyAssociations,
$contactAssociations,
$associationsData
);
$syncedOpportunity = $this->importOrUpdateOpportunity(
$deal,
isset($existingCrmIdSet[(string) $deal['id']])
);
if ($syncedOpportunity) {
$syncedOpportunities['success'][] = $syncedOpportunity;
}
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Failed to import opportunity', [
'teamId' => $this->team->getId(),
'crmId' => $deal['id'],
'error' => $e->getMessage(),
]);
$syncedOpportunities['failed_ids'][] = $deal['id'];
$syncedOpportunities['errors'][$deal['id']] = $e->getMessage();
}
}
return $syncedOpportunities;
}
/**
* Prepare associated entities for opportunities with optimized batch processing
* Returns structured data with CRM ID to DB ID mappings for each opportunity
*/
private function prepareAssociatedEntities(array $companyAssociations, array $contactAssociations): array
{
// Step 1: Collect all unique company and contact IDs from associations
$allCompanyIds = $this->flattenAssociationIds($companyAssociations);
$allContactIds = $this->flattenAssociationIds($contactAssociations);
// Step 2: Batch sync missing entities and get CRM ID to DB ID mappings
$companyIdMappings = [];
$contactIdMappings = [];
if (! empty($allCompanyIds)) {
$companyIdMappings = $this->prepareAssociatedAccounts($allCompanyIds);
}
if (! empty($allContactIds)) {
$contactIdMappings = $this->prepareAssociatedContacts($allContactIds);
}
return [
'company_id_mappings' => $companyIdMappings,
'contact_id_mappings' => $contactIdMappings,
];
}
/**
* Flatten association data to get unique IDs
*/
private function flattenAssociationIds(array $associations): array
{
$ids = [];
foreach ($associations as $dealAssociations) {
if (is_array($dealAssociations)) {
foreach ($dealAssociations as $id) {
$ids[$id] = true;
}
}
}
return array_keys($ids);
}
/**
* Batch sync missing accounts
*/
private function prepareAssociatedAccounts(array $companyIds): array
{
// Find which accounts already exist
$existingAccounts = $this->crmEntityRepository
->findAccountsByExternalIds($this->config, $companyIds);
$existingCompanyIds = $existingAccounts->pluck('crm_provider_id')->toArray();
$existingAccountsData = $existingAccounts->mapWithKeys(function ($account) {
return [$account->getCrmProviderId() => $account->getId()];
})->toArray();
$missingCompanyIds = array_diff($companyIds, $existingCompanyIds);
if (empty($missingCompanyIds)) {
return $existingAccountsData;
}
$this->logger->info('[' . $this->getDisplayName() . '] Batch syncing missing accounts', [
'teamId' => $this->team->getUuid(),
'total_companies' => count($companyIds),
'existing_companies' => count($existingCompanyIds),
'missing_companies' => count($missingCompanyIds),
]);
// we already have limit on opportunity ids count
// Initialize variable before try block
$syncedAccountsData = [];
try {
$syncedAccountsData = $this->batchSyncCrmObjects('companies', $missingCompanyIds);
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Failed to sync missing accounts', [
'size' => count($missingCompanyIds),
'error' => $e->getMessage(),
]);
$syncedAccountsData = [];
}
return $existingAccountsData + $syncedAccountsData;
}
/**
* Prepare associated contacts - find existing and sync missing ones
* Returns mapping of CRM ID to DB ID
*/
private function prepareAssociatedContacts(array $contactIds): array
{
// Find which contacts already exist
$existingContacts = $this->crmEntityRepository
->findContactsByExternalIds($this->config, $contactIds);
$existingContactIds = $existingContacts->pluck('crm_provider_id')->toArray();
// Create mapping for existing contacts
$existingContactsData = $existingContacts->mapWithKeys(function ($contact) {
return [$contact->getCrmProviderId() => $contact->getId()];
})->toArray();
$missingContactIds = array_diff($contactIds, $existingContactIds);
if (empty($missingContactIds)) {
return $existingContactsData;
}
$this->logger->info('[' . $this->getDisplayName() . '] Batch syncing missing contacts', [
'teamId' => $this->team->getUuid(),
'total_contacts' => count($contactIds),
'existing_contacts' => count($existingContactIds),
'missing_contacts' => count($missingContactIds),
]);
// Sync missing contacts using batch API
try {
$syncedContactsData = $this->batchSyncCrmObjects('contacts', $missingContactIds);
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Failed to sync missing contacts', [
'size' => count($missingContactIds),
'error' => $e->getMessage(),
]);
$syncedContactsData = [];
}
return $existingContactsData + $syncedContactsData;
}
private function batchSyncCrmObjects(string $objectType, array $crmIds): array
{
$syncObjects = [];
$crmObjectIds = array_values($crmIds);
foreach (array_chunk($crmObjectIds, self::BATCH_SIZE) as $chunk) {
try {
$objects = $objectType === 'companies' ?
$this->client->getCompaniesByIds($chunk, $this->getCompanyFields()) :
$this->client->getContactsByIds($chunk, $this->getContactFields());
foreach ($objects as $objectId => $objectData) {
$this->importCrmObject($objectType, (string) $objectId, $objectData, $syncObjects);
}
$this->logger->info('[' . $this->getDisplayName() . '] Batch synced ' . $objectType, [
'requested_count' => count($chunk),
'synced_count' => count($objects),
]);
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Batch ' . $objectType . ' sync failed', [
'ids' => $chunk,
'error' => $e->getMessage(),
]);
}
}
return $syncObjects;
}
private function importCrmObject(string $objectType, string $objectId, mixed $objectData, array &$syncObjects): void
{
try {
$object = $objectType === 'companies' ?
$this->importAccount($objectData) :
$this->importContact($objectData);
if ($object) {
$syncObjects[$object->getCrmProviderId()] = $object->getId();
}
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Failed to import batch ' . $objectType, [
'id' => $objectId,
'error' => $e->getMessage(),
]);
}
}
/**
* Prepare associations for a single opportunity
*
* The return value is an array with the following structure:
* [
* 'companies' => [
* $companyCrmId => $companyId,
* ...
* ],
* 'contacts' => [
* $contactCrmId => $contactId,
* ...
* ],
* 'account_id' => $accountId,
* ]
*/
private function prepareAssociationsForOpportunity(
string $oppCrmId,
array $companyAssociations,
array $contactAssociations,
array $associationsData
): array {
$associations = [
'companies' => [],
'contacts' => [],
'account_id' => null, // Primary account for opportunity
];
$oppCompanyIds = $companyAssociations[$oppCrmId] ?? [];
foreach ($oppCompanyIds as $companyCrmId) {
if (isset($associationsData['company_id_mappings'][$companyCrmId])) {
$associations['companies'][$companyCrmId] = $associationsData['company_id_mappings'][$companyCrmId];
// Set primary account (first company becomes primary account)
if ($associations['account_id'] === null) {
$associations['account_id'] = $associationsData['company_id_mappings'][$companyCrmId];
}
}
}
$oppContactIds = $contactAssociations[$oppCrmId] ?? [];
foreach ($oppContactIds as $contactCrmId) {
if (isset($associationsData['contact_id_mappings'][$contactCrmId])) {
$associations['contacts'][$contactCrmId] = $associationsData['contact_id_mappings'][$contactCrmId];
}
}
return $associations;
}
/**
* Update only associations for an opportunity
*/
private function updateOpportunityAssociations(Opportunity $opportunity, array $associations): void
{
// Update contact associations
$this->importOpportunityContacts($opportunity, $associations['contacts']);
// Update company (account) associations
$this->updateOpportunityAccount($opportunity, $associations['account_id']);
}
/**
* Remove all contact associations from an opportunity
*/
private function removeAllOpportunityContacts(Opportunity $opportunity): void
{
$currentCount = (int) $opportunity->contacts()->count();
if ($currentCount > 0) {
$opportunity->contacts()->detach();
$this->logger->info('[' . $this->getDisplayName() . '] Removed all contact associations', [
'opportunity_id' => $opportunity->getId(),
'removed_count' => $currentCount,
]);
}
}
private function updateOpportunityAccount(Opportunity $opportunity, ?int $accountId): void
{
if ($accountId === null) {
// No account ID provided - keep current account
return;
}
$currentAccountId = $opportunity->getAccountId();
// Only update if account has changed
if ($currentAccountId !== $accountId) {
$opportunity->account_id = $accountId;
$opportunity->save();
$this->logger->info('[' . $this->getDisplayName() . '] Updated opportunity account association', [
'opportunity_id' => $opportunity->getId(),
'old_account_id' => $currentAccountId,
'new_account_id' => $accountId,
]);
}
}
/**
* Find existing opportunities by external IDs (OPTIMIZED VERSION)
* Uses batch query for better performance
*/
private function findExistingOpportunities(array $crmIds): Collection
{
return $this->crmEntityRepository
->findOpportunitiesByExternalIds($this->config, $crmIds);
}
private function processOpportunityBatch(array $opportunities): int
{
$syncedOpportunities = $this->importOpportunityBatch($opportunities);
return count($syncedOpportunities['success'] ?? []);
}
/**
* Convert single deal associations from HubSpot format to internal format
* Handles both HubSpot SDK objects and array formats
*
* @param array $opportunityAssociations Raw associations from HubSpot API or pre-processed
*
* @return array Processed associations with DB IDs
*/
private function convertDealAssociations(array $opportunityAssociations): array
{
$associations = $this->initializeAssociationsStructure();
if (empty($opportunityAssociations)) {
return $associations;
}
$associationIds = $this->extractAssociationIds($opportunityAssociations);
$this->processCompanyAssociations($associationIds, $associations);
$this->processContactAssociations($associationIds, $associations);
return $associations;
}
private function initializeAssociationsStructure(): array
{
return [
'companies' => [],
'contacts' => [],
'account_id' => null, // Primary account for opportunity
];
}
private function extractAssociationIds(array $opportunityAssociations): array
{
$associationIds = [];
foreach ($opportunityAssociations as $type => $associationData) {
if (! empty($associationData)) {
$associationIds[$type] = $this->convertSingleDealAssociations($associationData);
}
}
return $associationIds;
}
private function processCompanyAssociations(array $associationIds, array &$associations): void
{
if (empty($associationIds['companies'])) {
return;
}
$companyId = $associationIds['companies'][0];
$account = $this->findOrSyncAccount($companyId);
if ($account instanceof Account) {
$associations['companies'][$companyId] = $account->getId();
$associations['account_id'] = $account->getId();
}
}
private function processContactAssociations(array $associationIds, array &$associations): void
{
if (empty($associationIds['contacts'])) {
return;
}
foreach ($associationIds['contacts'] as $contactId) {
$contact = $this->findOrSyncContact($contactId);
if ($contact instanceof Contact) {
$associations['contacts'][$contactId] = $contact->getId();
}
}
}
private function findOrSyncAccount(string $companyId): ?Account
{
$account = $this->crmEntityRepository->findAccountByExternalId($this->config, $companyId);
if (! $account instanceof Account) {
$account = $this->syncAccount($companyId);
}
return $account;
}
private function findOrSyncContact(string $contactId): ?Contact
{
$contact = $this->crmEntityRepository->findContactByExternalId($this->config, $contactId);
if (! $contact instanceof Contact) {
$contact = $this->syncContact($contactId);
}
return $contact;
}
private function convertSingleDealAssociations($opportunityAssociations = null): array
{
$associationData = [];
if ($opportunityAssociations === null) {
return $associationData;
}
// Handle array input (from extractAssociationIds)
if (is_array($opportunityAssociations)) {
return $opportunityAssociations;
}
// Handle CollectionResponseAssociatedId object
if ($opportunityAssociations instanceof CollectionResponseAssociatedId) {
foreach ($opportunityAssociations->getResults() as $association) {
$associationData[] = $association->getId();
}
}
return $associationData;
}
private function importOrUpdateOpportunity($crmData, ?bool $exists = null): ?Opportunity
{
if (empty($crmData['properties'])) {
return null;
}
$crmId = (string) $crmData['id'];
$properties = $crmData['properties'];
$associations = $crmData['associations'] ?? [];
$opportunityExists = $exists ?? (bool) $this->crmEntityRepository->findOpportunityByExternalId(
$this->config,
$crmId
);
if ($opportunityExists) {
return $this->updateOpportunity($crmId, $properties, $associations);
}
return $this->createOpportunity($crmId, $properties, $associations);
}
/**
* Create new opportunity
*/
private function createOpportunity(string $crmId, array $properties, array $associations): ?Opportunity
{
$accountId = $this->resolveAccountId($associations);
if (! $accountId) {
return null;
}
$businessProcess = $this->resolveBusinessProcess($properties['pipeline'] ?? null);
if (! $businessProcess) {
return null;
}
$stage = $this->resolveStage($businessProcess, $properties['dealstage'] ?? null);
if (! $stage) {
return null;
}
$data = $this->buildOpportunityData($properties, $accountId, $businessProcess, $stage);
$attributes = [
'crm_configuration_id' => $this->config->getId(),
'crm_provider_id' => $crmId,
];
$values = array_merge($attributes, $data);
$opportunity = $this->crmEntityRepository->upsertOpportunity($attributes, $values);
$this->importExternalFieldData($properties, $opportunity->getId());
$this->importOpportunityContacts($opportunity, $associations['contacts']);
if ($opportunity->wasRecentlyCreated) {
MatchActivitiesToNewOpportunity::dispatch($opportunity->getId());
}
return $opportunity;
}
/**
* Update existing opportunity
*/
private function updateOpportunity(string $crmId, array $properties, array $associations): Opportunity
{
$accountId = $this->resolveAccountId($associations);
$businessProcess = $this->resolveBusinessProcess($properties['pipeline'] ?? null);
$stage = $businessProcess ? $this->resolveStage($businessProcess, $properties['dealstage'] ?? null) : null;
$data = $this->buildOpportunityData($properties, $accountId, $businessProcess, $stage);
$attributes = [
'crm_configuration_id' => $this->config->getId(),
'crm_provider_id' => $crmId,
];
$values = array_merge($attributes, $data);
$opportunity = $this->crmEntityRepository->upsertOpportunity($attributes, $values);
$this->importExternalFieldData($properties, $opportunity->getId());
$this->updateOpportunityAssociations($opportunity, $associations);
return $opportunity;
}
private function resolveAccountId(array $associations): ?int
{
if (! empty($associations['account_id'])) {
return $associations['account_id'];
}
if (empty($associations)) {
return null;
}
// Fallback: use first company as account (currently SDK returns one company)
foreach ($associations['companies'] as $accountId) {
return $accountId;
}
return null;
}
private function buildOpportunityData(
array $properties,
?int $accountId,
?BusinessProcess $businessProcess,
?Stage $stage
): array {
$ownerId = null;
$profile = null;
if (! empty($properties['hubspot_owner_id'])) {
$ownerId = $properties['hubspot_owner_id'];
$profile = $this->crmEntityRepository->findProfileByExternalId($this->config, (string) $ownerId);
}
$name = 'Unknown';
if (isset($properties['dealname'])) {
$name = mb_strimwidth($properties['dealname'], 0, 128);
}
$amount = $this->resolveAmount($properties);
$currency = $properties['deal_currency_code'] ?? null;
$closeDate = null;
if (! empty($properties['closedate'])) {
$closeDate = Carbon::parse($properties['closedate'])->format('Y-m-d');
}
$remotelyCreatedAt = null;
if (! empty($properties['createdate']) && strtotime($properties['createdate'])) {
$date = $this->parseCleanDatetime($properties['createdate']);
$remotelyCreatedAt = $date?->format('Y-m-d H:i:s');
}
$closedStages = $this->getClosedDealStages();
$isWon = in_array($properties['dealstage'], $closedStages['won']);
$isLost = in_array($properties['dealstage'], $closedStages['lost']);
$data = [
'team_id' => $this->team->getId(),
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $ownerId,
'name' => $name,
'value' => ! empty($amount) ? $amount : null,
'currency_code' => CurrencyFormatter::formatCode($currency),
'close_date' => $closeDate,
'is_closed' => $isWon || $isLost,
'is_won' => $isWon,
'remotely_created_at' => $remotelyCreatedAt,
'probability' => $this->resolveDealProbability($properties['hs_deal_stage_probability']),
'forecast_category' => $this->resolveForecastCategory($properties['hs_manual_forecast_category']),
];
if ($accountId) {
$data['account_id'] = $accountId;
}
if ($stage) {
$data['stage_id'] = $stage->id;
}
if ($businessProcess) {
$recordType = $this->crmEntityRepository->getBusinessProcessRecordType($businessProcess);
if ($recordType) {
$data['record_type_id'] = $recordType->id;
}
}
return $data;
}
private function resolveBusinessProcess(?string $pipelineId): ?BusinessProcess
{
if ($pipelineId === null) {
return null;
}
$cacheKey = $this->getBusinessProcessCacheKey($pipelineId);
if (isset($this->cachedBusinessProcesses[$cacheKey])) {
return $this->cachedBusinessProcesses[$cacheKey];
}
$businessProcess = $this->getBusinessProcess($pipelineId);
if (! $businessProcess instanceof BusinessProcess) {
$this->importStages();
$businessProcess = $this->getBusinessProcess($pipelineId);
}
if (! $businessProcess instanceof BusinessProcess) {
$this->logger->info(
'[HubSpot] Deal is not attached to a pipeline',
[
'pipeline' => $pipelineId]
);
}
$this->cachedBusinessProcesses[$cacheKey] = $businessProcess;
return $businessProcess;
}
private function getBusinessProcess(string $pipelineId): ?BusinessProcess
{
return $this->crmEntityRepository->findBusinessProcessesByExternalId($this->config, $pipelineId);
}
private function getBusinessProcessCacheKey(string $pipelineId): string
{
return $this->config->getId() . '_' . $pipelineId;
}
private function resolveStage(BusinessProcess $businessProcess, ?string $stageId): ?Stage
{
if (empty($stageId)) {
return null;
}
$cacheKey = $businessProcess->getId() . ':' . $stageId;
if (isset($this->cachedStages[$cacheKey])) {
return $this->cachedStages[$cacheKey];
}
$stage = $this->crmEntityRepository->getPipelineStageByConditions(
$businessProcess,
[
'crm_provider_id' => $stageId,
'type' => Stage::TYPE_OPPORTUNITY,
]
);
if ($stage === null) {
$this->importStages(null, $stageId);
}
if ($stage === null) {
$this->logger->info('[HubSpot] Stage does not exist => ' . $stageId);
}
$this->cachedStages[$cacheKey] = $stage;
return $stage;
}
private function resolveAmount(array $properties): ?string
{
$amount = null;
if (! empty($properties['amount'])) {
$amount = str_replace(',', '', $properties['amount']);
}
if ($this->config->hasDefaultCurrencyFieldSet()) {
$valueFieldName = $this->config->getDefaultCurrencyField()->getCrmProviderId();
$amount = $properties[$valueFieldName] ?? $amount;
}
return $amount;
}
private function parseCleanDatetime(string $datetime): ?Carbon
{
// Treat pre-1980 values as invalid
$minValidDate = Carbon::parse('1980-01-01 00:00:00');
try {
$date = Carbon::parse($datetime);
if ($minValidDate->gt($date)) {
return null;
}
return $date;
} catch (Exception) {
return null; // On parse error, treat as null
}
}
private function resolveDealProbability(?string $stageProbability): int
{
if ($stageProbability === null) {
return 0;
}
$probability = (float) $stageProbability;
return $probability > 1 ? 0 : (int) ($probability * 100);
}
private function resolveForecastCategory(?string $forecastCategory): string
{
if (! $forecastCategory) {
return Forecast::FORECAST_CATEGORY_UNCATEGORIZED;
}
$forecastCategory = str_replace('_', ' ', $forecastCategory);
return ucwords(strtolower($forecastCategory));
}
private function importExternalFieldData(array $properties, int $opportunityId): void
{
$crmFields = $this->getOpportunitySyncableFields();
$this->importOpportunityCrmFieldData($properties, $crmFields, $opportunityId);
}
private function importOpportunityContacts(Opportunity $opportunity, array $associations): void
{
// Handle empty or missing contact associations
if (empty($associations)) {
// Remove all existing contact associations if none provided
$this->removeAllOpportunityContacts($opportunity);
return;
}
// Use differential sync approach for better performance and accuracy
$this->syncOpportunityContactsDifferential($opportunity, $associations);
}
/**
* Sync opportunity contacts using differential approach
* This compares current vs new associations and only makes necessary changes
*/
private function syncOpportunityContactsDifferential(Opportunity $opportunity, array $contactAssociations): void
{
$currentContactCrmIds = $this->getCurrentContactCrmIds($opportunity);
$contactAssociationIds = array_keys($contactAssociations);
$contactsToAdd = array_diff($contactAssociationIds, $currentContactCrmIds);
$contactsToRemove = array_diff($currentContactCrmIds, $contactAssociationIds);
if (empty($contactsToAdd) && empty($contactsToRemove)) {
return;
}
$this->logContactAssociationChanges($opportunity, $currentContactCrmIds, $contactAssociations, $contactsToAdd, $contactsToRemove);
$this->removeContactAssociations($opportunity, $contactsToRemove);
$this->addContactAssociations($opportunity, $contactsToAdd, $contactAssociations);
}
private function getCurrentContactCrmIds(Opportunity $opportunity): array
{
return $opportunity->contacts()
->pluck('contacts.crm_provider_id')
->toArray();
}
private function logContactAssociationChanges(
Opportunity $opportunity,
array $currentContactCrmIds,
array $contactAssociations,
array $contactsToAdd,
array $contactsToRemove
): void {
$this->logger->info('[' . $this->getDisplayName() . '] Contact association changes', [
'opportunity_id' => $opportunity->getId(),
'current_contacts' => $currentContactCrmIds,
'new_contacts' => $contactAssociations,
'contacts_to_add' => $contactsToAdd,
'contacts_to_remove' => $contactsToRemove,
]);
}
private function removeContactAssociations(Opportunity $opportunity, array $contactsToRemove): void
{
if (empty($contactsToRemove)) {
return;
}
$contactsToDetach = $opportunity->contacts()
->whereIn('contacts.crm_provider_id', $contactsToRemove)
->pluck('contacts.id')
->toArray();
if (! empty($contactsToDetach)) {
$opportunity->contacts()->detach($contactsToDetach);
$this->logger->info('[' . $this->getDisplayName() . '] Removed contact associations', [
'opportunity_id' => $opportunity->getId(),
'removed_contact_crm_ids' => $contactsToRemove,
'removed_contact_count' => count($contactsToDetach),
]);
}
}
private function addContactAssociations(Opportunity $opportunity, array $contactsToAdd, array $contactAssociations): void
{
if (empty($contactsToAdd)) {
return;
}
$contactsAdded = [];
foreach ($contactsToAdd as $crmId) {
$id = $contactAssociations[$crmId];
if ($this->attachSingleContact($opportunity, (string) $crmId, $id)) {
$contactsAdded[] = $crmId;
}
}
$this->logAddedContacts($opportunity, $contactsAdded);
}
private function attachSingleContact(Opportunity $opportunity, string $crmId, int $id): bool
{
try {
$contact = $this->crmEntityRepository->findContactByConfigurationAndId($this->config, $id);
if (! $contact) {
return false;
}
return $this->performContactAttachment($opportunity, $contact, $crmId);
} catch (\Throwable $e) {
$this->logger->warning('[' . $this->getDisplayName() . '] Failed to add contact association', [
'opportunity_id' => $opportunity->getId(),
'contact_crm_id' => $crmId,
'error' => $e->getMessage(),
]);
return false;
}
}
private function performContactAttachment(Opportunity $opportunity, Contact $contact, string $crmId): bool
{
try {
$opportunity->contacts()->attach($contact->getId(), [
'crm_provider_id' => $crmId,
]);
return true;
} catch (\Illuminate\Database\QueryException $e) {
if (str_contains($e->getMessage(), 'Duplicate entry')) {
$this->logger->info('[' . $this->getDisplayName() . '] Contact association already exists', [
'contact_id' => $contact->getId(),
'contact_crm_id' => $crmId,
'opportunity_id' => $opportunity->getId(),
]);
return false;
}
throw $e;
}
}
private function logAddedContacts(Opportunity $opportunity, array $contactsAdded): void
{
if (! empty($contactsAdded)) {
$this->logger->info('[' . $this->getDisplayName() . '] Added contact associations', [
'opportunity_id' => $opportunity->getId(),
'added_contact_crm_ids' => $contactsAdded,
'added_contacts_count' => count($contactsAdded),
]);
}
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
6
1
6
Previous Highlighted Error
Next Highlighted Error
# [PASSWORD_DOTS] HS [PASSWORD_DOTS]
select * from teams where id = 2; # 2
select * from features; # 2
select * from team_features where team_id = 2; # 2
select * from crm_configurations where id = 2; # 2
select * from users where team_id = 2; #
select * from playbooks where team_id = 2; # event 38
select * from playbook_categories where playbook_id = 38; #
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id is not null order by id desc;
https://app.hubspot.com/contacts/4392066/deal/16964514951/?engagement=96069102624
https://app.staging.jiminny.com/playback/d5df34dc-bd66-4ff5-a7b3-8d3be30322a0
SELECT * FROM activities WHERE uuid_to_bin('04fdcd0d-818f-4c53-92dc-6f18bc753ffd') = uuid;
# 609126 softphone tr. 11241
SELECT * FROM activities WHERE uuid_to_bin('6521bfcd-5a30-46e5-9f74-5440fd48befd') = uuid;
# 608874 conference tr. 11226 crmId: 103422236596
select * from ai_prompts where transcription_id IN (11241, 11226);
select * from activity_summary_logs where activity_id = 608874;
select * from sidekick_settings;
select * from default_activity_types;
select * from crm_field_data where activity_id = 1223;
select * from crm_layouts where crm_configuration_id = 2;
SELECT * FROM crm_layout_entities WHERE crm_layout_id IN (554);
select * from crm_fields where crm_configuration_id = 11 and object_type = 'event';
SELECT * FROM crm_field_values WHERE crm_field_id IN (1455,1450);
SELECT * FROM crm_field_data WHERE crm_layout_entity_id = 971;
SELECT * FROM crm_field_data WHERE crm_layout_entity_id IN (6494,6495,6496,6497,6498,6499);
SELECT
CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,
u.email,
sa.*,
t.owner_id FROM social_accounts sa
JOIN users u
on u.id = sa.sociable_id
JOIN teams t on t.id = u.team_id
WHERE u.team_id = 2 and sa.provider = 'hubspot';
select * from opportunities where team_id = 2
and crm_provider_id IN ('51317301383');
select * from contacts where id = 85;
select * from opportunities where team_id = 2 order by id desc;
select * from opportunities where team_id = 2 and crm_provider_id = '51317301383'; # 5112
select * from opportunities where team_id = 2 and crm_provider_id = '55976759904'; # 5112
select * from opportunity_contacts where opportunity_id = 5117;
select * from crm_field_data where object_id = 1365;
SELECT * FROM crm_fields WHERE id IN (1405, 1407, 1972, 2128);
select * from features;
select * from team_features where team_id IN (1);
select * from team_features where feature_id IN (36);
SHOW CREATE TABLE opportunity_contacts;
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '111751';
# $slug = 'HUBSPOT_WEBHOOK_SYNC';
# $team = Jiminny\Models\Team::find(2);
# $feature = Feature::query()->where('slug', $slug)->first();
# TeamFeature::query()->create(['feature_id' => $feature->getId(),'team_id' => $team->getId()]);
# hubspot_webhook_metrics
select * from opportunities where team_id = 2 and crm_provider_id IN ('374720564','14527423589','49908861993','50435771779'); # 1365
SELECT * FROM opportunity_contacts WHERE opportunity_id = '414';
SELECT * FROM opportunity_contacts WHERE crm_provider_id = '131501';
select * from contacts where id in (414, 464);
select * from activities where crm_configuration_id = 2;
select settings from crm_configurations where id = 11;
select * from teams; # 1, 2
select * from users;
select * from crm_configurations where id = 39;
select * from team_features where team_id = 2;
select * from features;
# SELECT * FROM opportunities WHERE crm_configuration_id = 2
# order by id desc;
# and crm_provider_id = '49908861993';
select * from activity_providers where id IN (443, 202, 203, 227);
select * from activity_imports where id = 795889;
select c.id, c.provider, c.settings, t.* from teams t join crm_configurations c on t.id = c.team_id
where c.provider = 'hubspot';
select * from crm_configurations crm JOIN teams t on crm.team_id = t.id
where provider = 'hubspot';
SELECT * FROM teams WHERE id = 31;
SELECT * FROM users WHERE id = 257;
SELECT * FROM opportunities WHERE team_id = 2;
select * from opportunity_contacts where opportunity_id = 5124;
select * from contacts where id IN (3850,3853,3851,4073,4140,4155,4480,4530,4623,5986,513,687,1806,1523,3613)
select * from activities where crm_configuration_id = 13;
SELECT * FROM activities WHERE uuid_to_bin('826619ce-ec8e-4e59-8467-a01f5f6ad71e') = uuid; # 418141
select id, team_id, crm_provider_id from crm_configurations where provider = 'hubspot' and crm_provider_id IS NOT NULL;
SELECT * FROM accounts WHERE team_id = 2 and crm_provider_id = '1212213464' order by id desc;
SELECT * FROM contacts WHERE team_id = 2 and account_id = 5189 order by id desc;
SELECT * FROM contacts WHERE team_id = 2 order by id desc;
select * from opportunity_contacts where contact_id = 6223;
SELECT * FROM opportunities WHERE team_id = 2 and account_id = 5189 order by id desc;
select * from crm_profiles where crm_configuration_id = 2;
select * from activities where account_id = 46;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
55387
|
NULL
|
0
|
2026-04-20T09:48:22.519528+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776678502519_m2.jpg...
|
Firefox
|
JY-20553 | Improve crm-sync delays by yalokin-jimi JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app — Work...
|
True
|
github.com/jiminny/app/pull/11976/changes#diff-f61 github.com/jiminny/app/pull/11976/changes#diff-f61f95a9f65b327dc254e0f402ef96bbeb6fcf71d4ea965e367f2e99ff4a6333...
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
Close tab
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
[JY-20543] AJ Reports > Tracking - Jira
[JY-20543] AJ Reports > Tracking - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira
Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app
Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app
New Tab
New Tab
Product Growth Platform | Userpilot
Product Growth Platform | Userpilot
Userpilot | Logged-activity
Userpilot | Logged-activity
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Feed — jiminny — Sentry
Feed — jiminny — Sentry
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Copy prompt
You said checkout to remote branch
You said
checkout to remote branch
Listen
Show more options
Show thinking
Gemini said
Gemini said
Here is the standard way to check out a remote branch in Git.
Step 1: Fetch the latest remote branches
Step 1: Fetch the latest remote branches
Before checking out, it is best practice to ensure your local repository knows about the latest branches on the remote. Run:
Bash
Copy code
git fetch
Step 2: Check out the branch
Step 2: Check out the branch
You have a few options depending on your version of Git and whether you want to use the exact same name as the remote branch.
Option A: The simplest way (Recommended)
Option A: The simplest way (Recommended)
If the remote branch exists and you don't have a local branch with the same name, Git will automatically create the local branch and set it up to track the remote one.
Using the newer
switch
command:
Bash
Copy code
git switch <branch-name>
Or using the traditional
checkout
command:
Bash
Copy code
git checkout <branch-name>
(Note: Do not include
origin/
in this command. Just use the branch name, e.g.,
git checkout feature-branch
)
Option B: The explicit way
Option B: The explicit way
If Option A doesn't work (for example, if you have multiple remotes), or if you want to give your local branch a
different name
than the remote branch, you can explicitly map them:
Bash
Copy code
git checkout -b <your-local-branch-name> origin/<remote-branch-name>
How to verify it worked
How to verify it worked
To confirm you are on the right branch and tracking the remote properly, run:
Bash
Copy code
git branch -vv
This will list your local branches, highlight your current branch, and show which remote branch it is tracking (e.g.,
[origin/<branch-name>]
).
Copy prompt
Edit
You said lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git fetch lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git checkout -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $
You said
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git fetch
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays
fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git checkout -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays
fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $
Expand
Listen
Show more options
Show thinking
Gemini said
Gemini said
Ah, it looks like just a tiny typo! You spelled
origin
as
orign
in your commands.
Git is throwing that error because it can't find a remote named "orign".
Here is the corrected command:
Bash
Copy code
git checkout -b JY-20553-debug-crm-sync-delays origin/JY-20553-debug-crm-sync-delays
An Easier Shortcut
An Easier Shortcut
Since your local branch name matches the remote branch exactly, you can actually skip the
-b
and
origin/
entirely. Git is smart enough to figure it out automatically:
Bash
Copy code
git checkout JY-20553-debug-crm-sync-delays
(Or if
co
is your alias for checkout, just
co JY-20553-debug-crm-sync-delays
will work!)
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Microphone
Your Jiminny chats aren’t used to improve our models. Gemini is AI and can make mistakes, including about people.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
Issues(g then i)
Pull requests
Repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (22)
Security and quality
(
22
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20553 | Improve crm-sync delays #11976 Edit title
JY-20553 | Improve crm-sync delays
#
11976
Edit title
Preview
Preview
Checks pending
Checks pending
Code
Code
Open
yalokin-jiminny
yalokin-jiminny
wants to merge 21 commits into
master
master
from
JY-20553-debug-crm-sync-delays
JY-20553-debug-crm-sync-delays
Copy head branch name to clipboard
Lines changed: 907 additions & 132 deletions
Conversation (5)
Conversation
(
5
)
Commits (21)
Commits
(
21
)
Checks (2)
Checks
(
2
)
Files changed (14)
Files changed
(
14
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
Open
JY-20553 | Improve crm-sync delays
JY-20553 | Improve crm-sync delays
#
11976
All commits
All commits
yalokin-jiminny
yalokin-jiminny
wants to merge 21 commits into
master
master
from
JY-20553-debug-crm-sync-delays
JY-20553-debug-crm-sync-delays
Copy head branch name to clipboard
6
/
14
viewed
Checks pending
Checks pending
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel
(
0
)
Filter files…
Filter options
File tree
File tree
app
Console/Commands/Crm
SyncObjects.php
SyncObjects.php
Http/Controllers
Internal/WebhookReceiver
HubspotController.php
HubspotController.php
Webhook/Hubspot
EventsController.php
EventsController.php
ProcessesWebhooksTrait.php
ProcessesWebhooksTrait.php
Jobs/Crm
SyncObjects.php
SyncObjects.php
SyncOpportunitiesJob.php
SyncOpportunitiesJob.php
Services/Crm
Hubspot/ServiceTraits
OpportunitySyncTrait.php
OpportunitySyncTrait.php
BaseService.php
BaseService.php
tests
Feature/Services/Crm
BaseServiceTest.php
BaseServiceTest.php
Unit
Http/Controllers/Webhook/Hubspot
ProcessesWebhooksTraitTest.php
ProcessesWebhooksTraitTest.php
Jobs/Crm
SyncObjectsTest.php
SyncObjectsTest.php
SyncOpportunitiesJobTest.php
SyncOpportunitiesJobTest.php
Services/Crm/Hubspot/ServiceTraits
OpportunitySyncTest.php
OpportunitySyncTest.php
OpportunitySyncTraitSyncOpportunitiesTest.php
OpportunitySyncTraitSyncOpportunitiesTest.php
Expand file
app/Console/Commands/Crm/SyncObjects.php
app/Console/Commands/Crm/SyncObjects.php
app/Console/Commands/Crm/SyncObjects.php
Copy file name to clipboard
Expand all lines: app/Console/Commands/Crm/SyncObjects.php
Lines changed: 22 additions & 12 deletions
Viewed
Viewed
Comment on this file
More options
Expand file
app/Http/Controllers/Internal/WebhookReceiver/HubspotController.php
app/Http/Controllers/Internal/WebhookReceiver/HubspotController.php
app/Http/Controllers/Internal/WebhookReceiver/HubspotController.php
Copy file name to clipboard
Expand all lines: app/Http/Controllers/Internal/WebhookReceiver/HubspotController.php
Lines changed: 3 additions & 2 deletions
Viewed
Viewed
Comment on this file
More options
Expand file
app/Http/Controllers/Webhook/Hubspot/EventsController.php
app/Http/Controllers/Webhook/Hubspot/EventsController.php
app/Http/Controllers/Webhook/Hubspot/EventsController.php
Copy file name to clipboard
Expand all lines: app/Http/Controllers/Webhook/Hubspot/EventsController.php
Lines changed: 1 addition & 5 deletions
Viewed
Viewed
Comment on this file
More options
Expand file
app/Http/Controllers/Webhook/Hubspot/ProcessesWebhooksTrait.php
app/Http/Controllers/Webhook/Hubspot/ProcessesWebhooksTrait.php
app/Http/Controllers/Webhook/Hubspot/ProcessesWebhooksTrait.php
Copy file name to clipboard
Expand all lines: app/Http/Controllers/Webhook/Hubspot/ProcessesWebhooksTrait.php
Lines changed: 63 additions & 12 deletions
Viewed
Viewed
Comment on this file
More options
Expand file
app/Jobs/Crm/SyncObjects.php
app/Jobs/Crm/SyncObjects.php
app/Jobs/Crm/SyncObjects.php
Copy file name to clipboard
Expand all lines: app/Jobs/Crm/SyncObjects.php
Lines changed: 23 additions & 15 deletions
Viewed
Viewed
Comment on this file
More options
Expand file
app/Jobs/Crm/SyncOpportunitiesJob.php
app/Jobs/Crm/SyncOpportunitiesJob.php
app/Jobs/Crm/SyncOpportunitiesJob.php
Copy file name to clipboard
Expand all lines: app/Jobs/Crm/SyncOpportunitiesJob.php
Lines changed: 11 additions & 1 deletion
Viewed
Viewed
Comment on this file
More options
Collapse file
app/Services/Crm/Hubspot/ServiceTraits/OpportunitySyncTrait.php
app/Services/Crm/Hubspot/ServiceTraits/OpportunitySyncTrait.php
app/Services/Crm/Hubspot/ServiceTraits/OpportunitySyncTrait.php
Copy file name to clipboard
Expand all lines: app/Services/Crm/Hubspot/ServiceTraits/OpportunitySyncTrait.php
Lines changed: 11 additions & 6 deletions
Not Viewed
Viewed
Comment on this file
More options
Original file line number
Original file line
Diff line number
Diff line change
@@ -43,17 +43,20 @@ trait OpportunitySyncTrait
43
43
44
public
function
syncOpportunities
(
array
$
parameters
, ?
string
$
strategy
=
null
):
int
44
public
function
syncOpportunities
(
array
$
parameters
, ?
string
$
strategy
=
null
):
int
45
{
45
{...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0018284575,"top":0.0518755,"width":0.07596409,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.09497207,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.10614525,"width":0.15774602,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.10215483,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6793] Les Mills activity types not pulling in - Jira","depth":4,"bounds":{"left":0.0,"top":0.12769353,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6793] Les Mills activity types not pulling in - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.13886672,"width":0.09524601,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.16041501,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.17158818,"width":0.19963431,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.19313647,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.20430966,"width":0.15525267,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20543] AJ Reports > Tracking - Jira","depth":4,"bounds":{"left":0.0,"top":0.22585794,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20543] AJ Reports > Tracking - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.23703113,"width":0.06981383,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira","depth":4,"bounds":{"left":0.0,"top":0.2585794,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.2697526,"width":0.10688165,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.29130086,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.30247405,"width":0.12915559,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.0,"top":0.32402235,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.013297873,"top":0.33519554,"width":0.014960106,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Product Growth Platform | Userpilot","depth":4,"bounds":{"left":0.0,"top":0.3567438,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Product Growth Platform | Userpilot","depth":5,"bounds":{"left":0.013297873,"top":0.367917,"width":0.06200133,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Logged-activity","depth":4,"bounds":{"left":0.0,"top":0.38946527,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Logged-activity","depth":5,"bounds":{"left":0.013297873,"top":0.40063846,"width":0.04637633,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.42218676,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.43335995,"width":0.2052859,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.45490822,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.4660814,"width":0.039228722,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Feed — jiminny — Sentry","depth":4,"bounds":{"left":0.0,"top":0.48762968,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Feed — jiminny — Sentry","depth":5,"bounds":{"left":0.013297873,"top":0.49880287,"width":0.042719416,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.5203512,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.53152436,"width":0.2052859,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.55307263,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.5642458,"width":0.013131649,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.5857941,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.5969673,"width":0.013131649,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.61851555,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.62968874,"width":0.013131649,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.6528332,"width":0.07413564,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.18733378,"top":0.055067837,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.19930187,"top":0.055067837,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.29039228,"top":0.103751,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08361037,"top":0.103751,"width":0.013297873,"height":0.031923383},"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09690824,"top":0.10454908,"width":0.028590426,"height":0.030327214},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.099567816,"top":0.10973663,"width":0.021941489,"height":0.020351157},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"bounds":{"left":0.26246676,"top":0.103751,"width":0.013297873,"height":0.031923383},"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"bounds":{"left":0.2757646,"top":0.103751,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":21,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said checkout to remote branch","depth":21,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"checkout to remote branch","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":26,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is the standard way to check out a remote branch in Git.","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Step 1: Fetch the latest remote branches","depth":23,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Step 1: Fetch the latest remote branches","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Before checking out, it is best practice to ensure your local repository knows about the latest branches on the remote. Run:","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bash","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy code","depth":25,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"git fetch","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Step 2: Check out the branch","depth":23,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Step 2: Check out the branch","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You have a few options depending on your version of Git and whether you want to use the exact same name as the remote branch.","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Option A: The simplest way (Recommended)","depth":23,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Option A: The simplest way (Recommended)","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the remote branch exists and you don't have a local branch with the same name, Git will automatically create the local branch and set it up to track the remote one.","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Using the newer","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"switch","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"command:","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bash","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy code","depth":25,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"git switch <branch-name>","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Or using the traditional","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"checkout","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"command:","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bash","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy code","depth":25,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"git checkout <branch-name>","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(Note: Do not include","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"origin/","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"in this command. Just use the branch name, e.g.,","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"git checkout feature-branch","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Option B: The explicit way","depth":23,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Option B: The explicit way","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If Option A doesn't work (for example, if you have multiple remotes), or if you want to give your local branch a","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"different name","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"than the remote branch, you can explicitly map them:","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bash","depth":25,"bounds":{"left":0.09358378,"top":0.0,"width":0.010804521,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy code","depth":25,"bounds":{"left":0.28507313,"top":0.0,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"git checkout -b <your-local-branch-name> origin/<remote-branch-name>","depth":25,"bounds":{"left":0.09358378,"top":0.0,"width":0.18982713,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How to verify it worked","depth":23,"bounds":{"left":0.08826463,"top":0.002793296,"width":0.21276596,"height":0.01915403},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How to verify it worked","depth":24,"bounds":{"left":0.08826463,"top":0.0043894653,"width":0.060339097,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To confirm you are on the right branch and tracking the remote properly, run:","depth":24,"bounds":{"left":0.08826463,"top":0.030726258,"width":0.18550532,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bash","depth":25,"bounds":{"left":0.09358378,"top":0.11612131,"width":0.010804521,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy code","depth":25,"bounds":{"left":0.28507313,"top":0.10694334,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"git branch -vv","depth":25,"bounds":{"left":0.09358378,"top":0.11572227,"width":0.0390625,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"This will list your local branches, highlight your current branch, and show which remote branch it is tracking (e.g.,","depth":24,"bounds":{"left":0.08826463,"top":0.15921788,"width":0.21027261,"height":0.037110932},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[origin/<branch-name>]","depth":25,"bounds":{"left":0.15275931,"top":0.1811652,"width":0.061502658,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":24,"bounds":{"left":0.21625665,"top":0.17996807,"width":0.0031582448,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":21,"bounds":{"left":0.11353058,"top":0.2525938,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"bounds":{"left":0.12815824,"top":0.2525938,"width":0.013297873,"height":0.031923383},"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git fetch lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git checkout -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $","depth":21,"bounds":{"left":0.14810506,"top":0.2621708,"width":0.13696809,"height":0.11173184},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"bounds":{"left":0.079288565,"top":0.26456505,"width":0.019946808,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git fetch","depth":23,"bounds":{"left":0.14810506,"top":0.26536313,"width":0.13331117,"height":0.061053474},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays","depth":23,"bounds":{"left":0.14810506,"top":0.33240223,"width":0.13447474,"height":0.08339984},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it","depth":23,"bounds":{"left":0.14810506,"top":0.37709498,"width":0.13314494,"height":0.061053474},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git checkout -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays","depth":23,"bounds":{"left":0.14810506,"top":0.4441341,"width":0.13331117,"height":0.08339984},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it","depth":23,"bounds":{"left":0.14810506,"top":0.53351957,"width":0.13314494,"height":0.061053474},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $","depth":23,"bounds":{"left":0.14810506,"top":0.60055864,"width":0.13331117,"height":0.038707104},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"bounds":{"left":0.28507313,"top":0.2621708,"width":0.013297873,"height":0.031923383},"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Listen","depth":22,"bounds":{"left":0.29039228,"top":0.40582603,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"bounds":{"left":0.29039228,"top":0.40023944,"width":0.013297873,"height":0.031923383},"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":26,"bounds":{"left":0.1015625,"top":0.40822026,"width":0.030917553,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"bounds":{"left":0.09923537,"top":0.44972068,"width":0.0003324468,"height":0.0007980846},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"bounds":{"left":0.09923537,"top":0.4517159,"width":0.04105718,"height":0.01915403},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ah, it looks like just a tiny typo! You spelled","depth":24,"bounds":{"left":0.08826463,"top":0.4592977,"width":0.10388963,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"origin","depth":25,"bounds":{"left":0.19414894,"top":0.46049482,"width":0.016788565,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"as","depth":24,"bounds":{"left":0.21293218,"top":0.4592977,"width":0.008144947,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"orign","depth":25,"bounds":{"left":0.22307181,"top":0.46049482,"width":0.013962766,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"in your commands.","depth":24,"bounds":{"left":0.23902926,"top":0.4592977,"width":0.047041222,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Git is throwing that error because it can't find a remote named \"orign\".","depth":24,"bounds":{"left":0.08826463,"top":0.49281725,"width":0.17004654,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is the corrected command:","depth":24,"bounds":{"left":0.08826463,"top":0.5263368,"width":0.077792555,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bash","depth":25,"bounds":{"left":0.09358378,"top":0.56943333,"width":0.010804521,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy code","depth":25,"bounds":{"left":0.28507313,"top":0.5602554,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"git checkout -b JY-20553-debug-crm-sync-delays origin/JY-20553-debug-crm-sync-delays","depth":25,"bounds":{"left":0.09358378,"top":0.6113328,"width":0.23454122,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"An Easier Shortcut","depth":23,"bounds":{"left":0.08826463,"top":0.66201115,"width":0.21276596,"height":0.01915403},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"An Easier Shortcut","depth":24,"bounds":{"left":0.08826463,"top":0.66360736,"width":0.04837101,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Since your local branch name matches the remote branch exactly, you can actually skip the","depth":24,"bounds":{"left":0.08826463,"top":0.68994415,"width":0.21210106,"height":0.037110932},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-b","depth":25,"bounds":{"left":0.099567816,"top":0.7118915,"width":0.0056515955,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":24,"bounds":{"left":0.10721409,"top":0.7106943,"width":0.011801862,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"origin/","depth":25,"bounds":{"left":0.12101064,"top":0.7118915,"width":0.019614361,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entirely. Git is smart enough to figure it out automatically:","depth":24,"bounds":{"left":0.14261968,"top":0.7106943,"width":0.13912898,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bash","depth":25,"bounds":{"left":0.09358378,"top":0.7537909,"width":0.010804521,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy code","depth":25,"bounds":{"left":0.28507313,"top":0.74461293,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"git checkout JY-20553-debug-crm-sync-delays","depth":25,"bounds":{"left":0.09358378,"top":0.79569036,"width":0.1200133,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(Or if","depth":24,"bounds":{"left":0.08826463,"top":0.83918595,"width":0.013962766,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"co","depth":25,"bounds":{"left":0.104222074,"top":0.84038305,"width":0.005485372,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is your alias for checkout, just","depth":24,"bounds":{"left":0.11170213,"top":0.83918595,"width":0.07446808,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"co JY-20553-debug-crm-sync-delays","depth":25,"bounds":{"left":0.18816489,"top":0.84038305,"width":0.09208777,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"will work!)","depth":24,"bounds":{"left":0.08826463,"top":0.83918595,"width":0.20428856,"height":0.037110932},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextArea","text":"Enter a prompt for Gemini\nencrypted","depth":20,"bounds":{"left":0.09291888,"top":0.82322425,"width":0.20279256,"height":0.01915403},"value":"Enter a prompt for Gemini\nencrypted","help_text":"","role_description":"text entry area","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enter a prompt for Gemini","depth":21,"bounds":{"left":0.099567816,"top":0.46089387,"width":0.069980055,"height":0.018355945},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"encrypted","depth":21,"bounds":{"left":0.091921546,"top":0.46049482,"width":0.0066489363,"height":0.01915403},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open upload file menu","depth":20,"bounds":{"left":0.08892952,"top":0.8575419,"width":0.013297873,"height":0.031923383},"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tools","depth":18,"bounds":{"left":0.10488697,"top":0.8575419,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open mode picker","depth":20,"bounds":{"left":0.25831118,"top":0.8567438,"width":0.026097074,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pro","depth":23,"bounds":{"left":0.26363033,"top":0.86552274,"width":0.007480053,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Microphone","depth":19,"bounds":{"left":0.2864029,"top":0.8567438,"width":0.013297873,"height":0.031923383},"role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your Jiminny chats aren’t used to improve our models. Gemini is AI and can make mistakes, including about people.","depth":17,"bounds":{"left":0.0887633,"top":0.90901834,"width":0.21110372,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Your privacy & Gemini Opens in a new window","depth":17,"bounds":{"left":0.17420213,"top":0.92178774,"width":0.040226065,"height":0.012370312},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your privacy & Gemini","depth":18,"bounds":{"left":0.17420213,"top":0.92178774,"width":0.040226065,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Opens in a new window","depth":19,"bounds":{"left":0.079288565,"top":0.92098963,"width":0.043218084,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Summarize page","depth":7,"bounds":{"left":0.08494016,"top":0.95730245,"width":0.053523935,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summarize page","depth":9,"bounds":{"left":0.09059176,"top":0.96249,"width":0.042220745,"height":0.015163607},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Skip to content","depth":6,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open menu","depth":10,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Homepage (g then d)","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"jiminny","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"app","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Type","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to search","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chat with Copilot","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Open Copilot…","depth":9,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Create new...","depth":9,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Issues(g then i)","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Pull requests","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Repositories","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"You have unread notifications(g then n)","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open user navigation menu","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Repository navigation","depth":9,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repository navigation","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests (31)","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"31","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Agents","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Agents","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Wiki","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wiki","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality (22)","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":10,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review this update","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub account settings","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"JY-20553 | Improve crm-sync delays #11976 Edit title","depth":13,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20553 | Improve crm-sync delays","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11976","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit title","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Preview","depth":13,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Preview","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Checks pending","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks pending","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Code","depth":13,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Code","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"yalokin-jiminny","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"yalokin-jiminny","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 21 commits into","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20553-debug-crm-sync-delays","depth":16,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20553-debug-crm-sync-delays","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 907 additions & 132 deletions","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Conversation (5)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Conversation","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Commits (21)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Commits","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"21","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Checks (2)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Files changed (14)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Files changed","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull Request Toolbar","depth":14,"bounds":{"left":0.3224734,"top":0.07581804,"width":0.0003324468,"height":0.0007980846},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull Request Toolbar","depth":15,"bounds":{"left":0.3224734,"top":0.07861133,"width":0.030086435,"height":0.08060654},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse file tree","depth":14,"bounds":{"left":0.3224734,"top":0.0650439,"width":0.00930851,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Open","depth":14,"bounds":{"left":0.34507978,"top":0.06943336,"width":0.011968086,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20553 | Improve crm-sync delays","depth":14,"bounds":{"left":0.3636968,"top":0.058260176,"width":0.08294548,"height":0.016759777},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20553 | Improve crm-sync delays","depth":16,"bounds":{"left":0.3636968,"top":0.059856344,"width":0.08294548,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"bounds":{"left":0.44930187,"top":0.059856344,"width":0.0029920214,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11976","depth":15,"bounds":{"left":0.45229387,"top":0.059856344,"width":0.012466756,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"All commits","depth":14,"bounds":{"left":0.36103722,"top":0.07182761,"width":0.03374335,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All commits","depth":16,"bounds":{"left":0.36402926,"top":0.07701516,"width":0.02244016,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"yalokin-jiminny","depth":15,"bounds":{"left":0.3991024,"top":0.07581804,"width":0.029920213,"height":0.014365523},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"yalokin-jiminny","depth":16,"bounds":{"left":0.3991024,"top":0.07701516,"width":0.029920213,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 21 commits into","depth":15,"bounds":{"left":0.4303524,"top":0.07701516,"width":0.059674203,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"bounds":{"left":0.49135637,"top":0.074221864,"width":0.018450798,"height":0.017557861},"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"bounds":{"left":0.49335107,"top":0.07741421,"width":0.014461436,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"bounds":{"left":0.51113695,"top":0.07701516,"width":0.008643617,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20553-debug-crm-sync-delays","depth":16,"bounds":{"left":0.52111036,"top":0.074221864,"width":0.07596409,"height":0.017557861},"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20553-debug-crm-sync-delays","depth":17,"bounds":{"left":0.523105,"top":0.07741421,"width":0.07197473,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"bounds":{"left":0.5984042,"top":0.07182761,"width":0.00930851,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"6","depth":15,"bounds":{"left":0.8231383,"top":0.070231445,"width":0.002493351,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":15,"bounds":{"left":0.8256317,"top":0.070231445,"width":0.0023271276,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14","depth":15,"bounds":{"left":0.82912236,"top":0.070231445,"width":0.004654255,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"viewed","depth":15,"bounds":{"left":0.83477396,"top":0.070231445,"width":0.013297873,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Checks pending","depth":14,"bounds":{"left":0.85638297,"top":0.0650439,"width":0.04338431,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks pending","depth":16,"bounds":{"left":0.86602396,"top":0.070231445,"width":0.030751329,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Submit review","depth":14,"bounds":{"left":0.90242684,"top":0.0650439,"width":0.03856383,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Submit","depth":16,"bounds":{"left":0.9054189,"top":0.070231445,"width":0.014793883,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"review","depth":16,"bounds":{"left":0.92021275,"top":0.070231445,"width":0.012466756,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Open diff view settings","depth":14,"bounds":{"left":0.94365025,"top":0.0650439,"width":0.00930851,"height":0.022346368},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open overview panel","depth":14,"bounds":{"left":0.96127,"top":0.0650439,"width":0.00930851,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open comments panel","depth":14,"bounds":{"left":0.9719083,"top":0.0650439,"width":0.017287234,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"(","depth":16,"bounds":{"left":0.9802194,"top":0.070231445,"width":0.0026595744,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"bounds":{"left":0.982879,"top":0.070231445,"width":0.0026595744,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":16,"bounds":{"left":0.98553854,"top":0.070231445,"width":0.0014960107,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Filter files…","depth":16,"bounds":{"left":0.3337766,"top":0.11332801,"width":0.06815159,"height":0.023942538},"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Filter options","depth":16,"bounds":{"left":0.40492022,"top":0.112529926,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"File tree","depth":15,"bounds":{"left":0.32280585,"top":0.15083799,"width":0.0003324468,"height":0.0007980846},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"File tree","depth":16,"bounds":{"left":0.32280585,"top":0.15363128,"width":0.014295213,"height":0.0518755},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":19,"bounds":{"left":0.3387633,"top":0.15682362,"width":0.008144947,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Console/Commands/Crm","depth":21,"bounds":{"left":0.3414229,"top":0.18276137,"width":0.053690158,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SyncObjects.php","depth":23,"bounds":{"left":0.34408244,"top":0.20830008,"width":0.036901597,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SyncObjects.php","depth":24,"bounds":{"left":0.34408244,"top":0.20830008,"width":0.036901597,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Http/Controllers","depth":21,"bounds":{"left":0.3414229,"top":0.23383878,"width":0.034408245,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Internal/WebhookReceiver","depth":23,"bounds":{"left":0.34408244,"top":0.25937748,"width":0.05618351,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"HubspotController.php","depth":25,"bounds":{"left":0.34674203,"top":0.28531525,"width":0.04886968,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"HubspotController.php","depth":26,"bounds":{"left":0.34674203,"top":0.28531525,"width":0.04886968,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Webhook/Hubspot","depth":23,"bounds":{"left":0.34408244,"top":0.31085396,"width":0.039893616,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"EventsController.php","depth":25,"bounds":{"left":0.34674203,"top":0.33639267,"width":0.04488032,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"EventsController.php","depth":26,"bounds":{"left":0.34674203,"top":0.33639267,"width":0.04488032,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ProcessesWebhooksTrait.php","depth":25,"bounds":{"left":0.34674203,"top":0.36193135,"width":0.06333112,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ProcessesWebhooksTrait.php","depth":26,"bounds":{"left":0.34674203,"top":0.36193135,"width":0.06333112,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jobs/Crm","depth":21,"bounds":{"left":0.3414229,"top":0.38786912,"width":0.020777926,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SyncObjects.php","depth":23,"bounds":{"left":0.34408244,"top":0.41340783,"width":0.036901597,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SyncObjects.php","depth":24,"bounds":{"left":0.34408244,"top":0.41340783,"width":0.036901597,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SyncOpportunitiesJob.php","depth":23,"bounds":{"left":0.34408244,"top":0.43894652,"width":0.057513297,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SyncOpportunitiesJob.php","depth":24,"bounds":{"left":0.34408244,"top":0.43894652,"width":0.057513297,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Services/Crm","depth":21,"bounds":{"left":0.3414229,"top":0.46448523,"width":0.028756648,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Hubspot/ServiceTraits","depth":23,"bounds":{"left":0.34408244,"top":0.49002394,"width":0.04720745,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"OpportunitySyncTrait.php","depth":25,"bounds":{"left":0.34674203,"top":0.5159617,"width":0.05518617,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"OpportunitySyncTrait.php","depth":26,"bounds":{"left":0.34674203,"top":0.5159617,"width":0.05518617,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"BaseService.php","depth":23,"bounds":{"left":0.34408244,"top":0.5415004,"width":0.036070477,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BaseService.php","depth":24,"bounds":{"left":0.34408244,"top":0.5415004,"width":0.036070477,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"tests","depth":19,"bounds":{"left":0.3387633,"top":0.56703913,"width":0.010638298,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Feature/Services/Crm","depth":21,"bounds":{"left":0.3414229,"top":0.5925778,"width":0.04654255,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"BaseServiceTest.php","depth":23,"bounds":{"left":0.34408244,"top":0.61851555,"width":0.044714097,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BaseServiceTest.php","depth":24,"bounds":{"left":0.34408244,"top":0.61851555,"width":0.044714097,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unit","depth":21,"bounds":{"left":0.3414229,"top":0.6440543,"width":0.00880984,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Http/Controllers/Webhook/Hubspot","depth":23,"bounds":{"left":0.34408244,"top":0.669593,"width":0.07579787,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ProcessesWebhooksTraitTest.php","depth":25,"bounds":{"left":0.34674203,"top":0.69513166,"width":0.072140954,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ProcessesWebhooksTraitTest.php","depth":26,"bounds":{"left":0.34674203,"top":0.69513166,"width":0.072140954,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jobs/Crm","depth":23,"bounds":{"left":0.34408244,"top":0.7206704,"width":0.020777926,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SyncObjectsTest.php","depth":25,"bounds":{"left":0.34674203,"top":0.74660814,"width":0.045545213,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SyncObjectsTest.php","depth":26,"bounds":{"left":0.34674203,"top":0.74660814,"width":0.045545213,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SyncOpportunitiesJobTest.php","depth":25,"bounds":{"left":0.34674203,"top":0.7721468,"width":0.06615692,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SyncOpportunitiesJobTest.php","depth":26,"bounds":{"left":0.34674203,"top":0.7721468,"width":0.06615692,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Services/Crm/Hubspot/ServiceTraits","depth":23,"bounds":{"left":0.34408244,"top":0.79768556,"width":0.0774601,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"OpportunitySyncTest.php","depth":25,"bounds":{"left":0.34674203,"top":0.82322425,"width":0.0546875,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"OpportunitySyncTest.php","depth":26,"bounds":{"left":0.34674203,"top":0.82322425,"width":0.0546875,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"OpportunitySyncTraitSyncOpportunitiesTest.php","depth":25,"bounds":{"left":0.34674203,"top":0.848763,"width":0.10405585,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"OpportunitySyncTraitSyncOpportunitiesTest.php","depth":26,"bounds":{"left":0.34674203,"top":0.848763,"width":0.10405585,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand file","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"app/Console/Commands/Crm/SyncObjects.php","depth":15,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"app/Console/Commands/Crm/SyncObjects.php","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app/Console/Commands/Crm/SyncObjects.php","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy file name to clipboard","depth":15,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Expand all lines: app/Console/Commands/Crm/SyncObjects.php","depth":15,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 22 additions & 12 deletions","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Viewed","depth":14,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Viewed","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Comment on this file","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"More options","depth":14,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand file","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"app/Http/Controllers/Internal/WebhookReceiver/HubspotController.php","depth":15,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"app/Http/Controllers/Internal/WebhookReceiver/HubspotController.php","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app/Http/Controllers/Internal/WebhookReceiver/HubspotController.php","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy file name to clipboard","depth":15,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Expand all lines: app/Http/Controllers/Internal/WebhookReceiver/HubspotController.php","depth":15,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 3 additions & 2 deletions","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Viewed","depth":14,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Viewed","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Comment on this file","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"More options","depth":14,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand file","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"app/Http/Controllers/Webhook/Hubspot/EventsController.php","depth":15,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"app/Http/Controllers/Webhook/Hubspot/EventsController.php","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app/Http/Controllers/Webhook/Hubspot/EventsController.php","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy file name to clipboard","depth":15,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Expand all lines: app/Http/Controllers/Webhook/Hubspot/EventsController.php","depth":15,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 1 addition & 5 deletions","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Viewed","depth":14,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Viewed","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Comment on this file","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"More options","depth":14,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand file","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"app/Http/Controllers/Webhook/Hubspot/ProcessesWebhooksTrait.php","depth":15,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"app/Http/Controllers/Webhook/Hubspot/ProcessesWebhooksTrait.php","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app/Http/Controllers/Webhook/Hubspot/ProcessesWebhooksTrait.php","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy file name to clipboard","depth":15,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Expand all lines: app/Http/Controllers/Webhook/Hubspot/ProcessesWebhooksTrait.php","depth":15,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 63 additions & 12 deletions","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Viewed","depth":14,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Viewed","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Comment on this file","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"More options","depth":14,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand file","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"app/Jobs/Crm/SyncObjects.php","depth":15,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"app/Jobs/Crm/SyncObjects.php","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app/Jobs/Crm/SyncObjects.php","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy file name to clipboard","depth":15,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Expand all lines: app/Jobs/Crm/SyncObjects.php","depth":15,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 23 additions & 15 deletions","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Viewed","depth":14,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Viewed","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Comment on this file","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"More options","depth":14,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand file","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"app/Jobs/Crm/SyncOpportunitiesJob.php","depth":15,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"app/Jobs/Crm/SyncOpportunitiesJob.php","depth":16,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app/Jobs/Crm/SyncOpportunitiesJob.php","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy file name to clipboard","depth":15,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Expand all lines: app/Jobs/Crm/SyncOpportunitiesJob.php","depth":15,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 11 additions & 1 deletion","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Viewed","depth":14,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"Viewed","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Comment on this file","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"More options","depth":14,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse file","depth":14,"bounds":{"left":0.42952126,"top":0.103751,"width":0.00930851,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"app/Services/Crm/Hubspot/ServiceTraits/OpportunitySyncTrait.php","depth":15,"bounds":{"left":0.4401596,"top":0.10654429,"width":0.15109707,"height":0.016759777},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXLink","text":"app/Services/Crm/Hubspot/ServiceTraits/OpportunitySyncTrait.php","depth":16,"bounds":{"left":0.4401596,"top":0.10814046,"width":0.15109707,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app/Services/Crm/Hubspot/ServiceTraits/OpportunitySyncTrait.php","depth":18,"bounds":{"left":0.4401596,"top":0.110135674,"width":0.15109707,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy file name to clipboard","depth":15,"bounds":{"left":0.59391624,"top":0.103751,"width":0.00930851,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Expand all lines: app/Services/Crm/Hubspot/ServiceTraits/OpportunitySyncTrait.php","depth":15,"bounds":{"left":0.60322475,"top":0.103751,"width":0.00930851,"height":0.022346368},"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 11 additions & 6 deletions","depth":15,"bounds":{"left":0.90425533,"top":0.11612131,"width":0.019946808,"height":0.11412609},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Not Viewed","depth":14,"bounds":{"left":0.93567157,"top":0.103751,"width":0.026595745,"height":0.022346368},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Viewed","depth":16,"bounds":{"left":0.9453125,"top":0.108938545,"width":0.013962766,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Comment on this file","depth":14,"bounds":{"left":0.96492684,"top":0.103751,"width":0.00930851,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"More options","depth":14,"bounds":{"left":0.976895,"top":0.103751,"width":0.00930851,"height":0.022346368},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Original file line number","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Original file line","depth":17,"bounds":{"left":0.44481382,"top":0.0,"width":0.018118352,"height":0.030327214},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Diff line number","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Diff line change","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"@@ -43,17 +43,20 @@ trait OpportunitySyncTrait","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"43","depth":16,"bounds":{"left":0.4331782,"top":0.0,"width":0.004654255,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"43","depth":16,"bounds":{"left":0.7140958,"top":0.0,"width":0.0048204786,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"44","depth":16,"bounds":{"left":0.4331782,"top":0.0,"width":0.004654255,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public","depth":18,"bounds":{"left":0.46176863,"top":0.0,"width":0.014295213,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"function","depth":18,"bounds":{"left":0.47855717,"top":0.0,"width":0.019115692,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"syncOpportunities","depth":18,"bounds":{"left":0.50016624,"top":0.0,"width":0.040724736,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"bounds":{"left":0.54089093,"top":0.0,"width":0.0023271276,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array","depth":18,"bounds":{"left":0.5432181,"top":0.0,"width":0.012134309,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"bounds":{"left":0.55767953,"top":0.0,"width":0.002493351,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"parameters","depth":18,"bounds":{"left":0.56017286,"top":0.0,"width":0.023936171,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", ?","depth":18,"bounds":{"left":0.58410907,"top":0.0,"width":0.0071476065,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"string","depth":18,"bounds":{"left":0.5912567,"top":0.0,"width":0.014461436,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"bounds":{"left":0.6080452,"top":0.0,"width":0.002493351,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"strategy","depth":18,"bounds":{"left":0.61053854,"top":0.0,"width":0.019115692,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":18,"bounds":{"left":0.6296542,"top":0.0,"width":0.0071476065,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"null","depth":18,"bounds":{"left":0.63680184,"top":0.0,"width":0.009640957,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"):","depth":18,"bounds":{"left":0.64644283,"top":0.0,"width":0.0071476065,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"int","depth":18,"bounds":{"left":0.65359044,"top":0.0,"width":0.00731383,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"44","depth":16,"bounds":{"left":0.7140958,"top":0.0,"width":0.0048204786,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"public","depth":18,"bounds":{"left":0.74268615,"top":0.0,"width":0.014461436,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"function","depth":18,"bounds":{"left":0.75947475,"top":0.0,"width":0.019281914,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"syncOpportunities","depth":18,"bounds":{"left":0.78108376,"top":0.0,"width":0.04089096,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"bounds":{"left":0.82197475,"top":0.0,"width":0.0023271276,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"array","depth":18,"bounds":{"left":0.82430184,"top":0.0,"width":0.011968086,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"bounds":{"left":0.8387633,"top":0.0,"width":0.0023271276,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"parameters","depth":18,"bounds":{"left":0.84109044,"top":0.0,"width":0.023936171,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":", ?","depth":18,"bounds":{"left":0.8650266,"top":0.0,"width":0.00731383,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"string","depth":18,"bounds":{"left":0.87234044,"top":0.0,"width":0.014295213,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$","depth":18,"bounds":{"left":0.889129,"top":0.0,"width":0.0023271276,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"strategy","depth":18,"bounds":{"left":0.8914561,"top":0.0,"width":0.019281914,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"=","depth":18,"bounds":{"left":0.91073805,"top":0.0,"width":0.0071476065,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"null","depth":18,"bounds":{"left":0.91788566,"top":0.0,"width":0.009640957,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"):","depth":18,"bounds":{"left":0.9275266,"top":0.0,"width":0.0071476065,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"int","depth":18,"bounds":{"left":0.9346742,"top":0.0,"width":0.0071476065,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"45","depth":16,"bounds":{"left":0.4331782,"top":0.0,"width":0.004654255,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":18,"bounds":{"left":0.45212767,"top":0.0,"width":0.011968086,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"45","depth":16,"bounds":{"left":0.7140958,"top":0.0,"width":0.0048204786,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"{","depth":18,"bounds":{"left":0.73321146,"top":0.0,"width":0.011968086,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-7681915147505659684
|
6900962689653743917
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
Close tab
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
[JY-20543] AJ Reports > Tracking - Jira
[JY-20543] AJ Reports > Tracking - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira
Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app
Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app
New Tab
New Tab
Product Growth Platform | Userpilot
Product Growth Platform | Userpilot
Userpilot | Logged-activity
Userpilot | Logged-activity
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Feed — jiminny — Sentry
Feed — jiminny — Sentry
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Copy prompt
You said checkout to remote branch
You said
checkout to remote branch
Listen
Show more options
Show thinking
Gemini said
Gemini said
Here is the standard way to check out a remote branch in Git.
Step 1: Fetch the latest remote branches
Step 1: Fetch the latest remote branches
Before checking out, it is best practice to ensure your local repository knows about the latest branches on the remote. Run:
Bash
Copy code
git fetch
Step 2: Check out the branch
Step 2: Check out the branch
You have a few options depending on your version of Git and whether you want to use the exact same name as the remote branch.
Option A: The simplest way (Recommended)
Option A: The simplest way (Recommended)
If the remote branch exists and you don't have a local branch with the same name, Git will automatically create the local branch and set it up to track the remote one.
Using the newer
switch
command:
Bash
Copy code
git switch <branch-name>
Or using the traditional
checkout
command:
Bash
Copy code
git checkout <branch-name>
(Note: Do not include
origin/
in this command. Just use the branch name, e.g.,
git checkout feature-branch
)
Option B: The explicit way
Option B: The explicit way
If Option A doesn't work (for example, if you have multiple remotes), or if you want to give your local branch a
different name
than the remote branch, you can explicitly map them:
Bash
Copy code
git checkout -b <your-local-branch-name> origin/<remote-branch-name>
How to verify it worked
How to verify it worked
To confirm you are on the right branch and tracking the remote properly, run:
Bash
Copy code
git branch -vv
This will list your local branches, highlight your current branch, and show which remote branch it is tracking (e.g.,
[origin/<branch-name>]
).
Copy prompt
Edit
You said lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git fetch lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git checkout -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $
You said
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git fetch
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays
fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git checkout -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays
fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $
Expand
Listen
Show more options
Show thinking
Gemini said
Gemini said
Ah, it looks like just a tiny typo! You spelled
origin
as
orign
in your commands.
Git is throwing that error because it can't find a remote named "orign".
Here is the corrected command:
Bash
Copy code
git checkout -b JY-20553-debug-crm-sync-delays origin/JY-20553-debug-crm-sync-delays
An Easier Shortcut
An Easier Shortcut
Since your local branch name matches the remote branch exactly, you can actually skip the
-b
and
origin/
entirely. Git is smart enough to figure it out automatically:
Bash
Copy code
git checkout JY-20553-debug-crm-sync-delays
(Or if
co
is your alias for checkout, just
co JY-20553-debug-crm-sync-delays
will work!)
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Microphone
Your Jiminny chats aren’t used to improve our models. Gemini is AI and can make mistakes, including about people.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
Issues(g then i)
Pull requests
Repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (22)
Security and quality
(
22
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20553 | Improve crm-sync delays #11976 Edit title
JY-20553 | Improve crm-sync delays
#
11976
Edit title
Preview
Preview
Checks pending
Checks pending
Code
Code
Open
yalokin-jiminny
yalokin-jiminny
wants to merge 21 commits into
master
master
from
JY-20553-debug-crm-sync-delays
JY-20553-debug-crm-sync-delays
Copy head branch name to clipboard
Lines changed: 907 additions & 132 deletions
Conversation (5)
Conversation
(
5
)
Commits (21)
Commits
(
21
)
Checks (2)
Checks
(
2
)
Files changed (14)
Files changed
(
14
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
Open
JY-20553 | Improve crm-sync delays
JY-20553 | Improve crm-sync delays
#
11976
All commits
All commits
yalokin-jiminny
yalokin-jiminny
wants to merge 21 commits into
master
master
from
JY-20553-debug-crm-sync-delays
JY-20553-debug-crm-sync-delays
Copy head branch name to clipboard
6
/
14
viewed
Checks pending
Checks pending
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel
(
0
)
Filter files…
Filter options
File tree
File tree
app
Console/Commands/Crm
SyncObjects.php
SyncObjects.php
Http/Controllers
Internal/WebhookReceiver
HubspotController.php
HubspotController.php
Webhook/Hubspot
EventsController.php
EventsController.php
ProcessesWebhooksTrait.php
ProcessesWebhooksTrait.php
Jobs/Crm
SyncObjects.php
SyncObjects.php
SyncOpportunitiesJob.php
SyncOpportunitiesJob.php
Services/Crm
Hubspot/ServiceTraits
OpportunitySyncTrait.php
OpportunitySyncTrait.php
BaseService.php
BaseService.php
tests
Feature/Services/Crm
BaseServiceTest.php
BaseServiceTest.php
Unit
Http/Controllers/Webhook/Hubspot
ProcessesWebhooksTraitTest.php
ProcessesWebhooksTraitTest.php
Jobs/Crm
SyncObjectsTest.php
SyncObjectsTest.php
SyncOpportunitiesJobTest.php
SyncOpportunitiesJobTest.php
Services/Crm/Hubspot/ServiceTraits
OpportunitySyncTest.php
OpportunitySyncTest.php
OpportunitySyncTraitSyncOpportunitiesTest.php
OpportunitySyncTraitSyncOpportunitiesTest.php
Expand file
app/Console/Commands/Crm/SyncObjects.php
app/Console/Commands/Crm/SyncObjects.php
app/Console/Commands/Crm/SyncObjects.php
Copy file name to clipboard
Expand all lines: app/Console/Commands/Crm/SyncObjects.php
Lines changed: 22 additions & 12 deletions
Viewed
Viewed
Comment on this file
More options
Expand file
app/Http/Controllers/Internal/WebhookReceiver/HubspotController.php
app/Http/Controllers/Internal/WebhookReceiver/HubspotController.php
app/Http/Controllers/Internal/WebhookReceiver/HubspotController.php
Copy file name to clipboard
Expand all lines: app/Http/Controllers/Internal/WebhookReceiver/HubspotController.php
Lines changed: 3 additions & 2 deletions
Viewed
Viewed
Comment on this file
More options
Expand file
app/Http/Controllers/Webhook/Hubspot/EventsController.php
app/Http/Controllers/Webhook/Hubspot/EventsController.php
app/Http/Controllers/Webhook/Hubspot/EventsController.php
Copy file name to clipboard
Expand all lines: app/Http/Controllers/Webhook/Hubspot/EventsController.php
Lines changed: 1 addition & 5 deletions
Viewed
Viewed
Comment on this file
More options
Expand file
app/Http/Controllers/Webhook/Hubspot/ProcessesWebhooksTrait.php
app/Http/Controllers/Webhook/Hubspot/ProcessesWebhooksTrait.php
app/Http/Controllers/Webhook/Hubspot/ProcessesWebhooksTrait.php
Copy file name to clipboard
Expand all lines: app/Http/Controllers/Webhook/Hubspot/ProcessesWebhooksTrait.php
Lines changed: 63 additions & 12 deletions
Viewed
Viewed
Comment on this file
More options
Expand file
app/Jobs/Crm/SyncObjects.php
app/Jobs/Crm/SyncObjects.php
app/Jobs/Crm/SyncObjects.php
Copy file name to clipboard
Expand all lines: app/Jobs/Crm/SyncObjects.php
Lines changed: 23 additions & 15 deletions
Viewed
Viewed
Comment on this file
More options
Expand file
app/Jobs/Crm/SyncOpportunitiesJob.php
app/Jobs/Crm/SyncOpportunitiesJob.php
app/Jobs/Crm/SyncOpportunitiesJob.php
Copy file name to clipboard
Expand all lines: app/Jobs/Crm/SyncOpportunitiesJob.php
Lines changed: 11 additions & 1 deletion
Viewed
Viewed
Comment on this file
More options
Collapse file
app/Services/Crm/Hubspot/ServiceTraits/OpportunitySyncTrait.php
app/Services/Crm/Hubspot/ServiceTraits/OpportunitySyncTrait.php
app/Services/Crm/Hubspot/ServiceTraits/OpportunitySyncTrait.php
Copy file name to clipboard
Expand all lines: app/Services/Crm/Hubspot/ServiceTraits/OpportunitySyncTrait.php
Lines changed: 11 additions & 6 deletions
Not Viewed
Viewed
Comment on this file
More options
Original file line number
Original file line
Diff line number
Diff line change
@@ -43,17 +43,20 @@ trait OpportunitySyncTrait
43
43
44
public
function
syncOpportunities
(
array
$
parameters
, ?
string
$
strategy
=
null
):
int
44
public
function
syncOpportunities
(
array
$
parameters
, ?
string
$
strategy
=
null
):
int
45
{
45
{...
|
NULL
|
|
55384
|
NULL
|
0
|
2026-04-20T09:48:17.627600+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776678497627_m1.jpg...
|
Firefox
|
JY-20553 | Improve crm-sync delays by yalokin-jimi JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app — Work...
|
True
|
github.com/jiminny/app/pull/11976/changes#diff-f61 github.com/jiminny/app/pull/11976/changes#diff-f61f95a9f65b327dc254e0f402ef96bbeb6fcf71d4ea965e367f2e99ff4a6333...
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
Close tab
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
[JY-20543] AJ Reports > Tracking - Jira
[JY-20543] AJ Reports > Tracking - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira
Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app
Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app
New Tab
New Tab
Product Growth Platform | Userpilot
Product Growth Platform | Userpilot
Userpilot | Logged-activity
Userpilot | Logged-activity
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Feed — jiminny — Sentry
Feed — jiminny — Sentry
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Copy prompt
You said checkout to remote branch
You said
checkout to remote branch
Listen
Show more options
Show thinking
Gemini said
Gemini said
Here is the standard way to check out a remote branch in Git.
Step 1: Fetch the latest remote branches
Step 1: Fetch the latest remote branches
Before checking out, it is best practice to ensure your local repository knows about the latest branches on the remote. Run:
Bash
Copy code
git fetch
Step 2: Check out the branch
Step 2: Check out the branch
You have a few options depending on your version of Git and whether you want to use the exact same name as the remote branch.
Option A: The simplest way (Recommended)
Option A: The simplest way (Recommended)
If the remote branch exists and you don't have a local branch with the same name, Git will automatically create the local branch and set it up to track the remote one.
Using the newer
switch
command:
Bash
Copy code
git switch <branch-name>
Or using the traditional
checkout
command:
Bash
Copy code
git checkout <branch-name>
(Note: Do not include
origin/
in this command. Just use the branch name, e.g.,
git checkout feature-branch
)
Option B: The explicit way
Option B: The explicit way
If Option A doesn't work (for example, if you have multiple remotes), or if you want to give your local branch a
different name
than the remote branch, you can explicitly map them:
Bash
Copy code
git checkout -b <your-local-branch-name> origin/<remote-branch-name>
How to verify it worked
How to verify it worked
To confirm you are on the right branch and tracking the remote properly, run:
Bash
Copy code
git branch -vv
This will list your local branches, highlight your current branch, and show which remote branch it is tracking (e.g.,
[origin/<branch-name>]
).
Copy prompt
Edit
You said lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git fetch lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git checkout -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $
You said
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git fetch
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays
fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git checkout -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays
fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $
Expand
Listen
Show more options
Show thinking
Gemini said
Gemini said
Ah, it looks like just a tiny typo! You spelled
origin
as
orign
in your commands.
Git is throwing that error because it can't find a remote named "orign".
Here is the corrected command:
Bash
Copy code
git checkout -b JY-20553-debug-crm-sync-delays origin/JY-20553-debug-crm-sync-delays
An Easier Shortcut
An Easier Shortcut
Since your local branch name matches the remote branch exactly, you can actually skip the
-b
and
origin/
entirely. Git is smart enough to figure it out automatically:
Bash
Copy code
git checkout JY-20553-debug-crm-sync-delays
(Or if
co
is your alias for checkout, just
co JY-20553-debug-crm-sync-delays
will work!)
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Microphone
Your Jiminny chats aren’t used to improve our models. Gemini is AI and can make mistakes, including about people.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
Issues(g then i)
Pull requests
Repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (22)
Security and quality
(
22
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20553 | Improve crm-sync delays #11976 Edit title
JY-20553 | Improve crm-sync delays
#
11976
Edit title
Preview
Preview
Checks pending
Checks pending
Code
Code
Open
yalokin-jiminny
yalokin-jiminny
wants to merge 21 commits into
master
master
from
JY-20553-debug-crm-sync-delays
JY-20553-debug-crm-sync-delays
Copy head branch name to clipboard
Lines changed: 907 additions & 132 deletions
Conversation (5)
Conversation
(
5
)
Commits (21)...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6793] Les Mills activity types not pulling in - Jira","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6793] Les Mills activity types not pulling in - Jira","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20543] AJ Reports > Tracking - Jira","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20543] AJ Reports > Tracking - Jira","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Product Growth Platform | Userpilot","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Product Growth Platform | Userpilot","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Logged-activity","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Logged-activity","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Feed — jiminny — Sentry","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Feed — jiminny — Sentry","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Chat","depth":12,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open menu for conversation actions.","depth":12,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":21,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said checkout to remote branch","depth":21,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"checkout to remote branch","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Listen","depth":22,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":26,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is the standard way to check out a remote branch in Git.","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Step 1: Fetch the latest remote branches","depth":23,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Step 1: Fetch the latest remote branches","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Before checking out, it is best practice to ensure your local repository knows about the latest branches on the remote. Run:","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bash","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy code","depth":25,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"git fetch","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Step 2: Check out the branch","depth":23,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Step 2: Check out the branch","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You have a few options depending on your version of Git and whether you want to use the exact same name as the remote branch.","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Option A: The simplest way (Recommended)","depth":23,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Option A: The simplest way (Recommended)","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If the remote branch exists and you don't have a local branch with the same name, Git will automatically create the local branch and set it up to track the remote one.","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Using the newer","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"switch","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"command:","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bash","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy code","depth":25,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"git switch <branch-name>","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Or using the traditional","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"checkout","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"command:","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bash","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy code","depth":25,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"git checkout <branch-name>","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(Note: Do not include","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"origin/","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"in this command. Just use the branch name, e.g.,","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"git checkout feature-branch","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Option B: The explicit way","depth":23,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Option B: The explicit way","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"If Option A doesn't work (for example, if you have multiple remotes), or if you want to give your local branch a","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"different name","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"than the remote branch, you can explicitly map them:","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bash","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy code","depth":25,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"git checkout -b <your-local-branch-name> origin/<remote-branch-name>","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"How to verify it worked","depth":23,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"How to verify it worked","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"To confirm you are on the right branch and tracking the remote properly, run:","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bash","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy code","depth":25,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"git branch -vv","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"This will list your local branches, highlight your current branch, and show which remote branch it is tracking (e.g.,","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"[origin/<branch-name>]","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":").","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":21,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":21,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git fetch lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git checkout -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $","depth":21,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git fetch","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git checkout -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Expand","depth":21,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Listen","depth":22,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Show more options","depth":20,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Show thinking","depth":26,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Gemini said","depth":20,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini said","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Ah, it looks like just a tiny typo! You spelled","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"origin","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"as","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"orign","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"in your commands.","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Git is throwing that error because it can't find a remote named \"orign\".","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Here is the corrected command:","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bash","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy code","depth":25,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"git checkout -b JY-20553-debug-crm-sync-delays origin/JY-20553-debug-crm-sync-delays","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"An Easier Shortcut","depth":23,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"An Easier Shortcut","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Since your local branch name matches the remote branch exactly, you can actually skip the","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"-b","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"origin/","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"entirely. Git is smart enough to figure it out automatically:","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Bash","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy code","depth":25,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"git checkout JY-20553-debug-crm-sync-delays","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(Or if","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"co","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"is your alias for checkout, just","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"co JY-20553-debug-crm-sync-delays","depth":25,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"will work!)","depth":24,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextArea","text":"Enter a prompt for Gemini\nencrypted","depth":20,"value":"Enter a prompt for Gemini\nencrypted","help_text":"","role_description":"text entry area","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Enter a prompt for Gemini","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"encrypted","depth":21,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open upload file menu","depth":20,"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tools","depth":18,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open mode picker","depth":20,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pro","depth":23,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXCheckBox","text":"Microphone","depth":19,"role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your Jiminny chats aren’t used to improve our models. Gemini is AI and can make mistakes, including about people.","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Your privacy & Gemini Opens in a new window","depth":17,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your privacy & Gemini","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Opens in a new window","depth":19,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Summarize page","depth":7,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summarize page","depth":9,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Skip to content","depth":6,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open menu","depth":10,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Homepage (g then d)","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"jiminny","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"app","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Type","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to search","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chat with Copilot","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Open Copilot…","depth":9,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Create new...","depth":9,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Issues(g then i)","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Pull requests","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Repositories","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"You have unread notifications(g then n)","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open user navigation menu","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Repository navigation","depth":9,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repository navigation","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests (31)","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"31","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Agents","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Agents","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Wiki","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wiki","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality (22)","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":10,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review this update","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub account settings","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"JY-20553 | Improve crm-sync delays #11976 Edit title","depth":13,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20553 | Improve crm-sync delays","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11976","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit title","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Preview","depth":13,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Preview","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Checks pending","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks pending","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Code","depth":13,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Code","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"yalokin-jiminny","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"yalokin-jiminny","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 21 commits into","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20553-debug-crm-sync-delays","depth":16,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20553-debug-crm-sync-delays","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 907 additions & 132 deletions","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Conversation (5)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Conversation","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Commits (21)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-6074676719002118658
|
-2605766687885417541
|
click
|
accessibility
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
Close tab
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
[JY-20543] AJ Reports > Tracking - Jira
[JY-20543] AJ Reports > Tracking - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira
Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app
Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app
New Tab
New Tab
Product Growth Platform | Userpilot
Product Growth Platform | Userpilot
Userpilot | Logged-activity
Userpilot | Logged-activity
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Feed — jiminny — Sentry
Feed — jiminny — Sentry
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
New Chat
Open menu for conversation actions.
Conversation with Gemini
Conversation with Gemini
Copy prompt
You said checkout to remote branch
You said
checkout to remote branch
Listen
Show more options
Show thinking
Gemini said
Gemini said
Here is the standard way to check out a remote branch in Git.
Step 1: Fetch the latest remote branches
Step 1: Fetch the latest remote branches
Before checking out, it is best practice to ensure your local repository knows about the latest branches on the remote. Run:
Bash
Copy code
git fetch
Step 2: Check out the branch
Step 2: Check out the branch
You have a few options depending on your version of Git and whether you want to use the exact same name as the remote branch.
Option A: The simplest way (Recommended)
Option A: The simplest way (Recommended)
If the remote branch exists and you don't have a local branch with the same name, Git will automatically create the local branch and set it up to track the remote one.
Using the newer
switch
command:
Bash
Copy code
git switch <branch-name>
Or using the traditional
checkout
command:
Bash
Copy code
git checkout <branch-name>
(Note: Do not include
origin/
in this command. Just use the branch name, e.g.,
git checkout feature-branch
)
Option B: The explicit way
Option B: The explicit way
If Option A doesn't work (for example, if you have multiple remotes), or if you want to give your local branch a
different name
than the remote branch, you can explicitly map them:
Bash
Copy code
git checkout -b <your-local-branch-name> origin/<remote-branch-name>
How to verify it worked
How to verify it worked
To confirm you are on the right branch and tracking the remote properly, run:
Bash
Copy code
git branch -vv
This will list your local branches, highlight your current branch, and show which remote branch it is tracking (e.g.,
[origin/<branch-name>]
).
Copy prompt
Edit
You said lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git fetch lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git checkout -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $
You said
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git fetch
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays
fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git checkout -b JY-20553-debug-crm-sync-delays orign/JY-20553-debug-crm-sync-delays
fatal: 'orign/JY-20553-debug-crm-sync-delays' is not a commit and a branch 'JY-20553-debug-crm-sync-delays' cannot be created from it
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $
Expand
Listen
Show more options
Show thinking
Gemini said
Gemini said
Ah, it looks like just a tiny typo! You spelled
origin
as
orign
in your commands.
Git is throwing that error because it can't find a remote named "orign".
Here is the corrected command:
Bash
Copy code
git checkout -b JY-20553-debug-crm-sync-delays origin/JY-20553-debug-crm-sync-delays
An Easier Shortcut
An Easier Shortcut
Since your local branch name matches the remote branch exactly, you can actually skip the
-b
and
origin/
entirely. Git is smart enough to figure it out automatically:
Bash
Copy code
git checkout JY-20553-debug-crm-sync-delays
(Or if
co
is your alias for checkout, just
co JY-20553-debug-crm-sync-delays
will work!)
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Microphone
Your Jiminny chats aren’t used to improve our models. Gemini is AI and can make mistakes, including about people.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
Issues(g then i)
Pull requests
Repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (22)
Security and quality
(
22
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20553 | Improve crm-sync delays #11976 Edit title
JY-20553 | Improve crm-sync delays
#
11976
Edit title
Preview
Preview
Checks pending
Checks pending
Code
Code
Open
yalokin-jiminny
yalokin-jiminny
wants to merge 21 commits into
master
master
from
JY-20553-debug-crm-sync-delays
JY-20553-debug-crm-sync-delays
Copy head branch name to clipboard
Lines changed: 907 additions & 132 deletions
Conversation (5)
Conversation
(
5
)
Commits (21)...
|
55379
|
|
55300
|
NULL
|
0
|
2026-04-20T09:43:16.616726+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776678196616_m2.jpg...
|
Firefox
|
JY-20553 | Improve crm-sync delays by yalokin-jimi JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app — Work...
|
True
|
github.com/jiminny/app/pull/11976/changes
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
Close tab
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
[JY-20543] AJ Reports > Tracking - Jira
[JY-20543] AJ Reports > Tracking - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira
Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app
Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app
New Tab
New Tab
Product Growth Platform | Userpilot
Product Growth Platform | Userpilot
Userpilot | Logged-activity
Userpilot | Logged-activity
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Feed — jiminny — Sentry
Feed — jiminny — Sentry
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
PRO
PRO
Conversation with Gemini
Conversation with Gemini
Copy prompt
Edit
You said checkout to remote branch
You said
checkout to remote branch
Show more options
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Stop response
Your Jiminny chats aren’t used to improve our models. Gemini is AI and can make mistakes, including about people.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Gemini is typing
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
Issues(g then i)
Pull requests
Repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (22)
Security and quality
(
22
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20553 | Improve crm-sync delays #11976 Edit title
JY-20553 | Improve crm-sync delays
#
11976
Edit title
Preview
Preview
Checks pending
Checks pending
Code
Code
Open
yalokin-jiminny
yalokin-jiminny
wants to merge 21 commits into
master
master
from
JY-20553-debug-crm-sync-delays
JY-20553-debug-crm-sync-delays
Copy head branch name to clipboard
Lines changed: 907 additions & 132 deletions
Conversation (5)
Conversation
(
5
)
Commits (21)
Commits
(
21
)
Checks (2)
Checks
(
2
)
Files changed (14)
Files changed
(
14
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
Open
JY-20553 | Improve crm-sync delays
JY-20553 | Improve crm-sync delays
#
11976
All commits
All commits
yalokin-jiminny
yalokin-jiminny
wants to merge 21 commits into
master
master
from
JY-20553-debug-crm-sync-delays
JY-20553-debug-crm-sync-delays
Copy head branch name to clipboard
0
/
14
viewed
Checks pending
Checks pending
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel
(
0
)
Filter files…
Filter options
File tree
File tree
app
Console/Commands/Crm
SyncObjects.php
SyncObjects.php
Http/Controllers
Internal/WebhookReceiver
HubspotController.php
HubspotController.php
Webhook/Hubspot
EventsController.php
EventsController.php
ProcessesWebhooksTrait.php
ProcessesWebhooksTrait.php
Jobs/Crm
SyncObjects.php
SyncObjects.php
SyncOpportunitiesJob.php
SyncOpportunitiesJob.php
Services/Crm
Hubspot/ServiceTraits
OpportunitySyncTrait.php
OpportunitySyncTrait.php
BaseService.php
BaseService.php
tests
Feature/Services/Crm
BaseServiceTest.php
BaseServiceTest.php
Unit
Http/Controllers/Webhook/Hubspot
ProcessesWebhooksTraitTest.php
ProcessesWebhooksTraitTest.php
Jobs/Crm
SyncObjectsTest.php...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0018284575,"top":0.0518755,"width":0.07596409,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.09497207,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.10614525,"width":0.15774602,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.10215483,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6793] Les Mills activity types not pulling in - Jira","depth":4,"bounds":{"left":0.0,"top":0.12769353,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6793] Les Mills activity types not pulling in - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.13886672,"width":0.09524601,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.16041501,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.17158818,"width":0.19963431,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.19313647,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.20430966,"width":0.15525267,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20543] AJ Reports > Tracking - Jira","depth":4,"bounds":{"left":0.0,"top":0.22585794,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20543] AJ Reports > Tracking - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.23703113,"width":0.06981383,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira","depth":4,"bounds":{"left":0.0,"top":0.2585794,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.2697526,"width":0.10688165,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.29130086,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.30247405,"width":0.12915559,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.0,"top":0.32402235,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.013297873,"top":0.33519554,"width":0.014960106,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Product Growth Platform | Userpilot","depth":4,"bounds":{"left":0.0,"top":0.3567438,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Product Growth Platform | Userpilot","depth":5,"bounds":{"left":0.013297873,"top":0.367917,"width":0.06200133,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Logged-activity","depth":4,"bounds":{"left":0.0,"top":0.38946527,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Logged-activity","depth":5,"bounds":{"left":0.013297873,"top":0.40063846,"width":0.04637633,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.42218676,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.43335995,"width":0.2052859,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.45490822,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.4660814,"width":0.039228722,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Feed — jiminny — Sentry","depth":4,"bounds":{"left":0.0,"top":0.48762968,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Feed — jiminny — Sentry","depth":5,"bounds":{"left":0.013297873,"top":0.49880287,"width":0.042719416,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.5203512,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.53152436,"width":0.2052859,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.55307263,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.5642458,"width":0.013131649,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.5857941,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.5969673,"width":0.013131649,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.61851555,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.62968874,"width":0.013131649,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.6528332,"width":0.07413564,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Close Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"AI Chat settings","depth":7,"bounds":{"left":0.1846742,"top":0.055067837,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close","depth":7,"bounds":{"left":0.1966423,"top":0.055067837,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"WORK, Google Account: lukas.kovalik@jiminny.com","depth":12,"bounds":{"left":0.1939827,"top":0.103751,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Main menu","depth":12,"bounds":{"left":0.08361037,"top":0.103751,"width":0.013297873,"height":0.031923383},"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New chat","depth":12,"bounds":{"left":0.09690824,"top":0.10454908,"width":0.028590426,"height":0.030327214},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Gemini","depth":15,"bounds":{"left":0.099567816,"top":0.10973663,"width":0.021941489,"height":0.020351157},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"PRO","depth":11,"bounds":{"left":0.17719415,"top":0.110135674,"width":0.014793883,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"PRO","depth":13,"bounds":{"left":0.17985372,"top":0.112529926,"width":0.009474734,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Conversation with Gemini","depth":15,"bounds":{"left":0.079288565,"top":0.14764565,"width":0.0003324468,"height":0.0007980846},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Conversation with Gemini","depth":16,"bounds":{"left":0.079288565,"top":0.15003991,"width":0.1200133,"height":0.025538707},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy prompt","depth":20,"bounds":{"left":0.1022274,"top":0.18355946,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Edit","depth":20,"bounds":{"left":0.116855055,"top":0.18355946,"width":0.013297873,"height":0.031923383},"role_description":"button","subrole":"AXUnknown","is_enabled":false,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"You said checkout to remote branch","depth":20,"bounds":{"left":0.13680187,"top":0.19313647,"width":0.065159574,"height":0.044692736},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"You said","depth":22,"bounds":{"left":0.079288565,"top":0.19553073,"width":0.019946808,"height":0.016360734},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"checkout to remote branch","depth":22,"bounds":{"left":0.13680187,"top":0.1963288,"width":0.04737367,"height":0.038707104},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Show more options","depth":18,"bounds":{"left":0.1939827,"top":0.26656026,"width":0.013297873,"height":0.031923383},"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXTextArea","text":"Enter a prompt for Gemini\nencrypted","depth":20,"bounds":{"left":0.09291888,"top":0.8104549,"width":0.10638298,"height":0.01915403},"value":"Enter a prompt for Gemini\nencrypted","help_text":"","role_description":"text entry area","subrole":"AXUnknown","is_enabled":true,"is_focused":true,"is_selected":false},{"role":"AXStaticText","text":"Enter a prompt for Gemini","depth":21,"bounds":{"left":0.099567816,"top":0.81085396,"width":0.069980055,"height":0.018355945},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"encrypted","depth":21,"bounds":{"left":0.091921546,"top":0.8104549,"width":0.0066489363,"height":0.01915403},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open upload file menu","depth":20,"bounds":{"left":0.08892952,"top":0.8447725,"width":0.013297873,"height":0.031923383},"role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tools","depth":18,"bounds":{"left":0.10488697,"top":0.8447725,"width":0.013297873,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open mode picker","depth":20,"bounds":{"left":0.1619016,"top":0.8439745,"width":0.026097074,"height":0.031923383},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pro","depth":23,"bounds":{"left":0.16722074,"top":0.8527534,"width":0.007480053,"height":0.014764565},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Stop response","depth":19,"bounds":{"left":0.18932846,"top":0.84317636,"width":0.013962766,"height":0.033519555},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your Jiminny chats aren’t used to improve our models. Gemini is AI and can make mistakes, including about people.","depth":17,"bounds":{"left":0.0852726,"top":0.896249,"width":0.12167553,"height":0.025139665},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Your privacy & Gemini Opens in a new window","depth":17,"bounds":{"left":0.12599733,"top":0.92178774,"width":0.040226065,"height":0.012370312},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Your privacy & Gemini","depth":18,"bounds":{"left":0.12599733,"top":0.92178774,"width":0.040226065,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Opens in a new window","depth":19,"bounds":{"left":0.079288565,"top":0.92098963,"width":0.043218084,"height":0.012370312},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gemini is typing","depth":9,"bounds":{"left":0.079288565,"top":0.091380686,"width":0.035738032,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Summarize page","depth":7,"bounds":{"left":0.08494016,"top":0.95730245,"width":0.053523935,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Summarize page","depth":9,"bounds":{"left":0.09059176,"top":0.96249,"width":0.042220745,"height":0.015163607},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Skip to content","depth":6,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Skip to content","depth":7,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Open menu","depth":10,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Homepage (g then d)","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"jiminny","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"jiminny","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"app","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"app","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Search or jump to…","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Type","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"to search","depth":12,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Chat with Copilot","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Open Copilot…","depth":9,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXMenuButton","text":"Create new...","depth":9,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXLink","text":"Issues(g then i)","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Pull requests","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"Repositories","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXLink","text":"You have unread notifications(g then n)","depth":9,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"Open user navigation menu","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"Repository navigation","depth":9,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Repository navigation","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Code","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Code","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Pull requests (31)","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pull requests","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"31","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Agents","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Agents","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Actions","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Actions","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Wiki","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Wiki","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Security and quality (22)","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Security and quality","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"22","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Insights","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Insights","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Settings","depth":12,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Settings","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Important update","depth":10,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Important update","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Review this update","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Review this update","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"and manage your preferences in your","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"GitHub account settings","depth":10,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"GitHub account settings","depth":11,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":".","depth":10,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Dismiss banner","depth":9,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXHeading","text":"JY-20553 | Improve crm-sync delays #11976 Edit title","depth":13,"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"JY-20553 | Improve crm-sync delays","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11976","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Edit title","depth":14,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Preview","depth":13,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Preview","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Checks pending","depth":13,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks pending","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Code","depth":13,"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Code","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Open","depth":13,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"yalokin-jiminny","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"yalokin-jiminny","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 21 commits into","depth":15,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20553-debug-crm-sync-delays","depth":16,"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20553-debug-crm-sync-delays","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Lines changed: 907 additions & 132 deletions","depth":14,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Conversation (5)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Conversation","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"5","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Commits (21)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Commits","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"21","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Checks (2)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Files changed (14)","depth":16,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Files changed","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"(","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":18,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Pull Request Toolbar","depth":14,"bounds":{"left":0.22606383,"top":0.07581804,"width":0.0003324468,"height":0.0007980846},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Pull Request Toolbar","depth":15,"bounds":{"left":0.22606383,"top":0.07861133,"width":0.030086435,"height":0.08060654},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Collapse file tree","depth":14,"bounds":{"left":0.22606383,"top":0.0650439,"width":0.00930851,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":true},{"role":"AXStaticText","text":"Open","depth":14,"bounds":{"left":0.2486702,"top":0.06943336,"width":0.011968086,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20553 | Improve crm-sync delays","depth":14,"bounds":{"left":0.26728722,"top":0.058260176,"width":0.08294548,"height":0.016759777},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20553 | Improve crm-sync delays","depth":16,"bounds":{"left":0.26728722,"top":0.059856344,"width":0.08294548,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"#","depth":15,"bounds":{"left":0.35289228,"top":0.059856344,"width":0.0029920214,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"11976","depth":15,"bounds":{"left":0.3558843,"top":0.059856344,"width":0.012466756,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"All commits","depth":14,"bounds":{"left":0.26462767,"top":0.07182761,"width":0.03374335,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"All commits","depth":16,"bounds":{"left":0.26761967,"top":0.07701516,"width":0.02244016,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"yalokin-jiminny","depth":15,"bounds":{"left":0.30269283,"top":0.07581804,"width":0.029920213,"height":0.014365523},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"yalokin-jiminny","depth":16,"bounds":{"left":0.30269283,"top":0.07701516,"width":0.029920213,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"wants to merge 21 commits into","depth":15,"bounds":{"left":0.33394283,"top":0.07701516,"width":0.059674203,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"master","depth":15,"bounds":{"left":0.3949468,"top":0.074221864,"width":0.018450798,"height":0.017557861},"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"master","depth":16,"bounds":{"left":0.39694148,"top":0.07741421,"width":0.014461436,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"from","depth":16,"bounds":{"left":0.4147274,"top":0.07701516,"width":0.008643617,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"JY-20553-debug-crm-sync-delays","depth":16,"bounds":{"left":0.4247008,"top":0.074221864,"width":0.07596409,"height":0.017557861},"role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20553-debug-crm-sync-delays","depth":17,"bounds":{"left":0.42669547,"top":0.07741421,"width":0.07197473,"height":0.011572227},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Copy head branch name to clipboard","depth":16,"bounds":{"left":0.50199467,"top":0.07182761,"width":0.00930851,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"0","depth":15,"bounds":{"left":0.8231383,"top":0.070231445,"width":0.002493351,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"/","depth":15,"bounds":{"left":0.8256317,"top":0.070231445,"width":0.0023271276,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"14","depth":15,"bounds":{"left":0.82912236,"top":0.070231445,"width":0.004654255,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"viewed","depth":15,"bounds":{"left":0.83477396,"top":0.070231445,"width":0.013297873,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Checks pending","depth":14,"bounds":{"left":0.85638297,"top":0.0650439,"width":0.04338431,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Checks pending","depth":16,"bounds":{"left":0.86602396,"top":0.070231445,"width":0.030751329,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Submit review","depth":14,"bounds":{"left":0.90242684,"top":0.0650439,"width":0.03856383,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Submit","depth":16,"bounds":{"left":0.9054189,"top":0.070231445,"width":0.014793883,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"review","depth":16,"bounds":{"left":0.92021275,"top":0.070231445,"width":0.012466756,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXMenuButton","text":"Open diff view settings","depth":14,"bounds":{"left":0.94365025,"top":0.0650439,"width":0.00930851,"height":0.022346368},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open overview panel","depth":14,"bounds":{"left":0.96127,"top":0.0650439,"width":0.00930851,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open comments panel","depth":14,"bounds":{"left":0.9719083,"top":0.0650439,"width":0.017287234,"height":0.022346368},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"(","depth":16,"bounds":{"left":0.9802194,"top":0.070231445,"width":0.0026595744,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"0","depth":16,"bounds":{"left":0.982879,"top":0.070231445,"width":0.0026595744,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":")","depth":16,"bounds":{"left":0.98553854,"top":0.070231445,"width":0.0014960107,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXTextField","text":"Filter files…","depth":16,"bounds":{"left":0.23736702,"top":0.11332801,"width":0.06815159,"height":0.023942538},"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXMenuButton","text":"Filter options","depth":16,"bounds":{"left":0.30851063,"top":0.112529926,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"menu button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXHeading","text":"File tree","depth":15,"bounds":{"left":0.22639628,"top":0.15083799,"width":0.0003324468,"height":0.0007980846},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"File tree","depth":16,"bounds":{"left":0.22639628,"top":0.15363128,"width":0.014295213,"height":0.0518755},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"app","depth":19,"bounds":{"left":0.24235372,"top":0.15722266,"width":0.008144947,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Console/Commands/Crm","depth":21,"bounds":{"left":0.2450133,"top":0.18276137,"width":0.053690158,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SyncObjects.php","depth":23,"bounds":{"left":0.24767287,"top":0.20830008,"width":0.036901597,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SyncObjects.php","depth":24,"bounds":{"left":0.24767287,"top":0.20830008,"width":0.036901597,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Http/Controllers","depth":21,"bounds":{"left":0.2450133,"top":0.23383878,"width":0.034408245,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Internal/WebhookReceiver","depth":23,"bounds":{"left":0.24767287,"top":0.25977653,"width":0.05618351,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"HubspotController.php","depth":25,"bounds":{"left":0.25033244,"top":0.28531525,"width":0.04886968,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"HubspotController.php","depth":26,"bounds":{"left":0.25033244,"top":0.28531525,"width":0.04886968,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Webhook/Hubspot","depth":23,"bounds":{"left":0.24767287,"top":0.31085396,"width":0.039893616,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"EventsController.php","depth":25,"bounds":{"left":0.25033244,"top":0.3367917,"width":0.04488032,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"EventsController.php","depth":26,"bounds":{"left":0.25033244,"top":0.3367917,"width":0.04488032,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ProcessesWebhooksTrait.php","depth":25,"bounds":{"left":0.25033244,"top":0.3623304,"width":0.06333112,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ProcessesWebhooksTrait.php","depth":26,"bounds":{"left":0.25033244,"top":0.3623304,"width":0.06333112,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jobs/Crm","depth":21,"bounds":{"left":0.2450133,"top":0.38786912,"width":0.020777926,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SyncObjects.php","depth":23,"bounds":{"left":0.24767287,"top":0.41340783,"width":0.036901597,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SyncObjects.php","depth":24,"bounds":{"left":0.24767287,"top":0.41340783,"width":0.036901597,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SyncOpportunitiesJob.php","depth":23,"bounds":{"left":0.24767287,"top":0.43894652,"width":0.057513297,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"SyncOpportunitiesJob.php","depth":24,"bounds":{"left":0.24767287,"top":0.43894652,"width":0.057513297,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Services/Crm","depth":21,"bounds":{"left":0.2450133,"top":0.46448523,"width":0.028756648,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Hubspot/ServiceTraits","depth":23,"bounds":{"left":0.24767287,"top":0.49002394,"width":0.04720745,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"OpportunitySyncTrait.php","depth":25,"bounds":{"left":0.25033244,"top":0.5159617,"width":0.05518617,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"OpportunitySyncTrait.php","depth":26,"bounds":{"left":0.25033244,"top":0.5159617,"width":0.05518617,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"BaseService.php","depth":23,"bounds":{"left":0.24767287,"top":0.5415004,"width":0.036070477,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BaseService.php","depth":24,"bounds":{"left":0.24767287,"top":0.5415004,"width":0.036070477,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"tests","depth":19,"bounds":{"left":0.24235372,"top":0.56703913,"width":0.010638298,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Feature/Services/Crm","depth":21,"bounds":{"left":0.2450133,"top":0.5925778,"width":0.04654255,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"BaseServiceTest.php","depth":23,"bounds":{"left":0.24767287,"top":0.61851555,"width":0.044714097,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BaseServiceTest.php","depth":24,"bounds":{"left":0.24767287,"top":0.61851555,"width":0.044714097,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unit","depth":21,"bounds":{"left":0.2450133,"top":0.6440543,"width":0.00880984,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Http/Controllers/Webhook/Hubspot","depth":23,"bounds":{"left":0.24767287,"top":0.669593,"width":0.07579787,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"ProcessesWebhooksTraitTest.php","depth":25,"bounds":{"left":0.25033244,"top":0.69513166,"width":0.072140954,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"ProcessesWebhooksTraitTest.php","depth":26,"bounds":{"left":0.25033244,"top":0.69513166,"width":0.072140954,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jobs/Crm","depth":23,"bounds":{"left":0.24767287,"top":0.7206704,"width":0.020777926,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"SyncObjectsTest.php","depth":25,"bounds":{"left":0.25033244,"top":0.74660814,"width":0.045545213,"height":0.013567438},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-3350738637795311336
|
-2678105760012015840
|
visual_change
|
accessibility
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
Close tab
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
[JY-20543] AJ Reports > Tracking - Jira
[JY-20543] AJ Reports > Tracking - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira
Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app
Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app
New Tab
New Tab
Product Growth Platform | Userpilot
Product Growth Platform | Userpilot
Userpilot | Logged-activity
Userpilot | Logged-activity
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Feed — jiminny — Sentry
Feed — jiminny — Sentry
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
New Tab
Customize sidebar
Close Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
AI Chat settings
Close
WORK, Google Account: [EMAIL]
Main menu
New chat
Gemini
PRO
PRO
Conversation with Gemini
Conversation with Gemini
Copy prompt
Edit
You said checkout to remote branch
You said
checkout to remote branch
Show more options
Enter a prompt for Gemini
encrypted
Enter a prompt for Gemini
encrypted
Open upload file menu
Tools
Open mode picker
Pro
Stop response
Your Jiminny chats aren’t used to improve our models. Gemini is AI and can make mistakes, including about people.
Your privacy & Gemini Opens in a new window
Your privacy & Gemini
Opens in a new window
Gemini is typing
Summarize page
Summarize page
Skip to content
Skip to content
Open menu
Homepage (g then d)
jiminny
jiminny
app
app
Search or jump to…
Type
/
to search
Chat with Copilot
Open Copilot…
Create new...
Issues(g then i)
Pull requests
Repositories
You have unread notifications(g then n)
Open user navigation menu
Repository navigation
Repository navigation
Code
Code
Pull requests (31)
Pull requests
(
31
)
Agents
Agents
Actions
Actions
Wiki
Wiki
Security and quality (22)
Security and quality
(
22
)
Insights
Insights
Settings
Settings
Important update
Important update
On April 24 we'll start using GitHub Copilot interaction data for AI model training unless you opt out.
Review this update
Review this update
and manage your preferences in your
GitHub account settings
GitHub account settings
.
Dismiss banner
JY-20553 | Improve crm-sync delays #11976 Edit title
JY-20553 | Improve crm-sync delays
#
11976
Edit title
Preview
Preview
Checks pending
Checks pending
Code
Code
Open
yalokin-jiminny
yalokin-jiminny
wants to merge 21 commits into
master
master
from
JY-20553-debug-crm-sync-delays
JY-20553-debug-crm-sync-delays
Copy head branch name to clipboard
Lines changed: 907 additions & 132 deletions
Conversation (5)
Conversation
(
5
)
Commits (21)
Commits
(
21
)
Checks (2)
Checks
(
2
)
Files changed (14)
Files changed
(
14
)
Pull Request Toolbar
Pull Request Toolbar
Collapse file tree
Open
JY-20553 | Improve crm-sync delays
JY-20553 | Improve crm-sync delays
#
11976
All commits
All commits
yalokin-jiminny
yalokin-jiminny
wants to merge 21 commits into
master
master
from
JY-20553-debug-crm-sync-delays
JY-20553-debug-crm-sync-delays
Copy head branch name to clipboard
0
/
14
viewed
Checks pending
Checks pending
Submit review
Submit
review
Open diff view settings
Open overview panel
Open comments panel
(
0
)
Filter files…
Filter options
File tree
File tree
app
Console/Commands/Crm
SyncObjects.php
SyncObjects.php
Http/Controllers
Internal/WebhookReceiver
HubspotController.php
HubspotController.php
Webhook/Hubspot
EventsController.php
EventsController.php
ProcessesWebhooksTrait.php
ProcessesWebhooksTrait.php
Jobs/Crm
SyncObjects.php
SyncObjects.php
SyncOpportunitiesJob.php
SyncOpportunitiesJob.php
Services/Crm
Hubspot/ServiceTraits
OpportunitySyncTrait.php
OpportunitySyncTrait.php
BaseService.php
BaseService.php
tests
Feature/Services/Crm
BaseServiceTest.php
BaseServiceTest.php
Unit
Http/Controllers/Webhook/Hubspot
ProcessesWebhooksTraitTest.php
ProcessesWebhooksTraitTest.php
Jobs/Crm
SyncObjectsTest.php...
|
55299
|
|
55296
|
NULL
|
0
|
2026-04-20T09:43:07.661048+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776678187661_m1.jpg...
|
Firefox
|
JY-20553 | Improve crm-sync delays by yalokin-jimi JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app — Work...
|
True
|
github.com/jiminny/app/pull/11976/changes
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
Close tab
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
[JY-20543] AJ Reports > Tracking - Jira
[JY-20543] AJ Reports > Tracking - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"[SRD-6793] Les Mills activity types not pulling in - Jira","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6793] Les Mills activity types not pulling in - Jira","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20543] AJ Reports > Tracking - Jira","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20543] AJ Reports > Tracking - Jira","depth":5,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira","depth":4,"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-654329278458865655
|
6223266628974356375
|
click
|
accessibility
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
Close tab
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
[JY-20543] AJ Reports > Tracking - Jira
[JY-20543] AJ Reports > Tracking - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira...
|
55295
|
|
55197
|
NULL
|
0
|
2026-04-20T09:37:57.755107+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776677877755_m2.jpg...
|
PhpStorm
|
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormVIeWINavigarecodeLaravelKeractorTOOISmelpP PhostormVIeWINavigarecodeLaravelKeractorTOOISmelpProiect© Field.php© FieldRepository.phpD Audio© AskJiminnyReportActivityService.php(c) RequestGenerateAskJiminnyReportJoblest.onpD AutomatedReports• kecuestGenerateaskJiminnykkequestGeneratekeporJoo.orAskJiminnykeporiscontroller.phgVo) Astil© SendReportJob.phpc) senckeponmallJob.ong0 CalendarC) AutomatedReportsCommand.php(c) AutomatedReportsReposb ermC) CreateHeldActivityEvent.phpC) TrackProviderInstalledEventDealRiskSMailboxC) UserPilotActivitvListener.ohv© ActivityLogged.phpC) ReauestGenerateAsk.JiminnvReport.Job.ohv X (C) AutomatedRerclass RequestGenerateAskJiminnyReportJob impublic function handle(l TreamTelenhonvIstatus! => AutomatedRelm Use'media_type' => Automate© BaseProcessingJob.phpC) Dummv.lob.oho© ImportRecallAlRecordingsJob.php© ImportRemoteTrackJob.phpG Job.php(C).lohDisnatcher nhnSactivityIds = $activityServicesavedsearch. ssavedsearch,user. screacorJobDispatcherInterface.phpfrequency: SautomatedReport© PurgeSoftDeletedOpportunityJob 102SqsVisibilityControl.phpLocal chancesSheliConsoleLO0Tv Changes 12 filesE.env.local app© ActivityController.php app/Http/Controllers/API© AskJiminnyReportActivityService.php app/Services/Kiosk/AutomatedReports© AskJiminnyReportActivitvServiceTest.php tests/Unit/Services/Kiosk/AutomatediĐa72e71cc app/Jo© AutomatedReportsService.php app/Services/Kiosk/AutomatedReports© AutomatedReportsServiceTest.php tests/Unit/Services/Kiosk/AutomatedReports© JiminnyDebugCommand.php app/Console/Commandsphp loaaina.php confia€ PlavbackService.phv app/Services$logger->info(self::LOG_PREFIX . ' Fetched activity IDs', [C) Requestcenerateask.iminnvRevoroo,ono aoo/oos AutomatedReoortsi'automatedReportUuid' => $this->reportUuid,@ SvncTolntercom.ohp app/.Jobs/Teamphp web.oho routedUnversioned Files 8 files= env.nikilocal aooE.env.other appc CanAccossAiRenortstlest.nhn tests/Unit/Policies(C) CreateMockAsk.liminnvRenortRecultCommand.nhnann/Console/Commands/ReE ids tyt andTraw sal query sal annC) SimulateWehhooksCommand.nhnann/Console/Commands/Crm/HubsnotMLWERHOOK FIL TERING IMPI EMENTATION mdann= custom.log=laravel.log4 SF jiminny@localhost] XA HS_local (jiminny@localhost]& console [PKol)A console [EU]A console [STAGING]Tx: Autovdojiminny vB10 BI2 XLY4ACommit ChanaesChangelist: Changes437e-a9f9-7e75f8025c22'01V → AutomatedReports 1 fileV © RequestGenerateAskJiminnyReportJob.php^ ^ Team 1 fileAuthor:437e-a9f9-7e75f8025c22'91Amend commit437e-a9f9-7e75f8025c22').Sian-oft commitv = U Services 3 files5 modifiedCommit checksCommit MessageJY-18909 F1x max date check on uodate & include activity fiuteriUpdate copvriahiPoformat codeRearrange codeOptimize importsv Dift0 = 1Y04.Side-by-side viewer -8 a72e71cc app/.../RequestGenerateAskJimDo notignoreHighlight woras1olmerenceCurrent version$activityIds = $activityService->getActivsavedSearch: SsavedSearch,user: ScreatorSactivitvids = CactivitvSenvice->netActivsavedSearch: SsavedSearchusen• Cenpaton.101 Mfrequency: $automatedReport->getFrequ$logger->info(self::L06_PREFIX. ' Fetche'automatedReportUuid' => $this->repon$logger->info(self::L06_PREFIX . ' Fetcheeurrent version'auсomateaкeporcuuld = Schis->repolCancelcommit100% LMon Z0 AOr 12:3/:0/CascadeGroup Photo UrL RevRetactor UserPilot TraFixing Expiration Date+O •Fix alse the tests for this changeThe test uses 2099-01-01 which is clearly more than 1 year away — that still works fine after the fix. The fix only changes theboundary case (same anniversary day, different time). No existing tests break.However, there's a missing test: the boundary case where expires on is exactly 1 year from today with a time componentlater in the day (the scenario that was broken). Let me check if the testValidateAskJiminnyReportDataExpiresTooFar test isRead AutdThe existing tests are fine — 2099-01-01 still fails correctly. What's missing is a test proving that a date exactly 1 year fromnow (with a late time component is accepted, not rejected. Let me look at the end of the test tile to tind where to append:Read AUtoorisservicelest.pho #4100-4142Now let me check the imooris at the too to see what carbon alias is used.Read AutomatedReportsServiceTest.oho #L1-30AutomatedRenortsServiceTest.ohrView alltests/Unit/Services/Kiosk/AutomatedRenorts/MAutomatedRenortcServiceTest.nhv +55*Reject allAccent alliAsk anvthina (&4L)+ « CodeS Adaptive1 differenceSactivitvids= SactivitvService->aetActivitvIdsForSavedSearchdsavedSearch: $savedSearch,usen. Screaton.frequencv: SautomatedRenont->aetFrequencvOrs1oanen-sinfofcolf..I0G ppEFTy , Fetched activity Thetr'automatedReportUuid' => $this->reportUuid.08-64LITE.RIPo 4 spaces...
|
NULL
|
2475662293335397426
|
NULL
|
click
|
ocr
|
NULL
|
PhostormVIeWINavigarecodeLaravelKeractorTOOISmelpP PhostormVIeWINavigarecodeLaravelKeractorTOOISmelpProiect© Field.php© FieldRepository.phpD Audio© AskJiminnyReportActivityService.php(c) RequestGenerateAskJiminnyReportJoblest.onpD AutomatedReports• kecuestGenerateaskJiminnykkequestGeneratekeporJoo.orAskJiminnykeporiscontroller.phgVo) Astil© SendReportJob.phpc) senckeponmallJob.ong0 CalendarC) AutomatedReportsCommand.php(c) AutomatedReportsReposb ermC) CreateHeldActivityEvent.phpC) TrackProviderInstalledEventDealRiskSMailboxC) UserPilotActivitvListener.ohv© ActivityLogged.phpC) ReauestGenerateAsk.JiminnvReport.Job.ohv X (C) AutomatedRerclass RequestGenerateAskJiminnyReportJob impublic function handle(l TreamTelenhonvIstatus! => AutomatedRelm Use'media_type' => Automate© BaseProcessingJob.phpC) Dummv.lob.oho© ImportRecallAlRecordingsJob.php© ImportRemoteTrackJob.phpG Job.php(C).lohDisnatcher nhnSactivityIds = $activityServicesavedsearch. ssavedsearch,user. screacorJobDispatcherInterface.phpfrequency: SautomatedReport© PurgeSoftDeletedOpportunityJob 102SqsVisibilityControl.phpLocal chancesSheliConsoleLO0Tv Changes 12 filesE.env.local app© ActivityController.php app/Http/Controllers/API© AskJiminnyReportActivityService.php app/Services/Kiosk/AutomatedReports© AskJiminnyReportActivitvServiceTest.php tests/Unit/Services/Kiosk/AutomatediĐa72e71cc app/Jo© AutomatedReportsService.php app/Services/Kiosk/AutomatedReports© AutomatedReportsServiceTest.php tests/Unit/Services/Kiosk/AutomatedReports© JiminnyDebugCommand.php app/Console/Commandsphp loaaina.php confia€ PlavbackService.phv app/Services$logger->info(self::LOG_PREFIX . ' Fetched activity IDs', [C) Requestcenerateask.iminnvRevoroo,ono aoo/oos AutomatedReoortsi'automatedReportUuid' => $this->reportUuid,@ SvncTolntercom.ohp app/.Jobs/Teamphp web.oho routedUnversioned Files 8 files= env.nikilocal aooE.env.other appc CanAccossAiRenortstlest.nhn tests/Unit/Policies(C) CreateMockAsk.liminnvRenortRecultCommand.nhnann/Console/Commands/ReE ids tyt andTraw sal query sal annC) SimulateWehhooksCommand.nhnann/Console/Commands/Crm/HubsnotMLWERHOOK FIL TERING IMPI EMENTATION mdann= custom.log=laravel.log4 SF jiminny@localhost] XA HS_local (jiminny@localhost]& console [PKol)A console [EU]A console [STAGING]Tx: Autovdojiminny vB10 BI2 XLY4ACommit ChanaesChangelist: Changes437e-a9f9-7e75f8025c22'01V → AutomatedReports 1 fileV © RequestGenerateAskJiminnyReportJob.php^ ^ Team 1 fileAuthor:437e-a9f9-7e75f8025c22'91Amend commit437e-a9f9-7e75f8025c22').Sian-oft commitv = U Services 3 files5 modifiedCommit checksCommit MessageJY-18909 F1x max date check on uodate & include activity fiuteriUpdate copvriahiPoformat codeRearrange codeOptimize importsv Dift0 = 1Y04.Side-by-side viewer -8 a72e71cc app/.../RequestGenerateAskJimDo notignoreHighlight woras1olmerenceCurrent version$activityIds = $activityService->getActivsavedSearch: SsavedSearch,user: ScreatorSactivitvids = CactivitvSenvice->netActivsavedSearch: SsavedSearchusen• Cenpaton.101 Mfrequency: $automatedReport->getFrequ$logger->info(self::L06_PREFIX. ' Fetche'automatedReportUuid' => $this->repon$logger->info(self::L06_PREFIX . ' Fetcheeurrent version'auсomateaкeporcuuld = Schis->repolCancelcommit100% LMon Z0 AOr 12:3/:0/CascadeGroup Photo UrL RevRetactor UserPilot TraFixing Expiration Date+O •Fix alse the tests for this changeThe test uses 2099-01-01 which is clearly more than 1 year away — that still works fine after the fix. The fix only changes theboundary case (same anniversary day, different time). No existing tests break.However, there's a missing test: the boundary case where expires on is exactly 1 year from today with a time componentlater in the day (the scenario that was broken). Let me check if the testValidateAskJiminnyReportDataExpiresTooFar test isRead AutdThe existing tests are fine — 2099-01-01 still fails correctly. What's missing is a test proving that a date exactly 1 year fromnow (with a late time component is accepted, not rejected. Let me look at the end of the test tile to tind where to append:Read AUtoorisservicelest.pho #4100-4142Now let me check the imooris at the too to see what carbon alias is used.Read AutomatedReportsServiceTest.oho #L1-30AutomatedRenortsServiceTest.ohrView alltests/Unit/Services/Kiosk/AutomatedRenorts/MAutomatedRenortcServiceTest.nhv +55*Reject allAccent alliAsk anvthina (&4L)+ « CodeS Adaptive1 differenceSactivitvids= SactivitvService->aetActivitvIdsForSavedSearchdsavedSearch: $savedSearch,usen. Screaton.frequencv: SautomatedRenont->aetFrequencvOrs1oanen-sinfofcolf..I0G ppEFTy , Fetched activity Thetr'automatedReportUuid' => $this->reportUuid.08-64LITE.RIPo 4 spaces...
|
NULL
|
|
55196
|
NULL
|
0
|
2026-04-20T09:37:57.840940+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776677877840_m1.jpg...
|
PhpStorm
|
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Commit and Push…
⌥⌘K
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"Commit and Push…","depth":5,"bounds":{"left":0.0,"top":0.0,"width":0.08263889,"height":0.024444444},"role_description":"text"},{"role":"AXStaticText","text":"⌥⌘K","depth":5,"bounds":{"left":0.0,"top":0.0,"width":0.04236111,"height":0.024444444},"role_description":"text"}]...
|
2535035496832215689
|
306252506011271184
|
click
|
hybrid
|
NULL
|
Commit and Push…
⌥⌘K
iTerm2ShellEditViewSessionScr Commit and Push…
⌥⌘K
iTerm2ShellEditViewSessionScriptsProfilesWindowHelp‹$0APP (-zsh)883DOCKERO 81DEV (docker)882raw_sql_query.sqltests/Unit/Policies/CanAccessAiReportsTest.phpAPP (-zsh)-zsh• 84no changes added to commit (use "gitadd"and/or "git commit -a")lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git pullremote: Enumerating objects: 49,done.remote: Counting objects:100% (49/49),done.remote: Compressing objects: 100% (16/16),done.remote: Total 49 (delta 33), reused 49 (delta 33), pack-reused 0 (from 0)reused o (from 0)Unpacking objects: 100% (49/49), 9.18 KiB | 284.00 KiB/s, done.From github.com:jiminny/app1d10796eec..fec25f3343JY-20701-reschedule-HubSpot-processing -› origin/JY-20701-reschedule-HubSpot-processingAlready up to date.lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ csfixdocker exec-it docker_lamp_1./vendor/bin/php-cs-fixer fix--config=.php-cs-fixer.dist.php -v --using-cache=no --diffPHP CS Fixer 3.87.1 Alexander by Fabien Potencier, Dariusz Ruminski and contributors.PHPruntime:8.3.30Running analysis on 7 cores with 10 files perprocess.Parallelrunner is an experimental feature and may be unstable, use it at your own risk. Feedback highly appreciated!Loadedconfig default from-php-cs-fixer.dist.php".5603/5603100%+++@@1) app/Http/Controllers/API/V2/AskJiminnyReportsController.php (single_quote)begin diff/home.iminny/app/Http/Controllers/API/V2/AskJiminnyReportsController.php/home/jiminny/app/Http/Controllers/AP1/V2/AskJiminnyReportsController.php-89,7 +89,7 00*/public function update(Request Srequest, string Suuid): JsonResponse\Illuminate\Support\Facades\Log::channel('custom_channel')->info("UPDATE");(Illuminate|Support\Facades\Log::channel('custom_channel')->info('UPDATE');/** @var User Suser */Suser = Srequest->user();ffmpegО ₴85100% C47 8 Mon 20 Apr 12:37:57T₴1|-zsh₴6APPend diffFixed 1 of 5603 files in 42.363 seconds, 60.00 MB memory usedWhat's next:Try Docker Debug for seamless, persistent debugging tools in any container or image » docker debug docker_1amp_1Learn more at https://docs.docker.com/go/debug-cli/lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $D...
|
55194
|
|
55058
|
NULL
|
0
|
2026-04-20T09:32:51.032657+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776677571032_m1.jpg...
|
iTerm2
|
APP (-zsh)
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Last login: Mon Apr 20 10:16:41 on ttys007
Poetry Last login: Mon Apr 20 10:16:41 on ttys007
Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parents
Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parents
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ ;xd
docker exec -it docker_lamp_1 bash -c "mv /usr/local/etc/php/conf.d/xdebug.ini ~/xdebug.ini"
What's next:
Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1
Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co master
error: Your local changes to the following files would be overwritten by checkout:
app/Listeners/AutomatedReports/UserPilot/TrackAutomatedReportGeneratedEvent.php
tests/Unit/Listeners/AutomatedReports/UserPilot/TrackAutomatedReportGeneratedEventTest.php
Please commit your changes or stash them before you switch branches.
Aborting
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ csfix
docker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php -v --using-cache=no --diff
PHP CS Fixer 3.87.1 Alexander by Fabien Potencier, Dariusz Ruminski and contributors.
PHP runtime: 8.3.30
Running analysis on 7 cores with 10 files per process.
Parallel runner is an experimental feature and may be unstable, use it at your own risk. Feedback highly appreciated!
Loaded config default from ".php-cs-fixer.dist.php".
5603/5603 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%
Fixed 0 of 5603 files in 30.988 seconds, 60.00 MB memory used
What's next:
Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1
Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (master) $ co JY-18909-automated-reports-ask-jiminny
M .env.local
M app/Console/Commands/JiminnyDebugCommand.php
M app/Http/Controllers/API/ActivityController.php
M app/Jobs/Team/SyncToIntercom.php
M app/Services/PlaybackService.php
M config/logging.php
M routes/web.php
Switched to branch 'JY-18909-automated-reports-ask-jiminny'
Your branch and 'origin/JY-18909-automated-reports-ask-jiminny' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git status
On branch JY-18909-automated-reports-ask-jiminny
Your branch and 'origin/JY-18909-automated-reports-ask-jiminny' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: .env.local
modified: app/Console/Commands/JiminnyDebugCommand.php
modified: app/Http/Controllers/API/ActivityController.php
modified: app/Jobs/Team/SyncToIntercom.php
modified: app/Services/PlaybackService.php
modified: config/logging.php
modified: routes/web.php
Untracked files:
(use "git add <file>..." to include in what will be committed)
.env.nikilocal
.env.other
WEBHOOK_FILTERING_IMPLEMENTATION.md
app/Console/Commands/Crm/Hubspot/SimulateWebhooksCommand.php
app/Console/Commands/Reports/CreateMockAskJiminnyReportResultCommand.php
ids.txt
raw_sql_query.sql
tests/Unit/Policies/CanAccessAiReportsTest.php
no changes added to commit (use "git add" and/or "git commit -a")
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git pull
Merge made by the 'ort' strategy.
app/Jobs/AutomatedReports/RequestGenerateAskJiminnyReportJob.php | 2 +-
app/Repositories/AutomatedReportsRepository.php | 9 +++++++++
app/Services/Kiosk/AutomatedReports/AutomatedReportsService.php | 13 +++++++++++++
tests/Unit/Jobs/AutomatedReports/RequestGenerateAskJiminnyReportJobTest.php | 26 +++++++++++++-------------
4 files changed, 36 insertions(+), 14 deletions(-)
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git status
On branch JY-18909-automated-reports-ask-jiminny
Your branch is ahead of 'origin/JY-18909-automated-reports-ask-jiminny' by 2 commits.
(use "git push" to publish your local commits)
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: .env.local
modified: app/Console/Commands/JiminnyDebugCommand.php
modified: app/Http/Controllers/API/ActivityController.php
modified: app/Jobs/Team/SyncToIntercom.php
modified: app/Services/PlaybackService.php
modified: config/logging.php
modified: routes/web.php
Untracked files:
(use "git add <file>..." to include in what will be committed)
.env.nikilocal
.env.other
WEBHOOK_FILTERING_IMPLEMENTATION.md
app/Console/Commands/Crm/Hubspot/SimulateWebhooksCommand.php
app/Console/Commands/Reports/CreateMockAskJiminnyReportResultCommand.php
ids.txt
raw_sql_query.sql
tests/Unit/Policies/CanAccessAiReportsTest.php
no changes added to commit (use "git add" and/or "git commit -a")
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git push
Enumerating objects: 38, done.
Counting objects: 100% (32/32), done.
Delta compression using up to 8 threads
Compressing objects: 100% (16/16), done.
Writing objects: 100% (18/18), 1.97 KiB | 1008.00 KiB/s, done.
Total 18 (delta 12), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (12/12), completed with 9 local objects.
remote:
remote: GitHub found 22 vulnerabilities on jiminny/app's default branch (10 high, 12 moderate). To find out more, visit:
remote: [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co master
M .env.local
M app/Console/Commands/JiminnyDebugCommand.php
M app/Http/Controllers/API/ActivityController.php
M app/Jobs/Team/SyncToIntercom.php
M app/Services/PlaybackService.php
M config/logging.php
M routes/web.php
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ git pull
Already up to date.
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $
DOCKER
Close Tab
DEV (docker)
Close Tab
APP (-zsh)
Close Tab
-zsh
Close Tab
screenpipe"
Close Tab
-zsh
Close Tab
⌥⌘1
APP (-zsh)...
|
[{"role":"AXTextArea","text [{"role":"AXTextArea","text":"Last login: Mon Apr 20 10:16:41 on ttys007\n\nPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parents\n\nPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parents\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ ;xd\ndocker exec -it docker_lamp_1 bash -c \"mv /usr/local/etc/php/conf.d/xdebug.ini ~/xdebug.ini\"\n\nWhat's next:\n Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1\n Learn more at https://docs.docker.com/go/debug-cli/\ndocker exec -it docker_lamp_1 supervisorctl restart all\njiminny-worker-processing-2:jiminny-worker-processing-2_00: stopped\njiminny-worker-processing-3:jiminny-worker-processing-3_00: stopped\njiminny-worker-processing-4:jiminny-worker-processing-4_00: stopped\njiminny-worker-processing-5:jiminny-worker-processing-5_00: stopped\njiminny-worker-processing-delayed:jiminny-worker-processing-delayed_00: stopped\nworker-analytics:worker-analytics_00: stopped\nworker-crm-update:worker-crm-update_00: stopped\nworker-download:worker-download_00: stopped\nworker-nudges:worker-nudges_00: stopped\nworker-conferences:worker-conferences_00: stopped\njiminny-worker-processing-1:jiminny-worker-processing-1_00: stopped\nworker:worker_00: stopped\nworker-audio:worker-audio_00: stopped\nworker-calendar:worker-calendar_00: stopped\nworker-crm-sync:worker-crm-sync_00: stopped\nworker-emails:worker-emails_00: stopped\nartisan-schedule:artisan-schedule_00: stopped\nworker-es-update:worker-es-update_00: stopped\nartisan-schedule:artisan-schedule_00: started\njiminny-worker-processing-1:jiminny-worker-processing-1_00: started\njiminny-worker-processing-2:jiminny-worker-processing-2_00: started\njiminny-worker-processing-3:jiminny-worker-processing-3_00: started\njiminny-worker-processing-4:jiminny-worker-processing-4_00: started\njiminny-worker-processing-5:jiminny-worker-processing-5_00: started\njiminny-worker-processing-delayed:jiminny-worker-processing-delayed_00: started\nworker:worker_00: started\nworker-analytics:worker-analytics_00: started\nworker-audio:worker-audio_00: started\nworker-calendar:worker-calendar_00: started\nworker-conferences:worker-conferences_00: started\nworker-crm-sync:worker-crm-sync_00: started\nworker-crm-update:worker-crm-update_00: started\nworker-download:worker-download_00: started\nworker-emails:worker-emails_00: started\nworker-es-update:worker-es-update_00: started\nworker-nudges:worker-nudges_00: started\n\nWhat's next:\n Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1\n Learn more at https://docs.docker.com/go/debug-cli/\ndocker exec -it docker_lamp_1 php -v\nPHP 8.3.30 (cli) (built: Mar 16 2026 22:32:32) (NTS)\nCopyright (c) The PHP Group\nZend Engine v4.3.30, Copyright (c) Zend Technologies\n with Zend OPcache v8.3.30, Copyright (c), by Zend Technologies\n\nWhat's next:\n Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1\n Learn more at https://docs.docker.com/go/debug-cli/\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co master\nerror: Your local changes to the following files would be overwritten by checkout:\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Listeners/AutomatedReports/UserPilot/TrackAutomatedReportGeneratedEvent.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\ttests/Unit/Listeners/AutomatedReports/UserPilot/TrackAutomatedReportGeneratedEventTest.php\nPlease commit your changes or stash them before you switch branches.\nAborting\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ csfix\ndocker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php -v --using-cache=no --diff \nPHP CS Fixer 3.87.1 Alexander by Fabien Potencier, Dariusz Ruminski and contributors.\nPHP runtime: 8.3.30\nRunning analysis on 7 cores with 10 files per process.\nParallel runner is an experimental feature and may be unstable, use it at your own risk. Feedback highly appreciated!\nLoaded config default from \".php-cs-fixer.dist.php\".\n 5603/5603 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%\n\n\nFixed 0 of 5603 files in 30.988 seconds, 60.00 MB memory used\n\nWhat's next:\n Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1\n Learn more at https://docs.docker.com/go/debug-cli/\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co master\nM\u0000\u0000\u0000\u0000\u0000\u0000\t.env.local\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/JiminnyDebugCommand.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Http/Controllers/API/ActivityController.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Jobs/Team/SyncToIntercom.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Services/PlaybackService.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tconfig/logging.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\troutes/web.php\nSwitched to branch 'master'\nYour branch is up to date with 'origin/master'.\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ git pull\nremote: Enumerating objects: 73, done.\nremote: Counting objects: 100% (73/73), done.\nremote: Compressing objects: 100% (35/35), done.\nremote: Total 73 (delta 40), reused 69 (delta 38), pack-reused 0 (from 0)\nUnpacking objects: 100% (73/73), 12.37 KiB | 218.00 KiB/s, done.\nFrom github.com:jiminny/app\n eb5bb80e5b..12ac2f1273 master -> origin/master\n da535e5554..24292b55b9 JY-18909-automated-reports-ask-jiminny -> origin/JY-18909-automated-reports-ask-jiminny\n + f6c0ec3d8b...5928f606d3 JY-20553-debug-crm-sync-delays -> origin/JY-20553-debug-crm-sync-delays (forced update)\n + 3d7234a4c4...1d10796eec JY-20701-reschedule-HubSpot-processing -> origin/JY-20701-reschedule-HubSpot-processing (forced update)\nUpdating eb5bb80e5b..12ac2f1273\nFast-forward\n composer.lock | 46 +++++++++++++++++++++++-----------------------\n 1 file changed, 23 insertions(+), 23 deletions(-)\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co JY-18909-automated-reports-ask-jiminny\nM\u0000\u0000\u0000\u0000\u0000\u0000\t.env.local\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/JiminnyDebugCommand.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Http/Controllers/API/ActivityController.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Jobs/Team/SyncToIntercom.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Services/PlaybackService.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tconfig/logging.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\troutes/web.php\nSwitched to branch 'JY-18909-automated-reports-ask-jiminny'\nYour branch and 'origin/JY-18909-automated-reports-ask-jiminny' have diverged,\nand have 1 and 1 different commits each, respectively.\n (use \"git pull\" to merge the remote branch into yours)\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git status\nOn branch JY-18909-automated-reports-ask-jiminny\nYour branch and 'origin/JY-18909-automated-reports-ask-jiminny' have diverged,\nand have 1 and 1 different commits each, respectively.\n (use \"git pull\" to merge the remote branch into yours)\n\nChanges not staged for commit:\n (use \"git add <file>...\" to update what will be committed)\n (use \"git restore <file>...\" to discard changes in working directory)\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: .env.local\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Console/Commands/JiminnyDebugCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Http/Controllers/API/ActivityController.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Jobs/Team/SyncToIntercom.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Services/PlaybackService.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: config/logging.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: routes/web.php\n\nUntracked files:\n (use \"git add <file>...\" to include in what will be committed)\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\t.env.nikilocal\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\t.env.other\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tWEBHOOK_FILTERING_IMPLEMENTATION.md\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/Crm/Hubspot/SimulateWebhooksCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/Reports/CreateMockAskJiminnyReportResultCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tids.txt\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\traw_sql_query.sql\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\ttests/Unit/Policies/CanAccessAiReportsTest.php\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git pull\nMerge made by the 'ort' strategy.\n app/Jobs/AutomatedReports/RequestGenerateAskJiminnyReportJob.php | 2 +-\n app/Repositories/AutomatedReportsRepository.php | 9 +++++++++\n app/Services/Kiosk/AutomatedReports/AutomatedReportsService.php | 13 +++++++++++++\n tests/Unit/Jobs/AutomatedReports/RequestGenerateAskJiminnyReportJobTest.php | 26 +++++++++++++-------------\n 4 files changed, 36 insertions(+), 14 deletions(-)\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git status\nOn branch JY-18909-automated-reports-ask-jiminny\nYour branch is ahead of 'origin/JY-18909-automated-reports-ask-jiminny' by 2 commits.\n (use \"git push\" to publish your local commits)\n\nChanges not staged for commit:\n (use \"git add <file>...\" to update what will be committed)\n (use \"git restore <file>...\" to discard changes in working directory)\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: .env.local\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Console/Commands/JiminnyDebugCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Http/Controllers/API/ActivityController.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Jobs/Team/SyncToIntercom.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Services/PlaybackService.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: config/logging.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: routes/web.php\n\nUntracked files:\n (use \"git add <file>...\" to include in what will be committed)\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\t.env.nikilocal\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\t.env.other\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tWEBHOOK_FILTERING_IMPLEMENTATION.md\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/Crm/Hubspot/SimulateWebhooksCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/Reports/CreateMockAskJiminnyReportResultCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tids.txt\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\traw_sql_query.sql\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\ttests/Unit/Policies/CanAccessAiReportsTest.php\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git push\nEnumerating objects: 38, done.\nCounting objects: 100% (32/32), done.\nDelta compression using up to 8 threads\nCompressing objects: 100% (16/16), done.\nWriting objects: 100% (18/18), 1.97 KiB | 1008.00 KiB/s, done.\nTotal 18 (delta 12), reused 0 (delta 0), pack-reused 0\nremote: Resolving deltas: 100% (12/12), completed with 9 local objects.\nremote: \nremote: GitHub found 22 vulnerabilities on jiminny/app's default branch (10 high, 12 moderate). To find out more, visit:\nremote: https://github.com/jiminny/app/security/dependabot\nremote: \nTo github.com:jiminny/app.git\n 24292b55b9..a72e71cc23 JY-18909-automated-reports-ask-jiminny -> JY-18909-automated-reports-ask-jiminny\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co master\nM\u0000\u0000\u0000\u0000\u0000\u0000\t.env.local\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/JiminnyDebugCommand.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Http/Controllers/API/ActivityController.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Jobs/Team/SyncToIntercom.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Services/PlaybackService.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tconfig/logging.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\troutes/web.php\nSwitched to branch 'master'\nYour branch is up to date with 'origin/master'.\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ git pull\nAlready up to date.\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $","depth":4,"value":"Last login: Mon Apr 20 10:16:41 on ttys007\n\nPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parents\n\nPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parents\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ ;xd\ndocker exec -it docker_lamp_1 bash -c \"mv /usr/local/etc/php/conf.d/xdebug.ini ~/xdebug.ini\"\n\nWhat's next:\n Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1\n Learn more at https://docs.docker.com/go/debug-cli/\ndocker exec -it docker_lamp_1 supervisorctl restart all\njiminny-worker-processing-2:jiminny-worker-processing-2_00: stopped\njiminny-worker-processing-3:jiminny-worker-processing-3_00: stopped\njiminny-worker-processing-4:jiminny-worker-processing-4_00: stopped\njiminny-worker-processing-5:jiminny-worker-processing-5_00: stopped\njiminny-worker-processing-delayed:jiminny-worker-processing-delayed_00: stopped\nworker-analytics:worker-analytics_00: stopped\nworker-crm-update:worker-crm-update_00: stopped\nworker-download:worker-download_00: stopped\nworker-nudges:worker-nudges_00: stopped\nworker-conferences:worker-conferences_00: stopped\njiminny-worker-processing-1:jiminny-worker-processing-1_00: stopped\nworker:worker_00: stopped\nworker-audio:worker-audio_00: stopped\nworker-calendar:worker-calendar_00: stopped\nworker-crm-sync:worker-crm-sync_00: stopped\nworker-emails:worker-emails_00: stopped\nartisan-schedule:artisan-schedule_00: stopped\nworker-es-update:worker-es-update_00: stopped\nartisan-schedule:artisan-schedule_00: started\njiminny-worker-processing-1:jiminny-worker-processing-1_00: started\njiminny-worker-processing-2:jiminny-worker-processing-2_00: started\njiminny-worker-processing-3:jiminny-worker-processing-3_00: started\njiminny-worker-processing-4:jiminny-worker-processing-4_00: started\njiminny-worker-processing-5:jiminny-worker-processing-5_00: started\njiminny-worker-processing-delayed:jiminny-worker-processing-delayed_00: started\nworker:worker_00: started\nworker-analytics:worker-analytics_00: started\nworker-audio:worker-audio_00: started\nworker-calendar:worker-calendar_00: started\nworker-conferences:worker-conferences_00: started\nworker-crm-sync:worker-crm-sync_00: started\nworker-crm-update:worker-crm-update_00: started\nworker-download:worker-download_00: started\nworker-emails:worker-emails_00: started\nworker-es-update:worker-es-update_00: started\nworker-nudges:worker-nudges_00: started\n\nWhat's next:\n Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1\n Learn more at https://docs.docker.com/go/debug-cli/\ndocker exec -it docker_lamp_1 php -v\nPHP 8.3.30 (cli) (built: Mar 16 2026 22:32:32) (NTS)\nCopyright (c) The PHP Group\nZend Engine v4.3.30, Copyright (c) Zend Technologies\n with Zend OPcache v8.3.30, Copyright (c), by Zend Technologies\n\nWhat's next:\n Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1\n Learn more at https://docs.docker.com/go/debug-cli/\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co master\nerror: Your local changes to the following files would be overwritten by checkout:\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Listeners/AutomatedReports/UserPilot/TrackAutomatedReportGeneratedEvent.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\ttests/Unit/Listeners/AutomatedReports/UserPilot/TrackAutomatedReportGeneratedEventTest.php\nPlease commit your changes or stash them before you switch branches.\nAborting\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ csfix\ndocker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php -v --using-cache=no --diff \nPHP CS Fixer 3.87.1 Alexander by Fabien Potencier, Dariusz Ruminski and contributors.\nPHP runtime: 8.3.30\nRunning analysis on 7 cores with 10 files per process.\nParallel runner is an experimental feature and may be unstable, use it at your own risk. Feedback highly appreciated!\nLoaded config default from \".php-cs-fixer.dist.php\".\n 5603/5603 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%\n\n\nFixed 0 of 5603 files in 30.988 seconds, 60.00 MB memory used\n\nWhat's next:\n Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1\n Learn more at https://docs.docker.com/go/debug-cli/\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co master\nM\u0000\u0000\u0000\u0000\u0000\u0000\t.env.local\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/JiminnyDebugCommand.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Http/Controllers/API/ActivityController.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Jobs/Team/SyncToIntercom.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Services/PlaybackService.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tconfig/logging.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\troutes/web.php\nSwitched to branch 'master'\nYour branch is up to date with 'origin/master'.\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ git pull\nremote: Enumerating objects: 73, done.\nremote: Counting objects: 100% (73/73), done.\nremote: Compressing objects: 100% (35/35), done.\nremote: Total 73 (delta 40), reused 69 (delta 38), pack-reused 0 (from 0)\nUnpacking objects: 100% (73/73), 12.37 KiB | 218.00 KiB/s, done.\nFrom github.com:jiminny/app\n eb5bb80e5b..12ac2f1273 master -> origin/master\n da535e5554..24292b55b9 JY-18909-automated-reports-ask-jiminny -> origin/JY-18909-automated-reports-ask-jiminny\n + f6c0ec3d8b...5928f606d3 JY-20553-debug-crm-sync-delays -> origin/JY-20553-debug-crm-sync-delays (forced update)\n + 3d7234a4c4...1d10796eec JY-20701-reschedule-HubSpot-processing -> origin/JY-20701-reschedule-HubSpot-processing (forced update)\nUpdating eb5bb80e5b..12ac2f1273\nFast-forward\n composer.lock | 46 +++++++++++++++++++++++-----------------------\n 1 file changed, 23 insertions(+), 23 deletions(-)\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co JY-18909-automated-reports-ask-jiminny\nM\u0000\u0000\u0000\u0000\u0000\u0000\t.env.local\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/JiminnyDebugCommand.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Http/Controllers/API/ActivityController.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Jobs/Team/SyncToIntercom.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Services/PlaybackService.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tconfig/logging.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\troutes/web.php\nSwitched to branch 'JY-18909-automated-reports-ask-jiminny'\nYour branch and 'origin/JY-18909-automated-reports-ask-jiminny' have diverged,\nand have 1 and 1 different commits each, respectively.\n (use \"git pull\" to merge the remote branch into yours)\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git status\nOn branch JY-18909-automated-reports-ask-jiminny\nYour branch and 'origin/JY-18909-automated-reports-ask-jiminny' have diverged,\nand have 1 and 1 different commits each, respectively.\n (use \"git pull\" to merge the remote branch into yours)\n\nChanges not staged for commit:\n (use \"git add <file>...\" to update what will be committed)\n (use \"git restore <file>...\" to discard changes in working directory)\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: .env.local\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Console/Commands/JiminnyDebugCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Http/Controllers/API/ActivityController.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Jobs/Team/SyncToIntercom.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Services/PlaybackService.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: config/logging.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: routes/web.php\n\nUntracked files:\n (use \"git add <file>...\" to include in what will be committed)\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\t.env.nikilocal\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\t.env.other\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tWEBHOOK_FILTERING_IMPLEMENTATION.md\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/Crm/Hubspot/SimulateWebhooksCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/Reports/CreateMockAskJiminnyReportResultCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tids.txt\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\traw_sql_query.sql\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\ttests/Unit/Policies/CanAccessAiReportsTest.php\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git pull\nMerge made by the 'ort' strategy.\n app/Jobs/AutomatedReports/RequestGenerateAskJiminnyReportJob.php | 2 +-\n app/Repositories/AutomatedReportsRepository.php | 9 +++++++++\n app/Services/Kiosk/AutomatedReports/AutomatedReportsService.php | 13 +++++++++++++\n tests/Unit/Jobs/AutomatedReports/RequestGenerateAskJiminnyReportJobTest.php | 26 +++++++++++++-------------\n 4 files changed, 36 insertions(+), 14 deletions(-)\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git status\nOn branch JY-18909-automated-reports-ask-jiminny\nYour branch is ahead of 'origin/JY-18909-automated-reports-ask-jiminny' by 2 commits.\n (use \"git push\" to publish your local commits)\n\nChanges not staged for commit:\n (use \"git add <file>...\" to update what will be committed)\n (use \"git restore <file>...\" to discard changes in working directory)\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: .env.local\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Console/Commands/JiminnyDebugCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Http/Controllers/API/ActivityController.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Jobs/Team/SyncToIntercom.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Services/PlaybackService.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: config/logging.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: routes/web.php\n\nUntracked files:\n (use \"git add <file>...\" to include in what will be committed)\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\t.env.nikilocal\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\t.env.other\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tWEBHOOK_FILTERING_IMPLEMENTATION.md\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/Crm/Hubspot/SimulateWebhooksCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/Reports/CreateMockAskJiminnyReportResultCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tids.txt\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\traw_sql_query.sql\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\ttests/Unit/Policies/CanAccessAiReportsTest.php\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git push\nEnumerating objects: 38, done.\nCounting objects: 100% (32/32), done.\nDelta compression using up to 8 threads\nCompressing objects: 100% (16/16), done.\nWriting objects: 100% (18/18), 1.97 KiB | 1008.00 KiB/s, done.\nTotal 18 (delta 12), reused 0 (delta 0), pack-reused 0\nremote: Resolving deltas: 100% (12/12), completed with 9 local objects.\nremote: \nremote: GitHub found 22 vulnerabilities on jiminny/app's default branch (10 high, 12 moderate). To find out more, visit:\nremote: https://github.com/jiminny/app/security/dependabot\nremote: \nTo github.com:jiminny/app.git\n 24292b55b9..a72e71cc23 JY-18909-automated-reports-ask-jiminny -> JY-18909-automated-reports-ask-jiminny\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co master\nM\u0000\u0000\u0000\u0000\u0000\u0000\t.env.local\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/JiminnyDebugCommand.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Http/Controllers/API/ActivityController.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Jobs/Team/SyncToIntercom.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Services/PlaybackService.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tconfig/logging.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\troutes/web.php\nSwitched to branch 'master'\nYour branch is up to date with 'origin/master'.\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ git pull\nAlready up to date.\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $","is_focused":true},{"role":"AXRadioButton","text":"DOCKER","depth":2,"bounds":{"left":0.0,"top":0.05888889,"width":0.16458334,"height":0.026666667},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.004166667,"top":0.06333333,"width":0.011111111,"height":0.017777778},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"DEV (docker)","depth":2,"bounds":{"left":0.16458334,"top":0.05888889,"width":0.16458334,"height":0.026666667},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.16875,"top":0.06333333,"width":0.011111111,"height":0.017777778},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"APP (-zsh)","depth":2,"bounds":{"left":0.32916668,"top":0.05888889,"width":0.16423611,"height":0.026666667},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.33333334,"top":0.06333333,"width":0.011111111,"height":0.017777778},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"-zsh","depth":2,"bounds":{"left":0.49340278,"top":0.05888889,"width":0.16423611,"height":0.026666667},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.49756944,"top":0.06333333,"width":0.011111111,"height":0.017777778},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"screenpipe\"","depth":2,"bounds":{"left":0.6576389,"top":0.05888889,"width":0.16423611,"height":0.026666667},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.66180557,"top":0.06333333,"width":0.011111111,"height":0.017777778},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"-zsh","depth":2,"bounds":{"left":0.821875,"top":0.05888889,"width":0.16423611,"height":0.026666667},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.82604164,"top":0.06333333,"width":0.011111111,"height":0.017777778},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"⌥⌘1","depth":1,"bounds":{"left":0.95763886,"top":0.032222223,"width":0.03888889,"height":0.018888889},"automation_id":"_NS:8","role_description":"text"},{"role":"AXStaticText","text":"APP (-zsh)","depth":1,"bounds":{"left":0.47569445,"top":0.033333335,"width":0.05138889,"height":0.017777778},"role_description":"text"}]...
|
302347288687105374
|
-3130110898930441257
|
click
|
accessibility
|
NULL
|
Last login: Mon Apr 20 10:16:41 on ttys007
Poetry Last login: Mon Apr 20 10:16:41 on ttys007
Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parents
Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parents
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ ;xd
docker exec -it docker_lamp_1 bash -c "mv /usr/local/etc/php/conf.d/xdebug.ini ~/xdebug.ini"
What's next:
Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1
Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co master
error: Your local changes to the following files would be overwritten by checkout:
app/Listeners/AutomatedReports/UserPilot/TrackAutomatedReportGeneratedEvent.php
tests/Unit/Listeners/AutomatedReports/UserPilot/TrackAutomatedReportGeneratedEventTest.php
Please commit your changes or stash them before you switch branches.
Aborting
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ csfix
docker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php -v --using-cache=no --diff
PHP CS Fixer 3.87.1 Alexander by Fabien Potencier, Dariusz Ruminski and contributors.
PHP runtime: 8.3.30
Running analysis on 7 cores with 10 files per process.
Parallel runner is an experimental feature and may be unstable, use it at your own risk. Feedback highly appreciated!
Loaded config default from ".php-cs-fixer.dist.php".
5603/5603 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%
Fixed 0 of 5603 files in 30.988 seconds, 60.00 MB memory used
What's next:
Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1
Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (master) $ co JY-18909-automated-reports-ask-jiminny
M .env.local
M app/Console/Commands/JiminnyDebugCommand.php
M app/Http/Controllers/API/ActivityController.php
M app/Jobs/Team/SyncToIntercom.php
M app/Services/PlaybackService.php
M config/logging.php
M routes/web.php
Switched to branch 'JY-18909-automated-reports-ask-jiminny'
Your branch and 'origin/JY-18909-automated-reports-ask-jiminny' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git status
On branch JY-18909-automated-reports-ask-jiminny
Your branch and 'origin/JY-18909-automated-reports-ask-jiminny' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: .env.local
modified: app/Console/Commands/JiminnyDebugCommand.php
modified: app/Http/Controllers/API/ActivityController.php
modified: app/Jobs/Team/SyncToIntercom.php
modified: app/Services/PlaybackService.php
modified: config/logging.php
modified: routes/web.php
Untracked files:
(use "git add <file>..." to include in what will be committed)
.env.nikilocal
.env.other
WEBHOOK_FILTERING_IMPLEMENTATION.md
app/Console/Commands/Crm/Hubspot/SimulateWebhooksCommand.php
app/Console/Commands/Reports/CreateMockAskJiminnyReportResultCommand.php
ids.txt
raw_sql_query.sql
tests/Unit/Policies/CanAccessAiReportsTest.php
no changes added to commit (use "git add" and/or "git commit -a")
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git pull
Merge made by the 'ort' strategy.
app/Jobs/AutomatedReports/RequestGenerateAskJiminnyReportJob.php | 2 +-
app/Repositories/AutomatedReportsRepository.php | 9 +++++++++
app/Services/Kiosk/AutomatedReports/AutomatedReportsService.php | 13 +++++++++++++
tests/Unit/Jobs/AutomatedReports/RequestGenerateAskJiminnyReportJobTest.php | 26 +++++++++++++-------------
4 files changed, 36 insertions(+), 14 deletions(-)
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git status
On branch JY-18909-automated-reports-ask-jiminny
Your branch is ahead of 'origin/JY-18909-automated-reports-ask-jiminny' by 2 commits.
(use "git push" to publish your local commits)
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: .env.local
modified: app/Console/Commands/JiminnyDebugCommand.php
modified: app/Http/Controllers/API/ActivityController.php
modified: app/Jobs/Team/SyncToIntercom.php
modified: app/Services/PlaybackService.php
modified: config/logging.php
modified: routes/web.php
Untracked files:
(use "git add <file>..." to include in what will be committed)
.env.nikilocal
.env.other
WEBHOOK_FILTERING_IMPLEMENTATION.md
app/Console/Commands/Crm/Hubspot/SimulateWebhooksCommand.php
app/Console/Commands/Reports/CreateMockAskJiminnyReportResultCommand.php
ids.txt
raw_sql_query.sql
tests/Unit/Policies/CanAccessAiReportsTest.php
no changes added to commit (use "git add" and/or "git commit -a")
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git push
Enumerating objects: 38, done.
Counting objects: 100% (32/32), done.
Delta compression using up to 8 threads
Compressing objects: 100% (16/16), done.
Writing objects: 100% (18/18), 1.97 KiB | 1008.00 KiB/s, done.
Total 18 (delta 12), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (12/12), completed with 9 local objects.
remote:
remote: GitHub found 22 vulnerabilities on jiminny/app's default branch (10 high, 12 moderate). To find out more, visit:
remote: [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co master
M .env.local
M app/Console/Commands/JiminnyDebugCommand.php
M app/Http/Controllers/API/ActivityController.php
M app/Jobs/Team/SyncToIntercom.php
M app/Services/PlaybackService.php
M config/logging.php
M routes/web.php
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ git pull
Already up to date.
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $
DOCKER
Close Tab
DEV (docker)
Close Tab
APP (-zsh)
Close Tab
-zsh
Close Tab
screenpipe"
Close Tab
-zsh
Close Tab
⌥⌘1
APP (-zsh)...
|
NULL
|
|
55057
|
NULL
|
0
|
2026-04-20T09:32:50.937555+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776677570937_m2.jpg...
|
iTerm2
|
APP (-zsh)
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Last login: Mon Apr 20 10:16:41 on ttys007
Poetry Last login: Mon Apr 20 10:16:41 on ttys007
Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parents
Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parents
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ ;xd
docker exec -it docker_lamp_1 bash -c "mv /usr/local/etc/php/conf.d/xdebug.ini ~/xdebug.ini"
What's next:
Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1
Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co master
error: Your local changes to the following files would be overwritten by checkout:
app/Listeners/AutomatedReports/UserPilot/TrackAutomatedReportGeneratedEvent.php
tests/Unit/Listeners/AutomatedReports/UserPilot/TrackAutomatedReportGeneratedEventTest.php
Please commit your changes or stash them before you switch branches.
Aborting
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ csfix
docker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php -v --using-cache=no --diff
PHP CS Fixer 3.87.1 Alexander by Fabien Potencier, Dariusz Ruminski and contributors.
PHP runtime: 8.3.30
Running analysis on 7 cores with 10 files per process.
Parallel runner is an experimental feature and may be unstable, use it at your own risk. Feedback highly appreciated!
Loaded config default from ".php-cs-fixer.dist.php".
5603/5603 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%
Fixed 0 of 5603 files in 30.988 seconds, 60.00 MB memory used
What's next:
Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1
Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (master) $ co JY-18909-automated-reports-ask-jiminny
M .env.local
M app/Console/Commands/JiminnyDebugCommand.php
M app/Http/Controllers/API/ActivityController.php
M app/Jobs/Team/SyncToIntercom.php
M app/Services/PlaybackService.php
M config/logging.php
M routes/web.php
Switched to branch 'JY-18909-automated-reports-ask-jiminny'
Your branch and 'origin/JY-18909-automated-reports-ask-jiminny' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git status
On branch JY-18909-automated-reports-ask-jiminny
Your branch and 'origin/JY-18909-automated-reports-ask-jiminny' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: .env.local
modified: app/Console/Commands/JiminnyDebugCommand.php
modified: app/Http/Controllers/API/ActivityController.php
modified: app/Jobs/Team/SyncToIntercom.php
modified: app/Services/PlaybackService.php
modified: config/logging.php
modified: routes/web.php
Untracked files:
(use "git add <file>..." to include in what will be committed)
.env.nikilocal
.env.other
WEBHOOK_FILTERING_IMPLEMENTATION.md
app/Console/Commands/Crm/Hubspot/SimulateWebhooksCommand.php
app/Console/Commands/Reports/CreateMockAskJiminnyReportResultCommand.php
ids.txt
raw_sql_query.sql
tests/Unit/Policies/CanAccessAiReportsTest.php
no changes added to commit (use "git add" and/or "git commit -a")
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git pull
Merge made by the 'ort' strategy.
app/Jobs/AutomatedReports/RequestGenerateAskJiminnyReportJob.php | 2 +-
app/Repositories/AutomatedReportsRepository.php | 9 +++++++++
app/Services/Kiosk/AutomatedReports/AutomatedReportsService.php | 13 +++++++++++++
tests/Unit/Jobs/AutomatedReports/RequestGenerateAskJiminnyReportJobTest.php | 26 +++++++++++++-------------
4 files changed, 36 insertions(+), 14 deletions(-)
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git status
On branch JY-18909-automated-reports-ask-jiminny
Your branch is ahead of 'origin/JY-18909-automated-reports-ask-jiminny' by 2 commits.
(use "git push" to publish your local commits)
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: .env.local
modified: app/Console/Commands/JiminnyDebugCommand.php
modified: app/Http/Controllers/API/ActivityController.php
modified: app/Jobs/Team/SyncToIntercom.php
modified: app/Services/PlaybackService.php
modified: config/logging.php
modified: routes/web.php
Untracked files:
(use "git add <file>..." to include in what will be committed)
.env.nikilocal
.env.other
WEBHOOK_FILTERING_IMPLEMENTATION.md
app/Console/Commands/Crm/Hubspot/SimulateWebhooksCommand.php
app/Console/Commands/Reports/CreateMockAskJiminnyReportResultCommand.php
ids.txt
raw_sql_query.sql
tests/Unit/Policies/CanAccessAiReportsTest.php
no changes added to commit (use "git add" and/or "git commit -a")
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git push
Enumerating objects: 38, done.
Counting objects: 100% (32/32), done.
Delta compression using up to 8 threads
Compressing objects: 100% (16/16), done.
Writing objects: 100% (18/18), 1.97 KiB | 1008.00 KiB/s, done.
Total 18 (delta 12), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (12/12), completed with 9 local objects.
remote:
remote: GitHub found 22 vulnerabilities on jiminny/app's default branch (10 high, 12 moderate). To find out more, visit:
remote: [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co master
M .env.local
M app/Console/Commands/JiminnyDebugCommand.php
M app/Http/Controllers/API/ActivityController.php
M app/Jobs/Team/SyncToIntercom.php
M app/Services/PlaybackService.php
M config/logging.php
M routes/web.php
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ git pull
Already up to date.
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $
DOCKER
Close Tab
DEV (docker)
Close Tab
APP (-zsh)
Close Tab
-zsh
Close Tab
screenpipe"
Close Tab
-zsh
Close Tab
⌥⌘1
APP (-zsh)...
|
[{"role":"AXTextArea","text [{"role":"AXTextArea","text":"Last login: Mon Apr 20 10:16:41 on ttys007\n\nPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parents\n\nPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parents\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ ;xd\ndocker exec -it docker_lamp_1 bash -c \"mv /usr/local/etc/php/conf.d/xdebug.ini ~/xdebug.ini\"\n\nWhat's next:\n Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1\n Learn more at https://docs.docker.com/go/debug-cli/\ndocker exec -it docker_lamp_1 supervisorctl restart all\njiminny-worker-processing-2:jiminny-worker-processing-2_00: stopped\njiminny-worker-processing-3:jiminny-worker-processing-3_00: stopped\njiminny-worker-processing-4:jiminny-worker-processing-4_00: stopped\njiminny-worker-processing-5:jiminny-worker-processing-5_00: stopped\njiminny-worker-processing-delayed:jiminny-worker-processing-delayed_00: stopped\nworker-analytics:worker-analytics_00: stopped\nworker-crm-update:worker-crm-update_00: stopped\nworker-download:worker-download_00: stopped\nworker-nudges:worker-nudges_00: stopped\nworker-conferences:worker-conferences_00: stopped\njiminny-worker-processing-1:jiminny-worker-processing-1_00: stopped\nworker:worker_00: stopped\nworker-audio:worker-audio_00: stopped\nworker-calendar:worker-calendar_00: stopped\nworker-crm-sync:worker-crm-sync_00: stopped\nworker-emails:worker-emails_00: stopped\nartisan-schedule:artisan-schedule_00: stopped\nworker-es-update:worker-es-update_00: stopped\nartisan-schedule:artisan-schedule_00: started\njiminny-worker-processing-1:jiminny-worker-processing-1_00: started\njiminny-worker-processing-2:jiminny-worker-processing-2_00: started\njiminny-worker-processing-3:jiminny-worker-processing-3_00: started\njiminny-worker-processing-4:jiminny-worker-processing-4_00: started\njiminny-worker-processing-5:jiminny-worker-processing-5_00: started\njiminny-worker-processing-delayed:jiminny-worker-processing-delayed_00: started\nworker:worker_00: started\nworker-analytics:worker-analytics_00: started\nworker-audio:worker-audio_00: started\nworker-calendar:worker-calendar_00: started\nworker-conferences:worker-conferences_00: started\nworker-crm-sync:worker-crm-sync_00: started\nworker-crm-update:worker-crm-update_00: started\nworker-download:worker-download_00: started\nworker-emails:worker-emails_00: started\nworker-es-update:worker-es-update_00: started\nworker-nudges:worker-nudges_00: started\n\nWhat's next:\n Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1\n Learn more at https://docs.docker.com/go/debug-cli/\ndocker exec -it docker_lamp_1 php -v\nPHP 8.3.30 (cli) (built: Mar 16 2026 22:32:32) (NTS)\nCopyright (c) The PHP Group\nZend Engine v4.3.30, Copyright (c) Zend Technologies\n with Zend OPcache v8.3.30, Copyright (c), by Zend Technologies\n\nWhat's next:\n Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1\n Learn more at https://docs.docker.com/go/debug-cli/\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co master\nerror: Your local changes to the following files would be overwritten by checkout:\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Listeners/AutomatedReports/UserPilot/TrackAutomatedReportGeneratedEvent.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\ttests/Unit/Listeners/AutomatedReports/UserPilot/TrackAutomatedReportGeneratedEventTest.php\nPlease commit your changes or stash them before you switch branches.\nAborting\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ csfix\ndocker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php -v --using-cache=no --diff \nPHP CS Fixer 3.87.1 Alexander by Fabien Potencier, Dariusz Ruminski and contributors.\nPHP runtime: 8.3.30\nRunning analysis on 7 cores with 10 files per process.\nParallel runner is an experimental feature and may be unstable, use it at your own risk. Feedback highly appreciated!\nLoaded config default from \".php-cs-fixer.dist.php\".\n 5603/5603 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%\n\n\nFixed 0 of 5603 files in 30.988 seconds, 60.00 MB memory used\n\nWhat's next:\n Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1\n Learn more at https://docs.docker.com/go/debug-cli/\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co master\nM\u0000\u0000\u0000\u0000\u0000\u0000\t.env.local\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/JiminnyDebugCommand.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Http/Controllers/API/ActivityController.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Jobs/Team/SyncToIntercom.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Services/PlaybackService.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tconfig/logging.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\troutes/web.php\nSwitched to branch 'master'\nYour branch is up to date with 'origin/master'.\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ git pull\nremote: Enumerating objects: 73, done.\nremote: Counting objects: 100% (73/73), done.\nremote: Compressing objects: 100% (35/35), done.\nremote: Total 73 (delta 40), reused 69 (delta 38), pack-reused 0 (from 0)\nUnpacking objects: 100% (73/73), 12.37 KiB | 218.00 KiB/s, done.\nFrom github.com:jiminny/app\n eb5bb80e5b..12ac2f1273 master -> origin/master\n da535e5554..24292b55b9 JY-18909-automated-reports-ask-jiminny -> origin/JY-18909-automated-reports-ask-jiminny\n + f6c0ec3d8b...5928f606d3 JY-20553-debug-crm-sync-delays -> origin/JY-20553-debug-crm-sync-delays (forced update)\n + 3d7234a4c4...1d10796eec JY-20701-reschedule-HubSpot-processing -> origin/JY-20701-reschedule-HubSpot-processing (forced update)\nUpdating eb5bb80e5b..12ac2f1273\nFast-forward\n composer.lock | 46 +++++++++++++++++++++++-----------------------\n 1 file changed, 23 insertions(+), 23 deletions(-)\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co JY-18909-automated-reports-ask-jiminny\nM\u0000\u0000\u0000\u0000\u0000\u0000\t.env.local\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/JiminnyDebugCommand.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Http/Controllers/API/ActivityController.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Jobs/Team/SyncToIntercom.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Services/PlaybackService.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tconfig/logging.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\troutes/web.php\nSwitched to branch 'JY-18909-automated-reports-ask-jiminny'\nYour branch and 'origin/JY-18909-automated-reports-ask-jiminny' have diverged,\nand have 1 and 1 different commits each, respectively.\n (use \"git pull\" to merge the remote branch into yours)\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git status\nOn branch JY-18909-automated-reports-ask-jiminny\nYour branch and 'origin/JY-18909-automated-reports-ask-jiminny' have diverged,\nand have 1 and 1 different commits each, respectively.\n (use \"git pull\" to merge the remote branch into yours)\n\nChanges not staged for commit:\n (use \"git add <file>...\" to update what will be committed)\n (use \"git restore <file>...\" to discard changes in working directory)\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: .env.local\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Console/Commands/JiminnyDebugCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Http/Controllers/API/ActivityController.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Jobs/Team/SyncToIntercom.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Services/PlaybackService.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: config/logging.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: routes/web.php\n\nUntracked files:\n (use \"git add <file>...\" to include in what will be committed)\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\t.env.nikilocal\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\t.env.other\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tWEBHOOK_FILTERING_IMPLEMENTATION.md\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/Crm/Hubspot/SimulateWebhooksCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/Reports/CreateMockAskJiminnyReportResultCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tids.txt\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\traw_sql_query.sql\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\ttests/Unit/Policies/CanAccessAiReportsTest.php\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git pull\nMerge made by the 'ort' strategy.\n app/Jobs/AutomatedReports/RequestGenerateAskJiminnyReportJob.php | 2 +-\n app/Repositories/AutomatedReportsRepository.php | 9 +++++++++\n app/Services/Kiosk/AutomatedReports/AutomatedReportsService.php | 13 +++++++++++++\n tests/Unit/Jobs/AutomatedReports/RequestGenerateAskJiminnyReportJobTest.php | 26 +++++++++++++-------------\n 4 files changed, 36 insertions(+), 14 deletions(-)\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git status\nOn branch JY-18909-automated-reports-ask-jiminny\nYour branch is ahead of 'origin/JY-18909-automated-reports-ask-jiminny' by 2 commits.\n (use \"git push\" to publish your local commits)\n\nChanges not staged for commit:\n (use \"git add <file>...\" to update what will be committed)\n (use \"git restore <file>...\" to discard changes in working directory)\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: .env.local\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Console/Commands/JiminnyDebugCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Http/Controllers/API/ActivityController.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Jobs/Team/SyncToIntercom.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Services/PlaybackService.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: config/logging.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: routes/web.php\n\nUntracked files:\n (use \"git add <file>...\" to include in what will be committed)\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\t.env.nikilocal\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\t.env.other\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tWEBHOOK_FILTERING_IMPLEMENTATION.md\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/Crm/Hubspot/SimulateWebhooksCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/Reports/CreateMockAskJiminnyReportResultCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tids.txt\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\traw_sql_query.sql\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\ttests/Unit/Policies/CanAccessAiReportsTest.php\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git push\nEnumerating objects: 38, done.\nCounting objects: 100% (32/32), done.\nDelta compression using up to 8 threads\nCompressing objects: 100% (16/16), done.\nWriting objects: 100% (18/18), 1.97 KiB | 1008.00 KiB/s, done.\nTotal 18 (delta 12), reused 0 (delta 0), pack-reused 0\nremote: Resolving deltas: 100% (12/12), completed with 9 local objects.\nremote: \nremote: GitHub found 22 vulnerabilities on jiminny/app's default branch (10 high, 12 moderate). To find out more, visit:\nremote: https://github.com/jiminny/app/security/dependabot\nremote: \nTo github.com:jiminny/app.git\n 24292b55b9..a72e71cc23 JY-18909-automated-reports-ask-jiminny -> JY-18909-automated-reports-ask-jiminny\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co master\nM\u0000\u0000\u0000\u0000\u0000\u0000\t.env.local\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/JiminnyDebugCommand.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Http/Controllers/API/ActivityController.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Jobs/Team/SyncToIntercom.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Services/PlaybackService.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tconfig/logging.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\troutes/web.php\nSwitched to branch 'master'\nYour branch is up to date with 'origin/master'.\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ git pull\nAlready up to date.\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $","depth":4,"value":"Last login: Mon Apr 20 10:16:41 on ttys007\n\nPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parents\n\nPoetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parents\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ ;xd\ndocker exec -it docker_lamp_1 bash -c \"mv /usr/local/etc/php/conf.d/xdebug.ini ~/xdebug.ini\"\n\nWhat's next:\n Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1\n Learn more at https://docs.docker.com/go/debug-cli/\ndocker exec -it docker_lamp_1 supervisorctl restart all\njiminny-worker-processing-2:jiminny-worker-processing-2_00: stopped\njiminny-worker-processing-3:jiminny-worker-processing-3_00: stopped\njiminny-worker-processing-4:jiminny-worker-processing-4_00: stopped\njiminny-worker-processing-5:jiminny-worker-processing-5_00: stopped\njiminny-worker-processing-delayed:jiminny-worker-processing-delayed_00: stopped\nworker-analytics:worker-analytics_00: stopped\nworker-crm-update:worker-crm-update_00: stopped\nworker-download:worker-download_00: stopped\nworker-nudges:worker-nudges_00: stopped\nworker-conferences:worker-conferences_00: stopped\njiminny-worker-processing-1:jiminny-worker-processing-1_00: stopped\nworker:worker_00: stopped\nworker-audio:worker-audio_00: stopped\nworker-calendar:worker-calendar_00: stopped\nworker-crm-sync:worker-crm-sync_00: stopped\nworker-emails:worker-emails_00: stopped\nartisan-schedule:artisan-schedule_00: stopped\nworker-es-update:worker-es-update_00: stopped\nartisan-schedule:artisan-schedule_00: started\njiminny-worker-processing-1:jiminny-worker-processing-1_00: started\njiminny-worker-processing-2:jiminny-worker-processing-2_00: started\njiminny-worker-processing-3:jiminny-worker-processing-3_00: started\njiminny-worker-processing-4:jiminny-worker-processing-4_00: started\njiminny-worker-processing-5:jiminny-worker-processing-5_00: started\njiminny-worker-processing-delayed:jiminny-worker-processing-delayed_00: started\nworker:worker_00: started\nworker-analytics:worker-analytics_00: started\nworker-audio:worker-audio_00: started\nworker-calendar:worker-calendar_00: started\nworker-conferences:worker-conferences_00: started\nworker-crm-sync:worker-crm-sync_00: started\nworker-crm-update:worker-crm-update_00: started\nworker-download:worker-download_00: started\nworker-emails:worker-emails_00: started\nworker-es-update:worker-es-update_00: started\nworker-nudges:worker-nudges_00: started\n\nWhat's next:\n Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1\n Learn more at https://docs.docker.com/go/debug-cli/\ndocker exec -it docker_lamp_1 php -v\nPHP 8.3.30 (cli) (built: Mar 16 2026 22:32:32) (NTS)\nCopyright (c) The PHP Group\nZend Engine v4.3.30, Copyright (c) Zend Technologies\n with Zend OPcache v8.3.30, Copyright (c), by Zend Technologies\n\nWhat's next:\n Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1\n Learn more at https://docs.docker.com/go/debug-cli/\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co master\nerror: Your local changes to the following files would be overwritten by checkout:\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Listeners/AutomatedReports/UserPilot/TrackAutomatedReportGeneratedEvent.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\ttests/Unit/Listeners/AutomatedReports/UserPilot/TrackAutomatedReportGeneratedEventTest.php\nPlease commit your changes or stash them before you switch branches.\nAborting\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ csfix\ndocker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php -v --using-cache=no --diff \nPHP CS Fixer 3.87.1 Alexander by Fabien Potencier, Dariusz Ruminski and contributors.\nPHP runtime: 8.3.30\nRunning analysis on 7 cores with 10 files per process.\nParallel runner is an experimental feature and may be unstable, use it at your own risk. Feedback highly appreciated!\nLoaded config default from \".php-cs-fixer.dist.php\".\n 5603/5603 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%\n\n\nFixed 0 of 5603 files in 30.988 seconds, 60.00 MB memory used\n\nWhat's next:\n Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1\n Learn more at https://docs.docker.com/go/debug-cli/\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co master\nM\u0000\u0000\u0000\u0000\u0000\u0000\t.env.local\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/JiminnyDebugCommand.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Http/Controllers/API/ActivityController.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Jobs/Team/SyncToIntercom.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Services/PlaybackService.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tconfig/logging.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\troutes/web.php\nSwitched to branch 'master'\nYour branch is up to date with 'origin/master'.\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ git pull\nremote: Enumerating objects: 73, done.\nremote: Counting objects: 100% (73/73), done.\nremote: Compressing objects: 100% (35/35), done.\nremote: Total 73 (delta 40), reused 69 (delta 38), pack-reused 0 (from 0)\nUnpacking objects: 100% (73/73), 12.37 KiB | 218.00 KiB/s, done.\nFrom github.com:jiminny/app\n eb5bb80e5b..12ac2f1273 master -> origin/master\n da535e5554..24292b55b9 JY-18909-automated-reports-ask-jiminny -> origin/JY-18909-automated-reports-ask-jiminny\n + f6c0ec3d8b...5928f606d3 JY-20553-debug-crm-sync-delays -> origin/JY-20553-debug-crm-sync-delays (forced update)\n + 3d7234a4c4...1d10796eec JY-20701-reschedule-HubSpot-processing -> origin/JY-20701-reschedule-HubSpot-processing (forced update)\nUpdating eb5bb80e5b..12ac2f1273\nFast-forward\n composer.lock | 46 +++++++++++++++++++++++-----------------------\n 1 file changed, 23 insertions(+), 23 deletions(-)\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ co JY-18909-automated-reports-ask-jiminny\nM\u0000\u0000\u0000\u0000\u0000\u0000\t.env.local\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/JiminnyDebugCommand.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Http/Controllers/API/ActivityController.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Jobs/Team/SyncToIntercom.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Services/PlaybackService.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tconfig/logging.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\troutes/web.php\nSwitched to branch 'JY-18909-automated-reports-ask-jiminny'\nYour branch and 'origin/JY-18909-automated-reports-ask-jiminny' have diverged,\nand have 1 and 1 different commits each, respectively.\n (use \"git pull\" to merge the remote branch into yours)\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git status\nOn branch JY-18909-automated-reports-ask-jiminny\nYour branch and 'origin/JY-18909-automated-reports-ask-jiminny' have diverged,\nand have 1 and 1 different commits each, respectively.\n (use \"git pull\" to merge the remote branch into yours)\n\nChanges not staged for commit:\n (use \"git add <file>...\" to update what will be committed)\n (use \"git restore <file>...\" to discard changes in working directory)\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: .env.local\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Console/Commands/JiminnyDebugCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Http/Controllers/API/ActivityController.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Jobs/Team/SyncToIntercom.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Services/PlaybackService.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: config/logging.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: routes/web.php\n\nUntracked files:\n (use \"git add <file>...\" to include in what will be committed)\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\t.env.nikilocal\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\t.env.other\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tWEBHOOK_FILTERING_IMPLEMENTATION.md\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/Crm/Hubspot/SimulateWebhooksCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/Reports/CreateMockAskJiminnyReportResultCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tids.txt\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\traw_sql_query.sql\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\ttests/Unit/Policies/CanAccessAiReportsTest.php\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git pull\nMerge made by the 'ort' strategy.\n app/Jobs/AutomatedReports/RequestGenerateAskJiminnyReportJob.php | 2 +-\n app/Repositories/AutomatedReportsRepository.php | 9 +++++++++\n app/Services/Kiosk/AutomatedReports/AutomatedReportsService.php | 13 +++++++++++++\n tests/Unit/Jobs/AutomatedReports/RequestGenerateAskJiminnyReportJobTest.php | 26 +++++++++++++-------------\n 4 files changed, 36 insertions(+), 14 deletions(-)\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git status\nOn branch JY-18909-automated-reports-ask-jiminny\nYour branch is ahead of 'origin/JY-18909-automated-reports-ask-jiminny' by 2 commits.\n (use \"git push\" to publish your local commits)\n\nChanges not staged for commit:\n (use \"git add <file>...\" to update what will be committed)\n (use \"git restore <file>...\" to discard changes in working directory)\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: .env.local\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Console/Commands/JiminnyDebugCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Http/Controllers/API/ActivityController.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Jobs/Team/SyncToIntercom.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: app/Services/PlaybackService.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: config/logging.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tmodified: routes/web.php\n\nUntracked files:\n (use \"git add <file>...\" to include in what will be committed)\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\t.env.nikilocal\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\t.env.other\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tWEBHOOK_FILTERING_IMPLEMENTATION.md\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/Crm/Hubspot/SimulateWebhooksCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/Reports/CreateMockAskJiminnyReportResultCommand.php\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\tids.txt\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\traw_sql_query.sql\n\u0000\u0000\u0000\u0000\u0000\u0000\u0000\ttests/Unit/Policies/CanAccessAiReportsTest.php\n\nno changes added to commit (use \"git add\" and/or \"git commit -a\")\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git push\nEnumerating objects: 38, done.\nCounting objects: 100% (32/32), done.\nDelta compression using up to 8 threads\nCompressing objects: 100% (16/16), done.\nWriting objects: 100% (18/18), 1.97 KiB | 1008.00 KiB/s, done.\nTotal 18 (delta 12), reused 0 (delta 0), pack-reused 0\nremote: Resolving deltas: 100% (12/12), completed with 9 local objects.\nremote: \nremote: GitHub found 22 vulnerabilities on jiminny/app's default branch (10 high, 12 moderate). To find out more, visit:\nremote: https://github.com/jiminny/app/security/dependabot\nremote: \nTo github.com:jiminny/app.git\n 24292b55b9..a72e71cc23 JY-18909-automated-reports-ask-jiminny -> JY-18909-automated-reports-ask-jiminny\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co master\nM\u0000\u0000\u0000\u0000\u0000\u0000\t.env.local\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Console/Commands/JiminnyDebugCommand.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Http/Controllers/API/ActivityController.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Jobs/Team/SyncToIntercom.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tapp/Services/PlaybackService.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\tconfig/logging.php\nM\u0000\u0000\u0000\u0000\u0000\u0000\troutes/web.php\nSwitched to branch 'master'\nYour branch is up to date with 'origin/master'.\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ git pull\nAlready up to date.\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $","is_focused":true},{"role":"AXRadioButton","text":"DOCKER","depth":2,"bounds":{"left":0.27027926,"top":1.0,"width":0.0787899,"height":-0.042298436},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.27227393,"top":1.0,"width":0.005319149,"height":-0.04549086},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"DEV (docker)","depth":2,"bounds":{"left":0.34906915,"top":1.0,"width":0.0787899,"height":-0.042298436},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.35106382,"top":1.0,"width":0.005319149,"height":-0.04549086},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"APP (-zsh)","depth":2,"bounds":{"left":0.42785904,"top":1.0,"width":0.07862367,"height":-0.042298436},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.42985374,"top":1.0,"width":0.005319149,"height":-0.04549086},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"-zsh","depth":2,"bounds":{"left":0.5064827,"top":1.0,"width":0.07862367,"height":-0.042298436},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.5084774,"top":1.0,"width":0.005319149,"height":-0.04549086},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"screenpipe\"","depth":2,"bounds":{"left":0.5851064,"top":1.0,"width":0.07862367,"height":-0.042298436},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.58710104,"top":1.0,"width":0.005319149,"height":-0.04549086},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"-zsh","depth":2,"bounds":{"left":0.66373,"top":1.0,"width":0.07862367,"height":-0.042298436},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.66572475,"top":1.0,"width":0.005319149,"height":-0.04549086},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"⌥⌘1","depth":1,"bounds":{"left":0.7287234,"top":1.0,"width":0.01861702,"height":-0.023144484},"automation_id":"_NS:8","role_description":"text"},{"role":"AXStaticText","text":"APP (-zsh)","depth":1,"bounds":{"left":0.49800533,"top":1.0,"width":0.024601065,"height":-0.02394259},"role_description":"text"}]...
|
302347288687105374
|
-3130110898930441257
|
click
|
accessibility
|
NULL
|
Last login: Mon Apr 20 10:16:41 on ttys007
Poetry Last login: Mon Apr 20 10:16:41 on ttys007
Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parents
Poetry could not find a pyproject.toml file in /Users/lukas/jiminny/app or its parents
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ ;xd
docker exec -it docker_lamp_1 bash -c "mv /usr/local/etc/php/conf.d/xdebug.ini ~/xdebug.ini"
What's next:
Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1
Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co master
error: Your local changes to the following files would be overwritten by checkout:
app/Listeners/AutomatedReports/UserPilot/TrackAutomatedReportGeneratedEvent.php
tests/Unit/Listeners/AutomatedReports/UserPilot/TrackAutomatedReportGeneratedEventTest.php
Please commit your changes or stash them before you switch branches.
Aborting
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ csfix
docker exec -it docker_lamp_1 ./vendor/bin/php-cs-fixer fix --config=.php-cs-fixer.dist.php -v --using-cache=no --diff
PHP CS Fixer 3.87.1 Alexander by Fabien Potencier, Dariusz Ruminski and contributors.
PHP runtime: 8.3.30
Running analysis on 7 cores with 10 files per process.
Parallel runner is an experimental feature and may be unstable, use it at your own risk. Feedback highly appreciated!
Loaded config default from ".php-cs-fixer.dist.php".
5603/5603 [▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓▓] 100%
Fixed 0 of 5603 files in 30.988 seconds, 60.00 MB memory used
What's next:
Try Docker Debug for seamless, persistent debugging tools in any container or image → docker debug docker_lamp_1
Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (master) $ co JY-18909-automated-reports-ask-jiminny
M .env.local
M app/Console/Commands/JiminnyDebugCommand.php
M app/Http/Controllers/API/ActivityController.php
M app/Jobs/Team/SyncToIntercom.php
M app/Services/PlaybackService.php
M config/logging.php
M routes/web.php
Switched to branch 'JY-18909-automated-reports-ask-jiminny'
Your branch and 'origin/JY-18909-automated-reports-ask-jiminny' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git status
On branch JY-18909-automated-reports-ask-jiminny
Your branch and 'origin/JY-18909-automated-reports-ask-jiminny' have diverged,
and have 1 and 1 different commits each, respectively.
(use "git pull" to merge the remote branch into yours)
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: .env.local
modified: app/Console/Commands/JiminnyDebugCommand.php
modified: app/Http/Controllers/API/ActivityController.php
modified: app/Jobs/Team/SyncToIntercom.php
modified: app/Services/PlaybackService.php
modified: config/logging.php
modified: routes/web.php
Untracked files:
(use "git add <file>..." to include in what will be committed)
.env.nikilocal
.env.other
WEBHOOK_FILTERING_IMPLEMENTATION.md
app/Console/Commands/Crm/Hubspot/SimulateWebhooksCommand.php
app/Console/Commands/Reports/CreateMockAskJiminnyReportResultCommand.php
ids.txt
raw_sql_query.sql
tests/Unit/Policies/CanAccessAiReportsTest.php
no changes added to commit (use "git add" and/or "git commit -a")
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git pull
Merge made by the 'ort' strategy.
app/Jobs/AutomatedReports/RequestGenerateAskJiminnyReportJob.php | 2 +-
app/Repositories/AutomatedReportsRepository.php | 9 +++++++++
app/Services/Kiosk/AutomatedReports/AutomatedReportsService.php | 13 +++++++++++++
tests/Unit/Jobs/AutomatedReports/RequestGenerateAskJiminnyReportJobTest.php | 26 +++++++++++++-------------
4 files changed, 36 insertions(+), 14 deletions(-)
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git status
On branch JY-18909-automated-reports-ask-jiminny
Your branch is ahead of 'origin/JY-18909-automated-reports-ask-jiminny' by 2 commits.
(use "git push" to publish your local commits)
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: .env.local
modified: app/Console/Commands/JiminnyDebugCommand.php
modified: app/Http/Controllers/API/ActivityController.php
modified: app/Jobs/Team/SyncToIntercom.php
modified: app/Services/PlaybackService.php
modified: config/logging.php
modified: routes/web.php
Untracked files:
(use "git add <file>..." to include in what will be committed)
.env.nikilocal
.env.other
WEBHOOK_FILTERING_IMPLEMENTATION.md
app/Console/Commands/Crm/Hubspot/SimulateWebhooksCommand.php
app/Console/Commands/Reports/CreateMockAskJiminnyReportResultCommand.php
ids.txt
raw_sql_query.sql
tests/Unit/Policies/CanAccessAiReportsTest.php
no changes added to commit (use "git add" and/or "git commit -a")
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ git push
Enumerating objects: 38, done.
Counting objects: 100% (32/32), done.
Delta compression using up to 8 threads
Compressing objects: 100% (16/16), done.
Writing objects: 100% (18/18), 1.97 KiB | 1008.00 KiB/s, done.
Total 18 (delta 12), reused 0 (delta 0), pack-reused 0
remote: Resolving deltas: 100% (12/12), completed with 9 local objects.
remote:
remote: GitHub found 22 vulnerabilities on jiminny/app's default branch (10 high, 12 moderate). To find out more, visit:
remote: [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-18909-automated-reports-ask-jiminny) $ co master
M .env.local
M app/Console/Commands/JiminnyDebugCommand.php
M app/Http/Controllers/API/ActivityController.php
M app/Jobs/Team/SyncToIntercom.php
M app/Services/PlaybackService.php
M config/logging.php
M routes/web.php
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $ git pull
Already up to date.
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~/jiminny/app (master) $
DOCKER
Close Tab
DEV (docker)
Close Tab
APP (-zsh)
Close Tab
-zsh
Close Tab
screenpipe"
Close Tab
-zsh
Close Tab
⌥⌘1
APP (-zsh)...
|
NULL
|
|
54990
|
NULL
|
0
|
2026-04-20T09:27:33.843292+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776677253843_m2.jpg...
|
PhpStorm
|
faVsco.js – SF [jiminny@localhost]
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
1
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\V2;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Exceptions\ModelNotFoundException;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Response;
use Throwable;
class AskJiminnyReportsController extends Controller
{
public function __construct(
private readonly AutomatedReportsService $automatedReportsService,
private readonly LoggerInterface $logger,
) {
}
private function isNotOwnedByUser(AutomatedReport $report, User $user): bool
{
return $report->getTeamId() !== $user->getTeamId()
|| $report->getAttribute('created_by') !== $user->getId();
}
public function getFormData(Request $request, ?string $uuid = null): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$report = $uuid ? $this->automatedReportsService->getReport($uuid) : null;
return new JsonResponse(
$this->automatedReportsService->getAskJiminnyReportFormData($user, $report)
);
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (Throwable $e) {
$this->logger->error('Failed to fetch Ask Jiminny report form data', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to fetch form data'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* Create a new Ask Jiminny report.
*/
public function create(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$data = $this->automatedReportsService->createAskJiminnyReport($request->all(), $user);
return new JsonResponse($data);
} catch (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} catch (Throwable $e) {
$this->logger->error('Failed to create Ask Jiminny report', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
]);
return new JsonResponse(
['error' => 'Failed to create report'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* Update an existing Ask Jiminny report.
*/
public function update(Request $request, string $uuid): JsonResponse
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info("UPDATE");
/** @var User $user */
$user = $request->user();
try {
$report = $this->automatedReportsService->getReport($uuid);
if ($this->isNotOwnedByUser($report, $user)) {
return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);
}
$data = $this->automatedReportsService->updateAskJiminnyReport($report, $request->all(), $user);
return new JsonResponse($data);
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} catch (Throwable $e) {
$this->logger->error('Failed to update Ask Jiminny report', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to update report'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* Toggle Ask Jiminny report status (enable/disable).
*/
public function toggleStatus(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$report = $this->automatedReportsService->getReport($uuid);
if ($this->isNotOwnedByUser($report, $user)) {
return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);
}
$data = $this->automatedReportsService->updateAskJiminnyReportStatus(
$report,
(bool) $request->input('enabled'),
);
return new JsonResponse($data);
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (Throwable $e) {
$this->logger->error('Failed to toggle Ask Jiminny report status', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to toggle report status'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* List all Ask Jiminny reports.
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$sortColumn = $request->input('sort_column', 'created_at');
$sortDirection = $request->input('sort_direction', 'desc');
$data = $this->automatedReportsService->listAskJiminnyReports($user, $sortColumn, $sortDirection);
return new JsonResponse($data);
} catch (Throwable $e) {
$this->logger->error('Failed to list Ask Jiminny reports', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
]);
return new JsonResponse(
['error' => 'Failed to fetch reports'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* Get a single Ask Jiminny report.
*/
public function get(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$report = $this->automatedReportsService->getReport($uuid);
if ($this->isNotOwnedByUser($report, $user)) {
return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);
}
return new JsonResponse($this->automatedReportsService->get($uuid));
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (Throwable $e) {
$this->logger->error('Failed to get Ask Jiminny report', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to fetch report'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
public function getReportsCount(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$report = $this->automatedReportsService->getReport($uuid);
if ($this->isNotOwnedByUser($report, $user)) {
return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);
}
$resultsCount = $this->automatedReportsService->getReportResults($report)->count();
return new JsonResponse(['count' => $resultsCount]);
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (Throwable $e) {
$this->logger->error('Failed to count report results', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'report_uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to count report results'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* Delete an Ask Jiminny report.
*/
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
if ($request->boolean('delete_generated_reports')) {
$this->automatedReportsService->deleteReportResults($uuid);
}
$report = $this->automatedReportsService->getReport($uuid);
if ($this->isNotOwnedByUser($report, $user)) {
return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);
}
$this->automatedReportsService->delete($uuid);
return new JsonResponse(null, Response::HTTP_NO_CONTENT);
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (Throwable $e) {
$this->logger->error('Failed to delete Ask Jiminny report', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to delete report'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
public function getFilters(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$filters = $this->automatedReportsService->getAskJiminnyReportFilters($user);
return new JsonResponse(['filters' => $filters]);
} catch (Throwable $e) {
$this->logger->error('Failed to fetch Ask Jiminny report filters', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
]);
return new JsonResponse(
['error' => 'Failed to fetch filters'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
10
12
2
4
Previous Highlighted Error
Next Highlighted Error
SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o
JOIN activities a ON o.id = a.opportunity_id
WHERE a.crm_configuration_id = 39
AND a.actual_start_time > '2025-10-13'
AND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM activities
WHERE crm_configuration_id = 39 and user_id = 143
and actual_start_time >= '2025-10-13'
AND type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM opportunities WHERE account_id IN (178);
select * from activities where id IN (620137, 620187, 620188, 620189, 620230);
# HS
SELECT * FROM opportunities WHERE id IN (238);
select * from activities where id IN (477,2076);
select * from users;
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM activities;
SELECT COUNT(*) FROM opportunities;
UPDATE activities
SET
actual_start_time = '2025-12-19 09:00:00',
actual_end_time = '2025-12-19 10:30:00',
scheduled_start_time = '2025-12-19 09:00:00',
scheduled_end_time = '2025-12-19 10:30:00'
WHERE id IN (407509,407375);
select * from partners;
SELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id
FROM activities
WHERE user_id = 143
AND actual_start_time >= '2025-10-13 00:00:00'
AND actual_start_time <= '2026-01-13 23:59:59'
ORDER BY actual_start_time DESC;
SELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;
SELECT * FROM crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;
# lead_id
# account_id 177
# contact_id 3969
# opportunity_id
# stage_id 203
SELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;
SELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'
AND user_id = 143 and actual_start_time >= '2025-10-13';
SELECT * FROM activities a
# JOIN opportunities o ON a.opportunity_id = o.id
WHERE a.crm_configuration_id = 39 AND a.type = 'conference'
and status = 'completed' and recording_state = 'recorded'
and a.actual_start_time >= '2025-10-13'
AND a.user_id = 143
;
select * from leads
where crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310);
SELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198
SELECT * FROM activities WHERE id IN (356001, 356008); # contacts:
SELECT * FROM opportunities WHERE id IN (1707);
SELECT * FROM stages where id IN (204, 198);
SELECT * FROM opportunities WHERE account_id IN (178);
SELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';
SELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal
SELECT * FROM activities where crm_configuration_id = 39
AND opportunity_id IS NULL
AND is_internal = false
and status = 'completed' and recording_state = 'recorded'
AND actual_start_time >= '2025-10-13'
AND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)
# AND lead_id IN (112, 109)
;
SELECT * FROM crm_profiles WHERE user_id = 143;
select * from inboxes; # 212
select * from users where id = 143; # 143
select * from inbox_email_batches where inbox_id = 212
and updated_at >= '2026-01-28 00:00:00' order by id desc;
select * from inbox_emails where inbox_id = 212
and batch_id = 95885 order by id desc;
select * from email_messages where origin_user_id = 143;
select * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';
select * from participants where activity_id = 620247;
select * from crm_profiles where user_id = 143;
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001
select * from transcription where activity_id = 356001; # 6943
select * from ai_prompts where transcription_id = 6943;
SELECT * FROM activity_summary_logs where activity_id = 356001;
SELECT * FROM social_accounts WHERE sociable_id = 143;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;
# 422515 softphone tr. 8100
SELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;
# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS
select * from ai_prompts where transcription_id IN (8100, 7670);
select * from activity_summary_logs where activity_id = 407509;
select * from sidekick_settings;
select * from default_activity_types;
SELECT * FROM contacts WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM leads WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM activity_searches where user_id = 143;
SELECT * FROM groups where team_id = 1;
select * from teams where id = 1;
select * from groups where team_id = 1; # 1150 - 7e75f8025c22
select id, name, group_id, status, deleted_at, email
from users where team_id = 1 order by group_id desc ;
select * from activity_searches where id in (1977, 1978, 1979);
select * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);
select * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277
select * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879
INSERT INTO `activity_search_filters`
(`activity_search_id`, `filter`, `value`) VALUES
(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')
;
select * from crm_configurations where id = 39;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from features;
SELECT * FROM activity_searches where id = 1982; # 1981
SELECT * FROM activity_search_filters WHERE activity_search_id = 1982;
SELECT * FROM automated_reports where id = 68;
SELECT * FROM automated_report_results where id = 275;
SELECT * FROM automated_reports order by id desc;
SELECT * FROM automated_report_results order by id desc;
select * from activity_searches where user_id = 143;
select * from ask_anything_prompts;
SELECT * FROM groups WHERE id = 1439;
SELECT * FROM users WHERE group_id = 1439;
select * from permissions; # 158
select * from roles;
select * from permission_role
select * from teams where id = 1;
select * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;
select * from groups where id = 28;
select * from playbooks where team_id = 1;
select * from playbooks where id = 179;
select * from playbook_categories where id = 1391;
select * from users where id = 143;
select * from crm_profiles where user_id = 143;
select * from activities where crm_configuration_id = 39 and type = 'conference'
and crm_provider_id IS NOT NULL ORDER by id desc;
select * from activities where id = 422003; # 00UO400000pB6fpMAC
SELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type
FROM automated_report_results ar
JOIN automated_reports a ON a.id = ar.report_id
WHERE a.type = 'ask_jiminny'
LIMIT 10;
select * from teams where id = 3143;
select * from crm_configurations where id = 500;
select * from users where name = 'Integration Account'; # 1695
SELECT * FROM social_accounts WHERE sociable_id = 1695;
select * from activities where crm_configuration_id = 39
and recording_state = 'recorded' and duration > 60
and status = 'completed' and actual_start_time >= '2025-12-01'
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11894 on JY-18909-automated-reports-ask-jiminny, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #11894 exists for current branch JY-18909-automated-reports-ask-jiminny","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.3700133,"top":0.273743,"width":0.00731383,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.3793218,"top":0.273743,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.38896278,"top":0.27214685,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.3962766,"top":0.27214685,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\V2;\n\nuse Illuminate\\Http\\JsonResponse;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Routing\\Controller;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Exceptions\\ModelNotFoundException;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Throwable;\n\nclass AskJiminnyReportsController extends Controller\n{\n public function __construct(\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly LoggerInterface $logger,\n ) {\n }\n\n private function isNotOwnedByUser(AutomatedReport $report, User $user): bool\n {\n return $report->getTeamId() !== $user->getTeamId()\n || $report->getAttribute('created_by') !== $user->getId();\n }\n\n public function getFormData(Request $request, ?string $uuid = null): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $report = $uuid ? $this->automatedReportsService->getReport($uuid) : null;\n\n return new JsonResponse(\n $this->automatedReportsService->getAskJiminnyReportFormData($user, $report)\n );\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (Throwable $e) {\n $this->logger->error('Failed to fetch Ask Jiminny report form data', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to fetch form data'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * Create a new Ask Jiminny report.\n */\n public function create(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $data = $this->automatedReportsService->createAskJiminnyReport($request->all(), $user);\n\n return new JsonResponse($data);\n } catch (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\n } catch (Throwable $e) {\n $this->logger->error('Failed to create Ask Jiminny report', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to create report'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * Update an existing Ask Jiminny report.\n */\n public function update(Request $request, string $uuid): JsonResponse\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info(\"UPDATE\");\n /** @var User $user */\n $user = $request->user();\n\n try {\n $report = $this->automatedReportsService->getReport($uuid);\n\n if ($this->isNotOwnedByUser($report, $user)) {\n return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);\n }\n\n $data = $this->automatedReportsService->updateAskJiminnyReport($report, $request->all(), $user);\n\n return new JsonResponse($data);\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\n } catch (Throwable $e) {\n $this->logger->error('Failed to update Ask Jiminny report', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to update report'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * Toggle Ask Jiminny report status (enable/disable).\n */\n public function toggleStatus(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $report = $this->automatedReportsService->getReport($uuid);\n\n if ($this->isNotOwnedByUser($report, $user)) {\n return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);\n }\n\n $data = $this->automatedReportsService->updateAskJiminnyReportStatus(\n $report,\n (bool) $request->input('enabled'),\n );\n\n return new JsonResponse($data);\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (Throwable $e) {\n $this->logger->error('Failed to toggle Ask Jiminny report status', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to toggle report status'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * List all Ask Jiminny reports.\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $sortColumn = $request->input('sort_column', 'created_at');\n $sortDirection = $request->input('sort_direction', 'desc');\n\n $data = $this->automatedReportsService->listAskJiminnyReports($user, $sortColumn, $sortDirection);\n\n return new JsonResponse($data);\n } catch (Throwable $e) {\n $this->logger->error('Failed to list Ask Jiminny reports', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to fetch reports'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * Get a single Ask Jiminny report.\n */\n public function get(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $report = $this->automatedReportsService->getReport($uuid);\n\n if ($this->isNotOwnedByUser($report, $user)) {\n return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);\n }\n\n return new JsonResponse($this->automatedReportsService->get($uuid));\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (Throwable $e) {\n $this->logger->error('Failed to get Ask Jiminny report', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to fetch report'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n public function getReportsCount(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $report = $this->automatedReportsService->getReport($uuid);\n\n if ($this->isNotOwnedByUser($report, $user)) {\n return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);\n }\n\n $resultsCount = $this->automatedReportsService->getReportResults($report)->count();\n\n return new JsonResponse(['count' => $resultsCount]);\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (Throwable $e) {\n $this->logger->error('Failed to count report results', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'report_uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to count report results'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * Delete an Ask Jiminny report.\n */\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n if ($request->boolean('delete_generated_reports')) {\n $this->automatedReportsService->deleteReportResults($uuid);\n }\n\n $report = $this->automatedReportsService->getReport($uuid);\n\n if ($this->isNotOwnedByUser($report, $user)) {\n return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);\n }\n\n $this->automatedReportsService->delete($uuid);\n\n return new JsonResponse(null, Response::HTTP_NO_CONTENT);\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (Throwable $e) {\n $this->logger->error('Failed to delete Ask Jiminny report', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to delete report'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n public function getFilters(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $filters = $this->automatedReportsService->getAskJiminnyReportFilters($user);\n\n return new JsonResponse(['filters' => $filters]);\n } catch (Throwable $e) {\n $this->logger->error('Failed to fetch Ask Jiminny report filters', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to fetch filters'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\V2;\n\nuse Illuminate\\Http\\JsonResponse;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Routing\\Controller;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Exceptions\\ModelNotFoundException;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Throwable;\n\nclass AskJiminnyReportsController extends Controller\n{\n public function __construct(\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly LoggerInterface $logger,\n ) {\n }\n\n private function isNotOwnedByUser(AutomatedReport $report, User $user): bool\n {\n return $report->getTeamId() !== $user->getTeamId()\n || $report->getAttribute('created_by') !== $user->getId();\n }\n\n public function getFormData(Request $request, ?string $uuid = null): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $report = $uuid ? $this->automatedReportsService->getReport($uuid) : null;\n\n return new JsonResponse(\n $this->automatedReportsService->getAskJiminnyReportFormData($user, $report)\n );\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (Throwable $e) {\n $this->logger->error('Failed to fetch Ask Jiminny report form data', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to fetch form data'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * Create a new Ask Jiminny report.\n */\n public function create(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $data = $this->automatedReportsService->createAskJiminnyReport($request->all(), $user);\n\n return new JsonResponse($data);\n } catch (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\n } catch (Throwable $e) {\n $this->logger->error('Failed to create Ask Jiminny report', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to create report'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * Update an existing Ask Jiminny report.\n */\n public function update(Request $request, string $uuid): JsonResponse\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info(\"UPDATE\");\n /** @var User $user */\n $user = $request->user();\n\n try {\n $report = $this->automatedReportsService->getReport($uuid);\n\n if ($this->isNotOwnedByUser($report, $user)) {\n return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);\n }\n\n $data = $this->automatedReportsService->updateAskJiminnyReport($report, $request->all(), $user);\n\n return new JsonResponse($data);\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\n } catch (Throwable $e) {\n $this->logger->error('Failed to update Ask Jiminny report', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to update report'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * Toggle Ask Jiminny report status (enable/disable).\n */\n public function toggleStatus(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $report = $this->automatedReportsService->getReport($uuid);\n\n if ($this->isNotOwnedByUser($report, $user)) {\n return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);\n }\n\n $data = $this->automatedReportsService->updateAskJiminnyReportStatus(\n $report,\n (bool) $request->input('enabled'),\n );\n\n return new JsonResponse($data);\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (Throwable $e) {\n $this->logger->error('Failed to toggle Ask Jiminny report status', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to toggle report status'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * List all Ask Jiminny reports.\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $sortColumn = $request->input('sort_column', 'created_at');\n $sortDirection = $request->input('sort_direction', 'desc');\n\n $data = $this->automatedReportsService->listAskJiminnyReports($user, $sortColumn, $sortDirection);\n\n return new JsonResponse($data);\n } catch (Throwable $e) {\n $this->logger->error('Failed to list Ask Jiminny reports', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to fetch reports'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * Get a single Ask Jiminny report.\n */\n public function get(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $report = $this->automatedReportsService->getReport($uuid);\n\n if ($this->isNotOwnedByUser($report, $user)) {\n return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);\n }\n\n return new JsonResponse($this->automatedReportsService->get($uuid));\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (Throwable $e) {\n $this->logger->error('Failed to get Ask Jiminny report', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to fetch report'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n public function getReportsCount(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $report = $this->automatedReportsService->getReport($uuid);\n\n if ($this->isNotOwnedByUser($report, $user)) {\n return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);\n }\n\n $resultsCount = $this->automatedReportsService->getReportResults($report)->count();\n\n return new JsonResponse(['count' => $resultsCount]);\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (Throwable $e) {\n $this->logger->error('Failed to count report results', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'report_uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to count report results'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * Delete an Ask Jiminny report.\n */\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n if ($request->boolean('delete_generated_reports')) {\n $this->automatedReportsService->deleteReportResults($uuid);\n }\n\n $report = $this->automatedReportsService->getReport($uuid);\n\n if ($this->isNotOwnedByUser($report, $user)) {\n return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);\n }\n\n $this->automatedReportsService->delete($uuid);\n\n return new JsonResponse(null, Response::HTTP_NO_CONTENT);\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (Throwable $e) {\n $this->logger->error('Failed to delete Ask Jiminny report', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to delete report'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n public function getFilters(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $filters = $this->automatedReportsService->getAskJiminnyReportFilters($user);\n\n return new JsonResponse(['filters' => $filters]);\n } catch (Throwable $e) {\n $this->logger->error('Failed to fetch Ask Jiminny report filters', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to fetch filters'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"bounds":{"left":0.40492022,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"bounds":{"left":0.41356382,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"bounds":{"left":0.4245346,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"bounds":{"left":0.4331782,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"bounds":{"left":0.4418218,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"bounds":{"left":0.45279256,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"bounds":{"left":0.4637633,"top":0.09896249,"width":0.024268618,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"bounds":{"left":0.49035904,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"bounds":{"left":0.5013298,"top":0.09896249,"width":0.029587766,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"bounds":{"left":0.69913566,"top":0.09896249,"width":0.02825798,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10","depth":4,"bounds":{"left":0.6715425,"top":0.123703115,"width":0.009640957,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"12","depth":4,"bounds":{"left":0.6831782,"top":0.123703115,"width":0.009640957,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.69481385,"top":0.123703115,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"bounds":{"left":0.70478725,"top":0.123703115,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7144282,"top":0.12210695,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.72174203,"top":0.12210695,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o\nJOIN activities a ON o.id = a.opportunity_id\nWHERE a.crm_configuration_id = 39\nAND a.actual_start_time > '2025-10-13'\nAND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 39 and user_id = 143\nand actual_start_time >= '2025-10-13'\nAND type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM opportunities WHERE account_id IN (178);\nselect * from activities where id IN (620137, 620187, 620188, 620189, 620230);\n\n# HS\nSELECT * FROM opportunities WHERE id IN (238);\nselect * from activities where id IN (477,2076);\n\nselect * from users;\n\nSELECT COUNT(*) FROM users;\nSELECT COUNT(*) FROM activities;\nSELECT COUNT(*) FROM opportunities;\n\nUPDATE activities\nSET\n actual_start_time = '2025-12-19 09:00:00',\n actual_end_time = '2025-12-19 10:30:00',\n scheduled_start_time = '2025-12-19 09:00:00',\n scheduled_end_time = '2025-12-19 10:30:00'\nWHERE id IN (407509,407375);\n\nselect * from partners;\n\nSELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id\nFROM activities\nWHERE user_id = 143\nAND actual_start_time >= '2025-10-13 00:00:00'\nAND actual_start_time <= '2026-01-13 23:59:59'\nORDER BY actual_start_time DESC;\n\nSELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;\nSELECT * FROM crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;\n# lead_id\n# account_id 177\n# contact_id 3969\n# opportunity_id\n# stage_id 203\n\nSELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;\n\nSELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'\nAND user_id = 143 and actual_start_time >= '2025-10-13';\n\nSELECT * FROM activities a\n# JOIN opportunities o ON a.opportunity_id = o.id\nWHERE a.crm_configuration_id = 39 AND a.type = 'conference'\nand status = 'completed' and recording_state = 'recorded'\nand a.actual_start_time >= '2025-10-13'\nAND a.user_id = 143\n;\n\nselect * from leads\nwhere crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707\n\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310);\nSELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198\nSELECT * FROM activities WHERE id IN (356001, 356008); # contacts:\n\nSELECT * FROM opportunities WHERE id IN (1707);\nSELECT * FROM stages where id IN (204, 198);\nSELECT * FROM opportunities WHERE account_id IN (178);\nSELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';\nSELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal\n\nSELECT * FROM activities where crm_configuration_id = 39\nAND opportunity_id IS NULL\nAND is_internal = false\nand status = 'completed' and recording_state = 'recorded'\nAND actual_start_time >= '2025-10-13'\nAND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)\n# AND lead_id IN (112, 109)\n;\n\nSELECT * FROM crm_profiles WHERE user_id = 143;\n\nselect * from inboxes; # 212\nselect * from users where id = 143; # 143\nselect * from inbox_email_batches where inbox_id = 212\nand updated_at >= '2026-01-28 00:00:00' order by id desc;\nselect * from inbox_emails where inbox_id = 212\nand batch_id = 95885 order by id desc;\nselect * from email_messages where origin_user_id = 143;\nselect * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';\nselect * from participants where activity_id = 620247;\n\nselect * from crm_profiles where user_id = 143;\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001\nselect * from transcription where activity_id = 356001; # 6943\nselect * from ai_prompts where transcription_id = 6943;\nSELECT * FROM activity_summary_logs where activity_id = 356001;\n\nSELECT * FROM social_accounts WHERE sociable_id = 143;\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;\n# 422515 softphone tr. 8100\n\nSELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;\n# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS\n\nselect * from ai_prompts where transcription_id IN (8100, 7670);\nselect * from activity_summary_logs where activity_id = 407509;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nSELECT * FROM contacts WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\nSELECT * FROM leads WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\n\nSELECT * FROM activity_searches where user_id = 143;\nSELECT * FROM groups where team_id = 1;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1; # 1150 - 7e75f8025c22\nselect id, name, group_id, status, deleted_at, email\nfrom users where team_id = 1 order by group_id desc ;\n\nselect * from activity_searches where id in (1977, 1978, 1979);\nselect * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);\nselect * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277\nselect * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879\n\nINSERT INTO `activity_search_filters`\n(`activity_search_id`, `filter`, `value`) VALUES\n(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')\n;\n\nselect * from crm_configurations where id = 39;\n\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\nselect * from features;\n\nSELECT * FROM activity_searches where id = 1982; # 1981\nSELECT * FROM activity_search_filters WHERE activity_search_id = 1982;\n\nSELECT * FROM automated_reports where id = 68;\nSELECT * FROM automated_report_results where id = 275;\n\nSELECT * FROM automated_reports order by id desc;\nSELECT * FROM automated_report_results order by id desc;\nselect * from activity_searches where user_id = 143;\nselect * from ask_anything_prompts;\n\nSELECT * FROM groups WHERE id = 1439;\nSELECT * FROM users WHERE group_id = 1439;\n\nselect * from permissions; # 158\nselect * from roles;\nselect * from permission_role\n\nselect * from teams where id = 1;\nselect * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;\nselect * from groups where id = 28;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 179;\nselect * from playbook_categories where id = 1391;\nselect * from users where id = 143;\nselect * from crm_profiles where user_id = 143;\nselect * from activities where crm_configuration_id = 39 and type = 'conference'\nand crm_provider_id IS NOT NULL ORDER by id desc;\nselect * from activities where id = 422003; # 00UO400000pB6fpMAC\n\nSELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type\nFROM automated_report_results ar\nJOIN automated_reports a ON a.id = ar.report_id\nWHERE a.type = 'ask_jiminny'\nLIMIT 10;\n\n\nselect * from teams where id = 3143;\nselect * from crm_configurations where id = 500;\nselect * from users where name = 'Integration Account'; # 1695\nSELECT * FROM social_accounts WHERE sociable_id = 1695;\n\nselect * from activities where crm_configuration_id = 39\nand recording_state = 'recorded' and duration > 60\nand status = 'completed' and actual_start_time >= '2025-12-01'\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid;","depth":4,"value":"SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o\nJOIN activities a ON o.id = a.opportunity_id\nWHERE a.crm_configuration_id = 39\nAND a.actual_start_time > '2025-10-13'\nAND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 39 and user_id = 143\nand actual_start_time >= '2025-10-13'\nAND type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM opportunities WHERE account_id IN (178);\nselect * from activities where id IN (620137, 620187, 620188, 620189, 620230);\n\n# HS\nSELECT * FROM opportunities WHERE id IN (238);\nselect * from activities where id IN (477,2076);\n\nselect * from users;\n\nSELECT COUNT(*) FROM users;\nSELECT COUNT(*) FROM activities;\nSELECT COUNT(*) FROM opportunities;\n\nUPDATE activities\nSET\n actual_start_time = '2025-12-19 09:00:00',\n actual_end_time = '2025-12-19 10:30:00',\n scheduled_start_time = '2025-12-19 09:00:00',\n scheduled_end_time = '2025-12-19 10:30:00'\nWHERE id IN (407509,407375);\n\nselect * from partners;\n\nSELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id\nFROM activities\nWHERE user_id = 143\nAND actual_start_time >= '2025-10-13 00:00:00'\nAND actual_start_time <= '2026-01-13 23:59:59'\nORDER BY actual_start_time DESC;\n\nSELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;\nSELECT * FROM crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;\n# lead_id\n# account_id 177\n# contact_id 3969\n# opportunity_id\n# stage_id 203\n\nSELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;\n\nSELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'\nAND user_id = 143 and actual_start_time >= '2025-10-13';\n\nSELECT * FROM activities a\n# JOIN opportunities o ON a.opportunity_id = o.id\nWHERE a.crm_configuration_id = 39 AND a.type = 'conference'\nand status = 'completed' and recording_state = 'recorded'\nand a.actual_start_time >= '2025-10-13'\nAND a.user_id = 143\n;\n\nselect * from leads\nwhere crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707\n\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310);\nSELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198\nSELECT * FROM activities WHERE id IN (356001, 356008); # contacts:\n\nSELECT * FROM opportunities WHERE id IN (1707);\nSELECT * FROM stages where id IN (204, 198);\nSELECT * FROM opportunities WHERE account_id IN (178);\nSELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';\nSELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal\n\nSELECT * FROM activities where crm_configuration_id = 39\nAND opportunity_id IS NULL\nAND is_internal = false\nand status = 'completed' and recording_state = 'recorded'\nAND actual_start_time >= '2025-10-13'\nAND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)\n# AND lead_id IN (112, 109)\n;\n\nSELECT * FROM crm_profiles WHERE user_id = 143;\n\nselect * from inboxes; # 212\nselect * from users where id = 143; # 143\nselect * from inbox_email_batches where inbox_id = 212\nand updated_at >= '2026-01-28 00:00:00' order by id desc;\nselect * from inbox_emails where inbox_id = 212\nand batch_id = 95885 order by id desc;\nselect * from email_messages where origin_user_id = 143;\nselect * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';\nselect * from participants where activity_id = 620247;\n\nselect * from crm_profiles where user_id = 143;\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001\nselect * from transcription where activity_id = 356001; # 6943\nselect * from ai_prompts where transcription_id = 6943;\nSELECT * FROM activity_summary_logs where activity_id = 356001;\n\nSELECT * FROM social_accounts WHERE sociable_id = 143;\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;\n# 422515 softphone tr. 8100\n\nSELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;\n# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS\n\nselect * from ai_prompts where transcription_id IN (8100, 7670);\nselect * from activity_summary_logs where activity_id = 407509;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nSELECT * FROM contacts WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\nSELECT * FROM leads WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\n\nSELECT * FROM activity_searches where user_id = 143;\nSELECT * FROM groups where team_id = 1;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1; # 1150 - 7e75f8025c22\nselect id, name, group_id, status, deleted_at, email\nfrom users where team_id = 1 order by group_id desc ;\n\nselect * from activity_searches where id in (1977, 1978, 1979);\nselect * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);\nselect * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277\nselect * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879\n\nINSERT INTO `activity_search_filters`\n(`activity_search_id`, `filter`, `value`) VALUES\n(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')\n;\n\nselect * from crm_configurations where id = 39;\n\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\nselect * from features;\n\nSELECT * FROM activity_searches where id = 1982; # 1981\nSELECT * FROM activity_search_filters WHERE activity_search_id = 1982;\n\nSELECT * FROM automated_reports where id = 68;\nSELECT * FROM automated_report_results where id = 275;\n\nSELECT * FROM automated_reports order by id desc;\nSELECT * FROM automated_report_results order by id desc;\nselect * from activity_searches where user_id = 143;\nselect * from ask_anything_prompts;\n\nSELECT * FROM groups WHERE id = 1439;\nSELECT * FROM users WHERE group_id = 1439;\n\nselect * from permissions; # 158\nselect * from roles;\nselect * from permission_role\n\nselect * from teams where id = 1;\nselect * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;\nselect * from groups where id = 28;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 179;\nselect * from playbook_categories where id = 1391;\nselect * from users where id = 143;\nselect * from crm_profiles where user_id = 143;\nselect * from activities where crm_configuration_id = 39 and type = 'conference'\nand crm_provider_id IS NOT NULL ORDER by id desc;\nselect * from activities where id = 422003; # 00UO400000pB6fpMAC\n\nSELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type\nFROM automated_report_results ar\nJOIN automated_reports a ON a.id = ar.report_id\nWHERE a.type = 'ask_jiminny'\nLIMIT 10;\n\n\nselect * from teams where id = 3143;\nselect * from crm_configurations where id = 500;\nselect * from users where name = 'Integration Account'; # 1695\nSELECT * FROM social_accounts WHERE sociable_id = 1695;\n\nselect * from activities where crm_configuration_id = 39\nand recording_state = 'recorded' and duration > 60\nand status = 'completed' and actual_start_time >= '2025-12-01'\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid;","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-7301178313361766127
|
-7003273557753482683
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
1
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\V2;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Exceptions\ModelNotFoundException;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Response;
use Throwable;
class AskJiminnyReportsController extends Controller
{
public function __construct(
private readonly AutomatedReportsService $automatedReportsService,
private readonly LoggerInterface $logger,
) {
}
private function isNotOwnedByUser(AutomatedReport $report, User $user): bool
{
return $report->getTeamId() !== $user->getTeamId()
|| $report->getAttribute('created_by') !== $user->getId();
}
public function getFormData(Request $request, ?string $uuid = null): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$report = $uuid ? $this->automatedReportsService->getReport($uuid) : null;
return new JsonResponse(
$this->automatedReportsService->getAskJiminnyReportFormData($user, $report)
);
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (Throwable $e) {
$this->logger->error('Failed to fetch Ask Jiminny report form data', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to fetch form data'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* Create a new Ask Jiminny report.
*/
public function create(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$data = $this->automatedReportsService->createAskJiminnyReport($request->all(), $user);
return new JsonResponse($data);
} catch (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} catch (Throwable $e) {
$this->logger->error('Failed to create Ask Jiminny report', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
]);
return new JsonResponse(
['error' => 'Failed to create report'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* Update an existing Ask Jiminny report.
*/
public function update(Request $request, string $uuid): JsonResponse
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info("UPDATE");
/** @var User $user */
$user = $request->user();
try {
$report = $this->automatedReportsService->getReport($uuid);
if ($this->isNotOwnedByUser($report, $user)) {
return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);
}
$data = $this->automatedReportsService->updateAskJiminnyReport($report, $request->all(), $user);
return new JsonResponse($data);
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} catch (Throwable $e) {
$this->logger->error('Failed to update Ask Jiminny report', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to update report'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* Toggle Ask Jiminny report status (enable/disable).
*/
public function toggleStatus(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$report = $this->automatedReportsService->getReport($uuid);
if ($this->isNotOwnedByUser($report, $user)) {
return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);
}
$data = $this->automatedReportsService->updateAskJiminnyReportStatus(
$report,
(bool) $request->input('enabled'),
);
return new JsonResponse($data);
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (Throwable $e) {
$this->logger->error('Failed to toggle Ask Jiminny report status', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to toggle report status'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* List all Ask Jiminny reports.
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$sortColumn = $request->input('sort_column', 'created_at');
$sortDirection = $request->input('sort_direction', 'desc');
$data = $this->automatedReportsService->listAskJiminnyReports($user, $sortColumn, $sortDirection);
return new JsonResponse($data);
} catch (Throwable $e) {
$this->logger->error('Failed to list Ask Jiminny reports', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
]);
return new JsonResponse(
['error' => 'Failed to fetch reports'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* Get a single Ask Jiminny report.
*/
public function get(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$report = $this->automatedReportsService->getReport($uuid);
if ($this->isNotOwnedByUser($report, $user)) {
return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);
}
return new JsonResponse($this->automatedReportsService->get($uuid));
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (Throwable $e) {
$this->logger->error('Failed to get Ask Jiminny report', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to fetch report'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
public function getReportsCount(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$report = $this->automatedReportsService->getReport($uuid);
if ($this->isNotOwnedByUser($report, $user)) {
return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);
}
$resultsCount = $this->automatedReportsService->getReportResults($report)->count();
return new JsonResponse(['count' => $resultsCount]);
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (Throwable $e) {
$this->logger->error('Failed to count report results', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'report_uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to count report results'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* Delete an Ask Jiminny report.
*/
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
if ($request->boolean('delete_generated_reports')) {
$this->automatedReportsService->deleteReportResults($uuid);
}
$report = $this->automatedReportsService->getReport($uuid);
if ($this->isNotOwnedByUser($report, $user)) {
return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);
}
$this->automatedReportsService->delete($uuid);
return new JsonResponse(null, Response::HTTP_NO_CONTENT);
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (Throwable $e) {
$this->logger->error('Failed to delete Ask Jiminny report', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to delete report'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
public function getFilters(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$filters = $this->automatedReportsService->getAskJiminnyReportFilters($user);
return new JsonResponse(['filters' => $filters]);
} catch (Throwable $e) {
$this->logger->error('Failed to fetch Ask Jiminny report filters', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
]);
return new JsonResponse(
['error' => 'Failed to fetch filters'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
10
12
2
4
Previous Highlighted Error
Next Highlighted Error
SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o
JOIN activities a ON o.id = a.opportunity_id
WHERE a.crm_configuration_id = 39
AND a.actual_start_time > '2025-10-13'
AND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM activities
WHERE crm_configuration_id = 39 and user_id = 143
and actual_start_time >= '2025-10-13'
AND type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM opportunities WHERE account_id IN (178);
select * from activities where id IN (620137, 620187, 620188, 620189, 620230);
# HS
SELECT * FROM opportunities WHERE id IN (238);
select * from activities where id IN (477,2076);
select * from users;
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM activities;
SELECT COUNT(*) FROM opportunities;
UPDATE activities
SET
actual_start_time = '2025-12-19 09:00:00',
actual_end_time = '2025-12-19 10:30:00',
scheduled_start_time = '2025-12-19 09:00:00',
scheduled_end_time = '2025-12-19 10:30:00'
WHERE id IN (407509,407375);
select * from partners;
SELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id
FROM activities
WHERE user_id = 143
AND actual_start_time >= '2025-10-13 00:00:00'
AND actual_start_time <= '2026-01-13 23:59:59'
ORDER BY actual_start_time DESC;
SELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;
SELECT * FROM crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;
# lead_id
# account_id 177
# contact_id 3969
# opportunity_id
# stage_id 203
SELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;
SELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'
AND user_id = 143 and actual_start_time >= '2025-10-13';
SELECT * FROM activities a
# JOIN opportunities o ON a.opportunity_id = o.id
WHERE a.crm_configuration_id = 39 AND a.type = 'conference'
and status = 'completed' and recording_state = 'recorded'
and a.actual_start_time >= '2025-10-13'
AND a.user_id = 143
;
select * from leads
where crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310);
SELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198
SELECT * FROM activities WHERE id IN (356001, 356008); # contacts:
SELECT * FROM opportunities WHERE id IN (1707);
SELECT * FROM stages where id IN (204, 198);
SELECT * FROM opportunities WHERE account_id IN (178);
SELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';
SELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal
SELECT * FROM activities where crm_configuration_id = 39
AND opportunity_id IS NULL
AND is_internal = false
and status = 'completed' and recording_state = 'recorded'
AND actual_start_time >= '2025-10-13'
AND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)
# AND lead_id IN (112, 109)
;
SELECT * FROM crm_profiles WHERE user_id = 143;
select * from inboxes; # 212
select * from users where id = 143; # 143
select * from inbox_email_batches where inbox_id = 212
and updated_at >= '2026-01-28 00:00:00' order by id desc;
select * from inbox_emails where inbox_id = 212
and batch_id = 95885 order by id desc;
select * from email_messages where origin_user_id = 143;
select * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';
select * from participants where activity_id = 620247;
select * from crm_profiles where user_id = 143;
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001
select * from transcription where activity_id = 356001; # 6943
select * from ai_prompts where transcription_id = 6943;
SELECT * FROM activity_summary_logs where activity_id = 356001;
SELECT * FROM social_accounts WHERE sociable_id = 143;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;
# 422515 softphone tr. 8100
SELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;
# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS
select * from ai_prompts where transcription_id IN (8100, 7670);
select * from activity_summary_logs where activity_id = 407509;
select * from sidekick_settings;
select * from default_activity_types;
SELECT * FROM contacts WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM leads WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM activity_searches where user_id = 143;
SELECT * FROM groups where team_id = 1;
select * from teams where id = 1;
select * from groups where team_id = 1; # 1150 - 7e75f8025c22
select id, name, group_id, status, deleted_at, email
from users where team_id = 1 order by group_id desc ;
select * from activity_searches where id in (1977, 1978, 1979);
select * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);
select * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277
select * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879
INSERT INTO `activity_search_filters`
(`activity_search_id`, `filter`, `value`) VALUES
(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')
;
select * from crm_configurations where id = 39;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from features;
SELECT * FROM activity_searches where id = 1982; # 1981
SELECT * FROM activity_search_filters WHERE activity_search_id = 1982;
SELECT * FROM automated_reports where id = 68;
SELECT * FROM automated_report_results where id = 275;
SELECT * FROM automated_reports order by id desc;
SELECT * FROM automated_report_results order by id desc;
select * from activity_searches where user_id = 143;
select * from ask_anything_prompts;
SELECT * FROM groups WHERE id = 1439;
SELECT * FROM users WHERE group_id = 1439;
select * from permissions; # 158
select * from roles;
select * from permission_role
select * from teams where id = 1;
select * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;
select * from groups where id = 28;
select * from playbooks where team_id = 1;
select * from playbooks where id = 179;
select * from playbook_categories where id = 1391;
select * from users where id = 143;
select * from crm_profiles where user_id = 143;
select * from activities where crm_configuration_id = 39 and type = 'conference'
and crm_provider_id IS NOT NULL ORDER by id desc;
select * from activities where id = 422003; # 00UO400000pB6fpMAC
SELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type
FROM automated_report_results ar
JOIN automated_reports a ON a.id = ar.report_id
WHERE a.type = 'ask_jiminny'
LIMIT 10;
select * from teams where id = 3143;
select * from crm_configurations where id = 500;
select * from users where name = 'Integration Account'; # 1695
SELECT * FROM social_accounts WHERE sociable_id = 1695;
select * from activities where crm_configuration_id = 39
and recording_state = 'recorded' and duration > 60
and status = 'completed' and actual_start_time >= '2025-12-01'
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
54989
|
NULL
|
0
|
2026-04-20T09:27:33.843069+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776677253843_m1.jpg...
|
PhpStorm
|
faVsco.js – SF [jiminny@localhost]
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
1
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\V2;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Exceptions\ModelNotFoundException;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Response;
use Throwable;
class AskJiminnyReportsController extends Controller
{
public function __construct(
private readonly AutomatedReportsService $automatedReportsService,
private readonly LoggerInterface $logger,
) {
}
private function isNotOwnedByUser(AutomatedReport $report, User $user): bool
{
return $report->getTeamId() !== $user->getTeamId()
|| $report->getAttribute('created_by') !== $user->getId();
}
public function getFormData(Request $request, ?string $uuid = null): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$report = $uuid ? $this->automatedReportsService->getReport($uuid) : null;
return new JsonResponse(
$this->automatedReportsService->getAskJiminnyReportFormData($user, $report)
);
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (Throwable $e) {
$this->logger->error('Failed to fetch Ask Jiminny report form data', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to fetch form data'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* Create a new Ask Jiminny report.
*/
public function create(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$data = $this->automatedReportsService->createAskJiminnyReport($request->all(), $user);
return new JsonResponse($data);
} catch (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} catch (Throwable $e) {
$this->logger->error('Failed to create Ask Jiminny report', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
]);
return new JsonResponse(
['error' => 'Failed to create report'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* Update an existing Ask Jiminny report.
*/
public function update(Request $request, string $uuid): JsonResponse
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info("UPDATE");
/** @var User $user */
$user = $request->user();
try {
$report = $this->automatedReportsService->getReport($uuid);
if ($this->isNotOwnedByUser($report, $user)) {
return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);
}
$data = $this->automatedReportsService->updateAskJiminnyReport($report, $request->all(), $user);
return new JsonResponse($data);
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} catch (Throwable $e) {
$this->logger->error('Failed to update Ask Jiminny report', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to update report'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* Toggle Ask Jiminny report status (enable/disable).
*/
public function toggleStatus(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$report = $this->automatedReportsService->getReport($uuid);
if ($this->isNotOwnedByUser($report, $user)) {
return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);
}
$data = $this->automatedReportsService->updateAskJiminnyReportStatus(
$report,
(bool) $request->input('enabled'),
);
return new JsonResponse($data);
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (Throwable $e) {
$this->logger->error('Failed to toggle Ask Jiminny report status', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to toggle report status'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* List all Ask Jiminny reports.
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$sortColumn = $request->input('sort_column', 'created_at');
$sortDirection = $request->input('sort_direction', 'desc');
$data = $this->automatedReportsService->listAskJiminnyReports($user, $sortColumn, $sortDirection);
return new JsonResponse($data);
} catch (Throwable $e) {
$this->logger->error('Failed to list Ask Jiminny reports', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
]);
return new JsonResponse(
['error' => 'Failed to fetch reports'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* Get a single Ask Jiminny report.
*/
public function get(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$report = $this->automatedReportsService->getReport($uuid);
if ($this->isNotOwnedByUser($report, $user)) {
return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);
}
return new JsonResponse($this->automatedReportsService->get($uuid));
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (Throwable $e) {
$this->logger->error('Failed to get Ask Jiminny report', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to fetch report'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
public function getReportsCount(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$report = $this->automatedReportsService->getReport($uuid);
if ($this->isNotOwnedByUser($report, $user)) {
return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);
}
$resultsCount = $this->automatedReportsService->getReportResults($report)->count();
return new JsonResponse(['count' => $resultsCount]);
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (Throwable $e) {
$this->logger->error('Failed to count report results', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'report_uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to count report results'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* Delete an Ask Jiminny report.
*/
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
if ($request->boolean('delete_generated_reports')) {
$this->automatedReportsService->deleteReportResults($uuid);
}
$report = $this->automatedReportsService->getReport($uuid);
if ($this->isNotOwnedByUser($report, $user)) {
return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);
}
$this->automatedReportsService->delete($uuid);
return new JsonResponse(null, Response::HTTP_NO_CONTENT);
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (Throwable $e) {
$this->logger->error('Failed to delete Ask Jiminny report', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to delete report'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
public function getFilters(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$filters = $this->automatedReportsService->getAskJiminnyReportFilters($user);
return new JsonResponse(['filters' => $filters]);
} catch (Throwable $e) {
$this->logger->error('Failed to fetch Ask Jiminny report filters', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
]);
return new JsonResponse(
['error' => 'Failed to fetch filters'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
10
12
2
4
Previous Highlighted Error
Next Highlighted Error
SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o
JOIN activities a ON o.id = a.opportunity_id
WHERE a.crm_configuration_id = 39
AND a.actual_start_time > '2025-10-13'
AND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM activities
WHERE crm_configuration_id = 39 and user_id = 143
and actual_start_time >= '2025-10-13'
AND type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM opportunities WHERE account_id IN (178);
select * from activities where id IN (620137, 620187, 620188, 620189, 620230);
# HS
SELECT * FROM opportunities WHERE id IN (238);
select * from activities where id IN (477,2076);
select * from users;
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM activities;
SELECT COUNT(*) FROM opportunities;
UPDATE activities
SET
actual_start_time = '2025-12-19 09:00:00',
actual_end_time = '2025-12-19 10:30:00',
scheduled_start_time = '2025-12-19 09:00:00',
scheduled_end_time = '2025-12-19 10:30:00'
WHERE id IN (407509,407375);
select * from partners;
SELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id
FROM activities
WHERE user_id = 143
AND actual_start_time >= '2025-10-13 00:00:00'
AND actual_start_time <= '2026-01-13 23:59:59'
ORDER BY actual_start_time DESC;
SELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;
SELECT * FROM crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;
# lead_id
# account_id 177
# contact_id 3969
# opportunity_id
# stage_id 203
SELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;
SELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'
AND user_id = 143 and actual_start_time >= '2025-10-13';
SELECT * FROM activities a
# JOIN opportunities o ON a.opportunity_id = o.id
WHERE a.crm_configuration_id = 39 AND a.type = 'conference'
and status = 'completed' and recording_state = 'recorded'
and a.actual_start_time >= '2025-10-13'
AND a.user_id = 143
;
select * from leads
where crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310);
SELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198
SELECT * FROM activities WHERE id IN (356001, 356008); # contacts:
SELECT * FROM opportunities WHERE id IN (1707);
SELECT * FROM stages where id IN (204, 198);
SELECT * FROM opportunities WHERE account_id IN (178);
SELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';
SELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal
SELECT * FROM activities where crm_configuration_id = 39
AND opportunity_id IS NULL
AND is_internal = false
and status = 'completed' and recording_state = 'recorded'
AND actual_start_time >= '2025-10-13'
AND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)
# AND lead_id IN (112, 109)
;
SELECT * FROM crm_profiles WHERE user_id = 143;
select * from inboxes; # 212
select * from users where id = 143; # 143
select * from inbox_email_batches where inbox_id = 212
and updated_at >= '2026-01-28 00:00:00' order by id desc;
select * from inbox_emails where inbox_id = 212
and batch_id = 95885 order by id desc;
select * from email_messages where origin_user_id = 143;
select * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';
select * from participants where activity_id = 620247;
select * from crm_profiles where user_id = 143;
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001
select * from transcription where activity_id = 356001; # 6943
select * from ai_prompts where transcription_id = 6943;
SELECT * FROM activity_summary_logs where activity_id = 356001;
SELECT * FROM social_accounts WHERE sociable_id = 143;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;
# 422515 softphone tr. 8100
SELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;
# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS
select * from ai_prompts where transcription_id IN (8100, 7670);
select * from activity_summary_logs where activity_id = 407509;
select * from sidekick_settings;
select * from default_activity_types;
SELECT * FROM contacts WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM leads WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM activity_searches where user_id = 143;
SELECT * FROM groups where team_id = 1;
select * from teams where id = 1;
select * from groups where team_id = 1; # 1150 - 7e75f8025c22
select id, name, group_id, status, deleted_at, email
from users where team_id = 1 order by group_id desc ;
select * from activity_searches where id in (1977, 1978, 1979);
select * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);
select * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277
select * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879
INSERT INTO `activity_search_filters`
(`activity_search_id`, `filter`, `value`) VALUES
(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')
;
select * from crm_configurations where id = 39;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from features;
SELECT * FROM activity_searches where id = 1982; # 1981
SELECT * FROM activity_search_filters WHERE activity_search_id = 1982;
SELECT * FROM automated_reports where id = 68;
SELECT * FROM automated_report_results where id = 275;
SELECT * FROM automated_reports order by id desc;
SELECT * FROM automated_report_results order by id desc;
select * from activity_searches where user_id = 143;
select * from ask_anything_prompts;
SELECT * FROM groups WHERE id = 1439;
SELECT * FROM users WHERE group_id = 1439;
select * from permissions; # 158
select * from roles;
select * from permission_role
select * from teams where id = 1;
select * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;
select * from groups where id = 28;
select * from playbooks where team_id = 1;
select * from playbooks where id = 179;
select * from playbook_categories where id = 1391;
select * from users where id = 143;
select * from crm_profiles where user_id = 143;
select * from activities where crm_configuration_id = 39 and type = 'conference'
and crm_provider_id IS NOT NULL ORDER by id desc;
select * from activities where id = 422003; # 00UO400000pB6fpMAC
SELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type
FROM automated_report_results ar
JOIN automated_reports a ON a.id = ar.report_id
WHERE a.type = 'ask_jiminny'
LIMIT 10;
select * from teams where id = 3143;
select * from crm_configurations where id = 500;
select * from users where name = 'Integration Account'; # 1695
SELECT * FROM social_accounts WHERE sociable_id = 1695;
select * from activities where crm_configuration_id = 39
and recording_state = 'recorded' and duration > 60
and status = 'completed' and actual_start_time >= '2025-12-01'
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11894 on JY-18909-automated-reports-ask-jiminny, menu","depth":5,"help_text":"Pull request #11894 exists for current branch JY-18909-automated-reports-ask-jiminny","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\V2;\n\nuse Illuminate\\Http\\JsonResponse;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Routing\\Controller;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Exceptions\\ModelNotFoundException;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Throwable;\n\nclass AskJiminnyReportsController extends Controller\n{\n public function __construct(\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly LoggerInterface $logger,\n ) {\n }\n\n private function isNotOwnedByUser(AutomatedReport $report, User $user): bool\n {\n return $report->getTeamId() !== $user->getTeamId()\n || $report->getAttribute('created_by') !== $user->getId();\n }\n\n public function getFormData(Request $request, ?string $uuid = null): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $report = $uuid ? $this->automatedReportsService->getReport($uuid) : null;\n\n return new JsonResponse(\n $this->automatedReportsService->getAskJiminnyReportFormData($user, $report)\n );\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (Throwable $e) {\n $this->logger->error('Failed to fetch Ask Jiminny report form data', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to fetch form data'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * Create a new Ask Jiminny report.\n */\n public function create(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $data = $this->automatedReportsService->createAskJiminnyReport($request->all(), $user);\n\n return new JsonResponse($data);\n } catch (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\n } catch (Throwable $e) {\n $this->logger->error('Failed to create Ask Jiminny report', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to create report'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * Update an existing Ask Jiminny report.\n */\n public function update(Request $request, string $uuid): JsonResponse\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info(\"UPDATE\");\n /** @var User $user */\n $user = $request->user();\n\n try {\n $report = $this->automatedReportsService->getReport($uuid);\n\n if ($this->isNotOwnedByUser($report, $user)) {\n return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);\n }\n\n $data = $this->automatedReportsService->updateAskJiminnyReport($report, $request->all(), $user);\n\n return new JsonResponse($data);\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\n } catch (Throwable $e) {\n $this->logger->error('Failed to update Ask Jiminny report', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to update report'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * Toggle Ask Jiminny report status (enable/disable).\n */\n public function toggleStatus(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $report = $this->automatedReportsService->getReport($uuid);\n\n if ($this->isNotOwnedByUser($report, $user)) {\n return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);\n }\n\n $data = $this->automatedReportsService->updateAskJiminnyReportStatus(\n $report,\n (bool) $request->input('enabled'),\n );\n\n return new JsonResponse($data);\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (Throwable $e) {\n $this->logger->error('Failed to toggle Ask Jiminny report status', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to toggle report status'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * List all Ask Jiminny reports.\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $sortColumn = $request->input('sort_column', 'created_at');\n $sortDirection = $request->input('sort_direction', 'desc');\n\n $data = $this->automatedReportsService->listAskJiminnyReports($user, $sortColumn, $sortDirection);\n\n return new JsonResponse($data);\n } catch (Throwable $e) {\n $this->logger->error('Failed to list Ask Jiminny reports', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to fetch reports'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * Get a single Ask Jiminny report.\n */\n public function get(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $report = $this->automatedReportsService->getReport($uuid);\n\n if ($this->isNotOwnedByUser($report, $user)) {\n return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);\n }\n\n return new JsonResponse($this->automatedReportsService->get($uuid));\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (Throwable $e) {\n $this->logger->error('Failed to get Ask Jiminny report', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to fetch report'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n public function getReportsCount(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $report = $this->automatedReportsService->getReport($uuid);\n\n if ($this->isNotOwnedByUser($report, $user)) {\n return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);\n }\n\n $resultsCount = $this->automatedReportsService->getReportResults($report)->count();\n\n return new JsonResponse(['count' => $resultsCount]);\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (Throwable $e) {\n $this->logger->error('Failed to count report results', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'report_uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to count report results'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * Delete an Ask Jiminny report.\n */\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n if ($request->boolean('delete_generated_reports')) {\n $this->automatedReportsService->deleteReportResults($uuid);\n }\n\n $report = $this->automatedReportsService->getReport($uuid);\n\n if ($this->isNotOwnedByUser($report, $user)) {\n return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);\n }\n\n $this->automatedReportsService->delete($uuid);\n\n return new JsonResponse(null, Response::HTTP_NO_CONTENT);\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (Throwable $e) {\n $this->logger->error('Failed to delete Ask Jiminny report', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to delete report'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n public function getFilters(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $filters = $this->automatedReportsService->getAskJiminnyReportFilters($user);\n\n return new JsonResponse(['filters' => $filters]);\n } catch (Throwable $e) {\n $this->logger->error('Failed to fetch Ask Jiminny report filters', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to fetch filters'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Http\\Controllers\\API\\V2;\n\nuse Illuminate\\Http\\JsonResponse;\nuse Illuminate\\Http\\Request;\nuse Illuminate\\Routing\\Controller;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Exceptions\\ModelNotFoundException;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Psr\\Log\\LoggerInterface;\nuse Symfony\\Component\\HttpFoundation\\Response;\nuse Throwable;\n\nclass AskJiminnyReportsController extends Controller\n{\n public function __construct(\n private readonly AutomatedReportsService $automatedReportsService,\n private readonly LoggerInterface $logger,\n ) {\n }\n\n private function isNotOwnedByUser(AutomatedReport $report, User $user): bool\n {\n return $report->getTeamId() !== $user->getTeamId()\n || $report->getAttribute('created_by') !== $user->getId();\n }\n\n public function getFormData(Request $request, ?string $uuid = null): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $report = $uuid ? $this->automatedReportsService->getReport($uuid) : null;\n\n return new JsonResponse(\n $this->automatedReportsService->getAskJiminnyReportFormData($user, $report)\n );\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (Throwable $e) {\n $this->logger->error('Failed to fetch Ask Jiminny report form data', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to fetch form data'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * Create a new Ask Jiminny report.\n */\n public function create(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $data = $this->automatedReportsService->createAskJiminnyReport($request->all(), $user);\n\n return new JsonResponse($data);\n } catch (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\n } catch (Throwable $e) {\n $this->logger->error('Failed to create Ask Jiminny report', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to create report'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * Update an existing Ask Jiminny report.\n */\n public function update(Request $request, string $uuid): JsonResponse\n {\n \\Illuminate\\Support\\Facades\\Log::channel('custom_channel')->info(\"UPDATE\");\n /** @var User $user */\n $user = $request->user();\n\n try {\n $report = $this->automatedReportsService->getReport($uuid);\n\n if ($this->isNotOwnedByUser($report, $user)) {\n return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);\n }\n\n $data = $this->automatedReportsService->updateAskJiminnyReport($report, $request->all(), $user);\n\n return new JsonResponse($data);\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\n } catch (Throwable $e) {\n $this->logger->error('Failed to update Ask Jiminny report', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to update report'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * Toggle Ask Jiminny report status (enable/disable).\n */\n public function toggleStatus(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $report = $this->automatedReportsService->getReport($uuid);\n\n if ($this->isNotOwnedByUser($report, $user)) {\n return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);\n }\n\n $data = $this->automatedReportsService->updateAskJiminnyReportStatus(\n $report,\n (bool) $request->input('enabled'),\n );\n\n return new JsonResponse($data);\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (Throwable $e) {\n $this->logger->error('Failed to toggle Ask Jiminny report status', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to toggle report status'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * List all Ask Jiminny reports.\n */\n public function list(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $sortColumn = $request->input('sort_column', 'created_at');\n $sortDirection = $request->input('sort_direction', 'desc');\n\n $data = $this->automatedReportsService->listAskJiminnyReports($user, $sortColumn, $sortDirection);\n\n return new JsonResponse($data);\n } catch (Throwable $e) {\n $this->logger->error('Failed to list Ask Jiminny reports', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to fetch reports'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * Get a single Ask Jiminny report.\n */\n public function get(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $report = $this->automatedReportsService->getReport($uuid);\n\n if ($this->isNotOwnedByUser($report, $user)) {\n return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);\n }\n\n return new JsonResponse($this->automatedReportsService->get($uuid));\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (Throwable $e) {\n $this->logger->error('Failed to get Ask Jiminny report', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to fetch report'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n public function getReportsCount(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $report = $this->automatedReportsService->getReport($uuid);\n\n if ($this->isNotOwnedByUser($report, $user)) {\n return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);\n }\n\n $resultsCount = $this->automatedReportsService->getReportResults($report)->count();\n\n return new JsonResponse(['count' => $resultsCount]);\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (Throwable $e) {\n $this->logger->error('Failed to count report results', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'report_uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to count report results'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n /**\n * Delete an Ask Jiminny report.\n */\n public function delete(Request $request, string $uuid): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n if ($request->boolean('delete_generated_reports')) {\n $this->automatedReportsService->deleteReportResults($uuid);\n }\n\n $report = $this->automatedReportsService->getReport($uuid);\n\n if ($this->isNotOwnedByUser($report, $user)) {\n return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);\n }\n\n $this->automatedReportsService->delete($uuid);\n\n return new JsonResponse(null, Response::HTTP_NO_CONTENT);\n } catch (ModelNotFoundException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);\n } catch (Throwable $e) {\n $this->logger->error('Failed to delete Ask Jiminny report', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n 'uuid' => $uuid,\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to delete report'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n\n public function getFilters(Request $request): JsonResponse\n {\n /** @var User $user */\n $user = $request->user();\n\n try {\n $filters = $this->automatedReportsService->getAskJiminnyReportFilters($user);\n\n return new JsonResponse(['filters' => $filters]);\n } catch (Throwable $e) {\n $this->logger->error('Failed to fetch Ask Jiminny report filters', [\n 'error' => $e->getMessage(),\n 'user_id' => $user->getId(),\n ]);\n\n return new JsonResponse(\n ['error' => 'Failed to fetch filters'],\n Response::HTTP_INTERNAL_SERVER_ERROR\n );\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"12","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o\nJOIN activities a ON o.id = a.opportunity_id\nWHERE a.crm_configuration_id = 39\nAND a.actual_start_time > '2025-10-13'\nAND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 39 and user_id = 143\nand actual_start_time >= '2025-10-13'\nAND type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM opportunities WHERE account_id IN (178);\nselect * from activities where id IN (620137, 620187, 620188, 620189, 620230);\n\n# HS\nSELECT * FROM opportunities WHERE id IN (238);\nselect * from activities where id IN (477,2076);\n\nselect * from users;\n\nSELECT COUNT(*) FROM users;\nSELECT COUNT(*) FROM activities;\nSELECT COUNT(*) FROM opportunities;\n\nUPDATE activities\nSET\n actual_start_time = '2025-12-19 09:00:00',\n actual_end_time = '2025-12-19 10:30:00',\n scheduled_start_time = '2025-12-19 09:00:00',\n scheduled_end_time = '2025-12-19 10:30:00'\nWHERE id IN (407509,407375);\n\nselect * from partners;\n\nSELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id\nFROM activities\nWHERE user_id = 143\nAND actual_start_time >= '2025-10-13 00:00:00'\nAND actual_start_time <= '2026-01-13 23:59:59'\nORDER BY actual_start_time DESC;\n\nSELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;\nSELECT * FROM crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;\n# lead_id\n# account_id 177\n# contact_id 3969\n# opportunity_id\n# stage_id 203\n\nSELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;\n\nSELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'\nAND user_id = 143 and actual_start_time >= '2025-10-13';\n\nSELECT * FROM activities a\n# JOIN opportunities o ON a.opportunity_id = o.id\nWHERE a.crm_configuration_id = 39 AND a.type = 'conference'\nand status = 'completed' and recording_state = 'recorded'\nand a.actual_start_time >= '2025-10-13'\nAND a.user_id = 143\n;\n\nselect * from leads\nwhere crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707\n\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310);\nSELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198\nSELECT * FROM activities WHERE id IN (356001, 356008); # contacts:\n\nSELECT * FROM opportunities WHERE id IN (1707);\nSELECT * FROM stages where id IN (204, 198);\nSELECT * FROM opportunities WHERE account_id IN (178);\nSELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';\nSELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal\n\nSELECT * FROM activities where crm_configuration_id = 39\nAND opportunity_id IS NULL\nAND is_internal = false\nand status = 'completed' and recording_state = 'recorded'\nAND actual_start_time >= '2025-10-13'\nAND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)\n# AND lead_id IN (112, 109)\n;\n\nSELECT * FROM crm_profiles WHERE user_id = 143;\n\nselect * from inboxes; # 212\nselect * from users where id = 143; # 143\nselect * from inbox_email_batches where inbox_id = 212\nand updated_at >= '2026-01-28 00:00:00' order by id desc;\nselect * from inbox_emails where inbox_id = 212\nand batch_id = 95885 order by id desc;\nselect * from email_messages where origin_user_id = 143;\nselect * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';\nselect * from participants where activity_id = 620247;\n\nselect * from crm_profiles where user_id = 143;\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001\nselect * from transcription where activity_id = 356001; # 6943\nselect * from ai_prompts where transcription_id = 6943;\nSELECT * FROM activity_summary_logs where activity_id = 356001;\n\nSELECT * FROM social_accounts WHERE sociable_id = 143;\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;\n# 422515 softphone tr. 8100\n\nSELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;\n# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS\n\nselect * from ai_prompts where transcription_id IN (8100, 7670);\nselect * from activity_summary_logs where activity_id = 407509;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nSELECT * FROM contacts WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\nSELECT * FROM leads WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\n\nSELECT * FROM activity_searches where user_id = 143;\nSELECT * FROM groups where team_id = 1;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1; # 1150 - 7e75f8025c22\nselect id, name, group_id, status, deleted_at, email\nfrom users where team_id = 1 order by group_id desc ;\n\nselect * from activity_searches where id in (1977, 1978, 1979);\nselect * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);\nselect * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277\nselect * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879\n\nINSERT INTO `activity_search_filters`\n(`activity_search_id`, `filter`, `value`) VALUES\n(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')\n;\n\nselect * from crm_configurations where id = 39;\n\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\nselect * from features;\n\nSELECT * FROM activity_searches where id = 1982; # 1981\nSELECT * FROM activity_search_filters WHERE activity_search_id = 1982;\n\nSELECT * FROM automated_reports where id = 68;\nSELECT * FROM automated_report_results where id = 275;\n\nSELECT * FROM automated_reports order by id desc;\nSELECT * FROM automated_report_results order by id desc;\nselect * from activity_searches where user_id = 143;\nselect * from ask_anything_prompts;\n\nSELECT * FROM groups WHERE id = 1439;\nSELECT * FROM users WHERE group_id = 1439;\n\nselect * from permissions; # 158\nselect * from roles;\nselect * from permission_role\n\nselect * from teams where id = 1;\nselect * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;\nselect * from groups where id = 28;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 179;\nselect * from playbook_categories where id = 1391;\nselect * from users where id = 143;\nselect * from crm_profiles where user_id = 143;\nselect * from activities where crm_configuration_id = 39 and type = 'conference'\nand crm_provider_id IS NOT NULL ORDER by id desc;\nselect * from activities where id = 422003; # 00UO400000pB6fpMAC\n\nSELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type\nFROM automated_report_results ar\nJOIN automated_reports a ON a.id = ar.report_id\nWHERE a.type = 'ask_jiminny'\nLIMIT 10;\n\n\nselect * from teams where id = 3143;\nselect * from crm_configurations where id = 500;\nselect * from users where name = 'Integration Account'; # 1695\nSELECT * FROM social_accounts WHERE sociable_id = 1695;\n\nselect * from activities where crm_configuration_id = 39\nand recording_state = 'recorded' and duration > 60\nand status = 'completed' and actual_start_time >= '2025-12-01'\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid;","depth":4,"value":"SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o\nJOIN activities a ON o.id = a.opportunity_id\nWHERE a.crm_configuration_id = 39\nAND a.actual_start_time > '2025-10-13'\nAND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 39 and user_id = 143\nand actual_start_time >= '2025-10-13'\nAND type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM opportunities WHERE account_id IN (178);\nselect * from activities where id IN (620137, 620187, 620188, 620189, 620230);\n\n# HS\nSELECT * FROM opportunities WHERE id IN (238);\nselect * from activities where id IN (477,2076);\n\nselect * from users;\n\nSELECT COUNT(*) FROM users;\nSELECT COUNT(*) FROM activities;\nSELECT COUNT(*) FROM opportunities;\n\nUPDATE activities\nSET\n actual_start_time = '2025-12-19 09:00:00',\n actual_end_time = '2025-12-19 10:30:00',\n scheduled_start_time = '2025-12-19 09:00:00',\n scheduled_end_time = '2025-12-19 10:30:00'\nWHERE id IN (407509,407375);\n\nselect * from partners;\n\nSELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id\nFROM activities\nWHERE user_id = 143\nAND actual_start_time >= '2025-10-13 00:00:00'\nAND actual_start_time <= '2026-01-13 23:59:59'\nORDER BY actual_start_time DESC;\n\nSELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;\nSELECT * FROM crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;\n# lead_id\n# account_id 177\n# contact_id 3969\n# opportunity_id\n# stage_id 203\n\nSELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;\n\nSELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'\nAND user_id = 143 and actual_start_time >= '2025-10-13';\n\nSELECT * FROM activities a\n# JOIN opportunities o ON a.opportunity_id = o.id\nWHERE a.crm_configuration_id = 39 AND a.type = 'conference'\nand status = 'completed' and recording_state = 'recorded'\nand a.actual_start_time >= '2025-10-13'\nAND a.user_id = 143\n;\n\nselect * from leads\nwhere crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707\n\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310);\nSELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198\nSELECT * FROM activities WHERE id IN (356001, 356008); # contacts:\n\nSELECT * FROM opportunities WHERE id IN (1707);\nSELECT * FROM stages where id IN (204, 198);\nSELECT * FROM opportunities WHERE account_id IN (178);\nSELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';\nSELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal\n\nSELECT * FROM activities where crm_configuration_id = 39\nAND opportunity_id IS NULL\nAND is_internal = false\nand status = 'completed' and recording_state = 'recorded'\nAND actual_start_time >= '2025-10-13'\nAND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)\n# AND lead_id IN (112, 109)\n;\n\nSELECT * FROM crm_profiles WHERE user_id = 143;\n\nselect * from inboxes; # 212\nselect * from users where id = 143; # 143\nselect * from inbox_email_batches where inbox_id = 212\nand updated_at >= '2026-01-28 00:00:00' order by id desc;\nselect * from inbox_emails where inbox_id = 212\nand batch_id = 95885 order by id desc;\nselect * from email_messages where origin_user_id = 143;\nselect * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';\nselect * from participants where activity_id = 620247;\n\nselect * from crm_profiles where user_id = 143;\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001\nselect * from transcription where activity_id = 356001; # 6943\nselect * from ai_prompts where transcription_id = 6943;\nSELECT * FROM activity_summary_logs where activity_id = 356001;\n\nSELECT * FROM social_accounts WHERE sociable_id = 143;\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;\n# 422515 softphone tr. 8100\n\nSELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;\n# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS\n\nselect * from ai_prompts where transcription_id IN (8100, 7670);\nselect * from activity_summary_logs where activity_id = 407509;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nSELECT * FROM contacts WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\nSELECT * FROM leads WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\n\nSELECT * FROM activity_searches where user_id = 143;\nSELECT * FROM groups where team_id = 1;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1; # 1150 - 7e75f8025c22\nselect id, name, group_id, status, deleted_at, email\nfrom users where team_id = 1 order by group_id desc ;\n\nselect * from activity_searches where id in (1977, 1978, 1979);\nselect * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);\nselect * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277\nselect * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879\n\nINSERT INTO `activity_search_filters`\n(`activity_search_id`, `filter`, `value`) VALUES\n(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')\n;\n\nselect * from crm_configurations where id = 39;\n\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\nselect * from features;\n\nSELECT * FROM activity_searches where id = 1982; # 1981\nSELECT * FROM activity_search_filters WHERE activity_search_id = 1982;\n\nSELECT * FROM automated_reports where id = 68;\nSELECT * FROM automated_report_results where id = 275;\n\nSELECT * FROM automated_reports order by id desc;\nSELECT * FROM automated_report_results order by id desc;\nselect * from activity_searches where user_id = 143;\nselect * from ask_anything_prompts;\n\nSELECT * FROM groups WHERE id = 1439;\nSELECT * FROM users WHERE group_id = 1439;\n\nselect * from permissions; # 158\nselect * from roles;\nselect * from permission_role\n\nselect * from teams where id = 1;\nselect * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;\nselect * from groups where id = 28;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 179;\nselect * from playbook_categories where id = 1391;\nselect * from users where id = 143;\nselect * from crm_profiles where user_id = 143;\nselect * from activities where crm_configuration_id = 39 and type = 'conference'\nand crm_provider_id IS NOT NULL ORDER by id desc;\nselect * from activities where id = 422003; # 00UO400000pB6fpMAC\n\nSELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type\nFROM automated_report_results ar\nJOIN automated_reports a ON a.id = ar.report_id\nWHERE a.type = 'ask_jiminny'\nLIMIT 10;\n\n\nselect * from teams where id = 3143;\nselect * from crm_configurations where id = 500;\nselect * from users where name = 'Integration Account'; # 1695\nSELECT * FROM social_accounts WHERE sociable_id = 1695;\n\nselect * from activities where crm_configuration_id = 39\nand recording_state = 'recorded' and duration > 60\nand status = 'completed' and actual_start_time >= '2025-12-01'\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid;","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-7301178313361766127
|
-7003273557753482683
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
1
9
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Http\Controllers\API\V2;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Routing\Controller;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Exceptions\ModelNotFoundException;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Psr\Log\LoggerInterface;
use Symfony\Component\HttpFoundation\Response;
use Throwable;
class AskJiminnyReportsController extends Controller
{
public function __construct(
private readonly AutomatedReportsService $automatedReportsService,
private readonly LoggerInterface $logger,
) {
}
private function isNotOwnedByUser(AutomatedReport $report, User $user): bool
{
return $report->getTeamId() !== $user->getTeamId()
|| $report->getAttribute('created_by') !== $user->getId();
}
public function getFormData(Request $request, ?string $uuid = null): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$report = $uuid ? $this->automatedReportsService->getReport($uuid) : null;
return new JsonResponse(
$this->automatedReportsService->getAskJiminnyReportFormData($user, $report)
);
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (Throwable $e) {
$this->logger->error('Failed to fetch Ask Jiminny report form data', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to fetch form data'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* Create a new Ask Jiminny report.
*/
public function create(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$data = $this->automatedReportsService->createAskJiminnyReport($request->all(), $user);
return new JsonResponse($data);
} catch (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} catch (Throwable $e) {
$this->logger->error('Failed to create Ask Jiminny report', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
]);
return new JsonResponse(
['error' => 'Failed to create report'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* Update an existing Ask Jiminny report.
*/
public function update(Request $request, string $uuid): JsonResponse
{
\Illuminate\Support\Facades\Log::channel('custom_channel')->info("UPDATE");
/** @var User $user */
$user = $request->user();
try {
$report = $this->automatedReportsService->getReport($uuid);
if ($this->isNotOwnedByUser($report, $user)) {
return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);
}
$data = $this->automatedReportsService->updateAskJiminnyReport($report, $request->all(), $user);
return new JsonResponse($data);
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} catch (Throwable $e) {
$this->logger->error('Failed to update Ask Jiminny report', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to update report'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* Toggle Ask Jiminny report status (enable/disable).
*/
public function toggleStatus(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$report = $this->automatedReportsService->getReport($uuid);
if ($this->isNotOwnedByUser($report, $user)) {
return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);
}
$data = $this->automatedReportsService->updateAskJiminnyReportStatus(
$report,
(bool) $request->input('enabled'),
);
return new JsonResponse($data);
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (Throwable $e) {
$this->logger->error('Failed to toggle Ask Jiminny report status', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to toggle report status'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* List all Ask Jiminny reports.
*/
public function list(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$sortColumn = $request->input('sort_column', 'created_at');
$sortDirection = $request->input('sort_direction', 'desc');
$data = $this->automatedReportsService->listAskJiminnyReports($user, $sortColumn, $sortDirection);
return new JsonResponse($data);
} catch (Throwable $e) {
$this->logger->error('Failed to list Ask Jiminny reports', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
]);
return new JsonResponse(
['error' => 'Failed to fetch reports'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* Get a single Ask Jiminny report.
*/
public function get(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$report = $this->automatedReportsService->getReport($uuid);
if ($this->isNotOwnedByUser($report, $user)) {
return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);
}
return new JsonResponse($this->automatedReportsService->get($uuid));
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (Throwable $e) {
$this->logger->error('Failed to get Ask Jiminny report', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to fetch report'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
public function getReportsCount(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$report = $this->automatedReportsService->getReport($uuid);
if ($this->isNotOwnedByUser($report, $user)) {
return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);
}
$resultsCount = $this->automatedReportsService->getReportResults($report)->count();
return new JsonResponse(['count' => $resultsCount]);
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (Throwable $e) {
$this->logger->error('Failed to count report results', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'report_uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to count report results'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
/**
* Delete an Ask Jiminny report.
*/
public function delete(Request $request, string $uuid): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
if ($request->boolean('delete_generated_reports')) {
$this->automatedReportsService->deleteReportResults($uuid);
}
$report = $this->automatedReportsService->getReport($uuid);
if ($this->isNotOwnedByUser($report, $user)) {
return new JsonResponse(['error' => 'Report not found'], Response::HTTP_NOT_FOUND);
}
$this->automatedReportsService->delete($uuid);
return new JsonResponse(null, Response::HTTP_NO_CONTENT);
} catch (ModelNotFoundException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_NOT_FOUND);
} catch (Throwable $e) {
$this->logger->error('Failed to delete Ask Jiminny report', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
'uuid' => $uuid,
]);
return new JsonResponse(
['error' => 'Failed to delete report'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
public function getFilters(Request $request): JsonResponse
{
/** @var User $user */
$user = $request->user();
try {
$filters = $this->automatedReportsService->getAskJiminnyReportFilters($user);
return new JsonResponse(['filters' => $filters]);
} catch (Throwable $e) {
$this->logger->error('Failed to fetch Ask Jiminny report filters', [
'error' => $e->getMessage(),
'user_id' => $user->getId(),
]);
return new JsonResponse(
['error' => 'Failed to fetch filters'],
Response::HTTP_INTERNAL_SERVER_ERROR
);
}
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
10
12
2
4
Previous Highlighted Error
Next Highlighted Error
SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o
JOIN activities a ON o.id = a.opportunity_id
WHERE a.crm_configuration_id = 39
AND a.actual_start_time > '2025-10-13'
AND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM activities
WHERE crm_configuration_id = 39 and user_id = 143
and actual_start_time >= '2025-10-13'
AND type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM opportunities WHERE account_id IN (178);
select * from activities where id IN (620137, 620187, 620188, 620189, 620230);
# HS
SELECT * FROM opportunities WHERE id IN (238);
select * from activities where id IN (477,2076);
select * from users;
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM activities;
SELECT COUNT(*) FROM opportunities;
UPDATE activities
SET
actual_start_time = '2025-12-19 09:00:00',
actual_end_time = '2025-12-19 10:30:00',
scheduled_start_time = '2025-12-19 09:00:00',
scheduled_end_time = '2025-12-19 10:30:00'
WHERE id IN (407509,407375);
select * from partners;
SELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id
FROM activities
WHERE user_id = 143
AND actual_start_time >= '2025-10-13 00:00:00'
AND actual_start_time <= '2026-01-13 23:59:59'
ORDER BY actual_start_time DESC;
SELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;
SELECT * FROM crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;
# lead_id
# account_id 177
# contact_id 3969
# opportunity_id
# stage_id 203
SELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;
SELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'
AND user_id = 143 and actual_start_time >= '2025-10-13';
SELECT * FROM activities a
# JOIN opportunities o ON a.opportunity_id = o.id
WHERE a.crm_configuration_id = 39 AND a.type = 'conference'
and status = 'completed' and recording_state = 'recorded'
and a.actual_start_time >= '2025-10-13'
AND a.user_id = 143
;
select * from leads
where crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310);
SELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198
SELECT * FROM activities WHERE id IN (356001, 356008); # contacts:
SELECT * FROM opportunities WHERE id IN (1707);
SELECT * FROM stages where id IN (204, 198);
SELECT * FROM opportunities WHERE account_id IN (178);
SELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';
SELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal
SELECT * FROM activities where crm_configuration_id = 39
AND opportunity_id IS NULL
AND is_internal = false
and status = 'completed' and recording_state = 'recorded'
AND actual_start_time >= '2025-10-13'
AND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)
# AND lead_id IN (112, 109)
;
SELECT * FROM crm_profiles WHERE user_id = 143;
select * from inboxes; # 212
select * from users where id = 143; # 143
select * from inbox_email_batches where inbox_id = 212
and updated_at >= '2026-01-28 00:00:00' order by id desc;
select * from inbox_emails where inbox_id = 212
and batch_id = 95885 order by id desc;
select * from email_messages where origin_user_id = 143;
select * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';
select * from participants where activity_id = 620247;
select * from crm_profiles where user_id = 143;
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001
select * from transcription where activity_id = 356001; # 6943
select * from ai_prompts where transcription_id = 6943;
SELECT * FROM activity_summary_logs where activity_id = 356001;
SELECT * FROM social_accounts WHERE sociable_id = 143;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;
# 422515 softphone tr. 8100
SELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;
# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS
select * from ai_prompts where transcription_id IN (8100, 7670);
select * from activity_summary_logs where activity_id = 407509;
select * from sidekick_settings;
select * from default_activity_types;
SELECT * FROM contacts WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM leads WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM activity_searches where user_id = 143;
SELECT * FROM groups where team_id = 1;
select * from teams where id = 1;
select * from groups where team_id = 1; # 1150 - 7e75f8025c22
select id, name, group_id, status, deleted_at, email
from users where team_id = 1 order by group_id desc ;
select * from activity_searches where id in (1977, 1978, 1979);
select * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);
select * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277
select * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879
INSERT INTO `activity_search_filters`
(`activity_search_id`, `filter`, `value`) VALUES
(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')
;
select * from crm_configurations where id = 39;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from features;
SELECT * FROM activity_searches where id = 1982; # 1981
SELECT * FROM activity_search_filters WHERE activity_search_id = 1982;
SELECT * FROM automated_reports where id = 68;
SELECT * FROM automated_report_results where id = 275;
SELECT * FROM automated_reports order by id desc;
SELECT * FROM automated_report_results order by id desc;
select * from activity_searches where user_id = 143;
select * from ask_anything_prompts;
SELECT * FROM groups WHERE id = 1439;
SELECT * FROM users WHERE group_id = 1439;
select * from permissions; # 158
select * from roles;
select * from permission_role
select * from teams where id = 1;
select * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;
select * from groups where id = 28;
select * from playbooks where team_id = 1;
select * from playbooks where id = 179;
select * from playbook_categories where id = 1391;
select * from users where id = 143;
select * from crm_profiles where user_id = 143;
select * from activities where crm_configuration_id = 39 and type = 'conference'
and crm_provider_id IS NOT NULL ORDER by id desc;
select * from activities where id = 422003; # 00UO400000pB6fpMAC
SELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type
FROM automated_report_results ar
JOIN automated_reports a ON a.id = ar.report_id
WHERE a.type = 'ask_jiminny'
LIMIT 10;
select * from teams where id = 3143;
select * from crm_configurations where id = 500;
select * from users where name = 'Integration Account'; # 1695
SELECT * FROM social_accounts WHERE sociable_id = 1695;
select * from activities where crm_configuration_id = 39
and recording_state = 'recorded' and duration > 60
and status = 'completed' and actual_start_time >= '2025-12-01'
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
54883
|
NULL
|
0
|
2026-04-20T09:22:28.423426+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776676948423_m2.jpg...
|
PhpStorm
|
faVsco.js – AskJiminnyReportActivityServiceTest.ph faVsco.js – AskJiminnyReportActivityServiceTest.php...
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Services\Kiosk\AutomatedReports;
use Carbon\CarbonImmutable;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityActualDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityUpdatedDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\DealInsights\ClosingPeriodFilter;
use Jiminny\Component\ActivitySearch\FilterDefinitionCollection;
use Jiminny\Component\ActivitySearch\Service\ActivitySearch;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\Activity\SearchFilter;
use Jiminny\Models\User;
use Jiminny\Repositories\ElasticActivityRepository;
use Jiminny\Services\Kiosk\AutomatedReports\AskJiminnyReportActivityService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\VO\Repository\OnDemandActivitySearch\Criteria;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
class AskJiminnyReportActivityServiceTest extends TestCase
{
private ActivitySearch&MockObject $activitySearch;
private ElasticActivityRepository&MockObject $elasticRepository;
private LoggerInterface&MockObject $logger;
private AskJiminnyReportActivityService $service;
protected function setUp(): void
{
$this->activitySearch = $this->createMock(ActivitySearch::class);
$this->elasticRepository = $this->createMock(ElasticActivityRepository::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->service = new AskJiminnyReportActivityService(
$this->activitySearch,
$this->elasticRepository,
$this->logger,
);
}
private function makeFilter(string $key, ?string $value): SearchFilter&MockObject
{
$filter = $this->createMock(SearchFilter::class);
$filter->method('getFilterProperty')->willReturn($key);
$filter->method('getFilterValue')->willReturn($value);
return $filter;
}
private function makeUser(): User&MockObject
{
$tz = new \DateTimeZone('UTC');
$user = $this->createMock(User::class);
$user->method('getTimezone')->willReturn($tz);
$user->method('getId')->willReturn(1);
$user->method('getUuid')->willReturn('user-uuid');
return $user;
}
private function makeSavedSearch(array $filters): Search&MockObject
{
$savedSearch = $this->createMock(Search::class);
$savedSearch->method('getId')->willReturn(42);
$savedSearch->method('getFilters')->willReturn(new \Illuminate\Support\LazyCollection($filters));
return $savedSearch;
}
public function testGetActivityIdsForSavedSearchReturnsIds(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->expects($this->once())
->method('getArrayFilterKeys')
->with($user)
->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->expects($this->once())
->method('onDemandSearchIdsOnly')
->willReturn(['id-1', 'id-2', 'id-3']);
$this->logger->expects($this->once())
->method('info')
->with('[AskJiminnyReport] Fetched activity IDs for saved search');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1', 'id-2', 'id-3'], $result);
}
public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->expects($this->once())->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEmpty($result);
}
public function testGetActivityIdsFiltersOutDateFilters(): void
{
$user = $this->makeUser();
$nonDateFilter = $this->makeFilter('owner_id', '123');
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');
$updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');
$updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');
$savedSearch = $this->makeSavedSearch([
$nonDateFilter,
$startDateFilter,
$endDateFilter,
$updatedFromFilter,
$updatedToFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
}
public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void
{
$user = $this->makeUser();
$closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');
$closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');
$regularFilter = $this->makeFilter('rep_id', '99');
$savedSearch = $this->makeSavedSearch([
$closingStartFilter,
$closingEndFilter,
$regularFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesArrayFilters(): void
{
$user = $this->makeUser();
$filter1 = $this->makeFilter('outcome', 'positive');
$filter2 = $this->makeFilter('outcome', 'negative');
$savedSearch = $this->makeSavedSearch([$filter1, $filter2]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesScalarFilters(): void
{
$user = $this->makeUser();
$filter = $this->makeFilter('direction', 'inbound');
$savedSearch = $this->makeSavedSearch([$filter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-5'], $result);
}
public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
$this->assertFalse($capturedCriteria->isFirstRequest());
}
public function testGetActivityIdsLogsWithCorrectContext(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);
$this->logger->expects($this->once())
->method('info')
->with(
'[AskJiminnyReport] Fetched activity IDs for saved search',
$this->callback(fn ($context) => $context['saved_search_id'] === 42
&& $context['user_id'] === 1
&& $context['activity_count'] === 2)
);
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
}
public static function frequencyDateRangeProvider(): array
{
return [
'daily' => [
AutomatedReportsService::FREQUENCY_DAILY,
'2025-06-15 00:00:00',
'2025-06-15 23:59:59',
],
'weekly' => [
AutomatedReportsService::FREQUENCY_WEEKLY,
'2025-06-09 00:00:00',
'2025-06-15 23:59:59',
],
'monthly' => [
AutomatedReportsService::FREQUENCY_MONTHLY,
'2025-05-01 00:00:00',
'2025-05-31 23:59:59',
],
'quarterly' => [
AutomatedReportsService::FREQUENCY_QUARTERLY,
'2025-01-01 00:00:00',
'2025-03-31 23:59:59',
],
];
}
/**
* @dataProvider frequencyDateRangeProvider
*/
public function testGetActivityIdsInjectsDateRangeForFrequency(
string $frequency,
string $expectedStartDate,
string $expectedEndDate,
): void {
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);
$this->assertNotNull($capturedCriteria);
$this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void
{
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');
$savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);
$this->assertNotNull($capturedCriteria);
$this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl, folder
ActionItems, folder
Activity, folder
ActivityAnalytics, folder
ActivitySearch, folder
EventSubscriber, folder
FilterDefinition, folder
DealInsights, folder
Security
TeamInsights
ActivityActualDate.php, class
ActivityChannel.php, final class
ActivityDurationRange.php, class
ActivityFilter.php, final class
ActivityPlaylistIn.php, final class
ActivityProviderIn.php, final class
ActivityRecorded.php, class
ActivityRecordingStopped.php, final class
ActivityScheduledDate.php, final class
ActivityStatusIn.php, class
ActivityType.php, final class
ActivityUpdatedDate.php, final class
AiCallScoreFilter.php, final class
AutoScoreFilter.php, final class
ClosedDealsFilter.php, final class
CoachingFeedbackAverageScore.php, final class
CoachingFeedbackCoachUserIn.php, final class
CommentCountRange.php, final class
CrmFieldCollection.php, final class
CurrentStage.php, final class
Customer.php, final class
CustomerMonologueDuration.php, final class
CustomerQuestionCount.php, final class
DealAge.php, final class
DealCloseDate.php, final class
DealValue.php, final class
EngagingQuestionCount.php, final class
ExternalId.php, final class
HasPendingAiCrmNotes.php, final class
HasTopicTriggersFilterDefinition.php, final class
HasTranscription.php, final class
InputTypeEnum.php, final class
InsightfulQuestionCount.php, final class
LanguageFilterDefinition.php, final class
LoggedToCrm.php, final class
NudgeRunId.php, final class
OnlyActiveUsers.php, final class
OrganiserGroupIn.php, class
OrganiserTeamIn.php, final class
OrganiserUserIn.php, class
OrganiserUserNotIn.php, final class
ParticipantUserIn.php, final class
PartnerFilterDefinition.php, final class
PatienceRange.php, final class
PlaybackTopicFilterDefinition.php, final class
ProviderFilterDefinition.php, final class
ShowInternalExternalActivitiesFilter.php, final class
SortBy.php, final class
SpeechRate.php, final class
StageAtCallFilterDefinition.php, class
TalkTimeRatio.php, final class
TeamMemberUserIn.php, final class
TranscriptionComposite.php, final class
UserGroupInOptionalFilter.php, final class
UserMonologueDuration.php, final class
UserQuestionCount.php, final class
Service
AbstractStageFilterDefinition.php, abstract class
ActivitySearchServiceProvider.php, final class
DealInsightsPeriodFilterFactory.php
DealInsightsPeriodFilterFactoryInterface.php, interface
FilterDefinition.php, abstract class
FilterDefinitionCollection.php, class
FilterDefinitionQuery.php, class
FilterDefinitionQueryCollection.php, class
FilteredValueContainerInterface.php, interface
IntMinMaxRange.php, class
AiActivityType
AiAutomation
AiCallScoring
AskAnything
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model
Notification
Nudge
ParagraphBreaker
ParticipantSpeech
PartitionedCookie
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11894 on JY-18909-automated-reports-ask-jiminny, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #11894 exists for current branch JY-18909-automated-reports-ask-jiminny","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.006981383,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Services\\Kiosk\\AutomatedReports;\n\nuse Carbon\\CarbonImmutable;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityActualDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityUpdatedDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\DealInsights\\ClosingPeriodFilter;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionCollection;\nuse Jiminny\\Component\\ActivitySearch\\Service\\ActivitySearch;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\Activity\\SearchFilter;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\ElasticActivityRepository;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AskJiminnyReportActivityService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\VO\\Repository\\OnDemandActivitySearch\\Criteria;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\n\nclass AskJiminnyReportActivityServiceTest extends TestCase\n{\n private ActivitySearch&MockObject $activitySearch;\n private ElasticActivityRepository&MockObject $elasticRepository;\n private LoggerInterface&MockObject $logger;\n private AskJiminnyReportActivityService $service;\n\n protected function setUp(): void\n {\n $this->activitySearch = $this->createMock(ActivitySearch::class);\n $this->elasticRepository = $this->createMock(ElasticActivityRepository::class);\n $this->logger = $this->createMock(LoggerInterface::class);\n\n $this->service = new AskJiminnyReportActivityService(\n $this->activitySearch,\n $this->elasticRepository,\n $this->logger,\n );\n }\n\n private function makeFilter(string $key, ?string $value): SearchFilter&MockObject\n {\n $filter = $this->createMock(SearchFilter::class);\n $filter->method('getFilterProperty')->willReturn($key);\n $filter->method('getFilterValue')->willReturn($value);\n\n return $filter;\n }\n\n private function makeUser(): User&MockObject\n {\n $tz = new \\DateTimeZone('UTC');\n $user = $this->createMock(User::class);\n $user->method('getTimezone')->willReturn($tz);\n $user->method('getId')->willReturn(1);\n $user->method('getUuid')->willReturn('user-uuid');\n\n return $user;\n }\n\n private function makeSavedSearch(array $filters): Search&MockObject\n {\n $savedSearch = $this->createMock(Search::class);\n $savedSearch->method('getId')->willReturn(42);\n $savedSearch->method('getFilters')->willReturn(new \\Illuminate\\Support\\LazyCollection($filters));\n\n return $savedSearch;\n }\n\n public function testGetActivityIdsForSavedSearchReturnsIds(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->expects($this->once())\n ->method('getArrayFilterKeys')\n ->with($user)\n ->willReturn([]);\n\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n\n $this->elasticRepository->expects($this->once())\n ->method('onDemandSearchIdsOnly')\n ->willReturn(['id-1', 'id-2', 'id-3']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[AskJiminnyReport] Fetched activity IDs for saved search');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1', 'id-2', 'id-3'], $result);\n }\n\n public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $this->logger->expects($this->once())->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEmpty($result);\n }\n\n public function testGetActivityIdsFiltersOutDateFilters(): void\n {\n $user = $this->makeUser();\n\n $nonDateFilter = $this->makeFilter('owner_id', '123');\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');\n $updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');\n $updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');\n\n $savedSearch = $this->makeSavedSearch([\n $nonDateFilter,\n $startDateFilter,\n $endDateFilter,\n $updatedFromFilter,\n $updatedToFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n }\n\n public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void\n {\n $user = $this->makeUser();\n\n $closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');\n $closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');\n $regularFilter = $this->makeFilter('rep_id', '99');\n\n $savedSearch = $this->makeSavedSearch([\n $closingStartFilter,\n $closingEndFilter,\n $regularFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesArrayFilters(): void\n {\n $user = $this->makeUser();\n\n $filter1 = $this->makeFilter('outcome', 'positive');\n $filter2 = $this->makeFilter('outcome', 'negative');\n\n $savedSearch = $this->makeSavedSearch([$filter1, $filter2]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesScalarFilters(): void\n {\n $user = $this->makeUser();\n\n $filter = $this->makeFilter('direction', 'inbound');\n $savedSearch = $this->makeSavedSearch([$filter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-5'], $result);\n }\n\n public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertFalse($capturedCriteria->isFirstRequest());\n }\n\n public function testGetActivityIdsLogsWithCorrectContext(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with(\n '[AskJiminnyReport] Fetched activity IDs for saved search',\n $this->callback(fn ($context) => $context['saved_search_id'] === 42\n && $context['user_id'] === 1\n && $context['activity_count'] === 2)\n );\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n }\n\n public static function frequencyDateRangeProvider(): array\n {\n return [\n 'daily' => [\n AutomatedReportsService::FREQUENCY_DAILY,\n '2025-06-15 00:00:00',\n '2025-06-15 23:59:59',\n ],\n 'weekly' => [\n AutomatedReportsService::FREQUENCY_WEEKLY,\n '2025-06-09 00:00:00',\n '2025-06-15 23:59:59',\n ],\n 'monthly' => [\n AutomatedReportsService::FREQUENCY_MONTHLY,\n '2025-05-01 00:00:00',\n '2025-05-31 23:59:59',\n ],\n 'quarterly' => [\n AutomatedReportsService::FREQUENCY_QUARTERLY,\n '2025-01-01 00:00:00',\n '2025-03-31 23:59:59',\n ],\n ];\n }\n\n /**\n * @dataProvider frequencyDateRangeProvider\n */\n public function testGetActivityIdsInjectsDateRangeForFrequency(\n string $frequency,\n string $expectedStartDate,\n string $expectedEndDate,\n ): void {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n\n public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void\n {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');\n $savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n}","depth":4,"bounds":{"left":0.13863032,"top":0.27055067,"width":0.34375,"height":0.72944933},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Services\\Kiosk\\AutomatedReports;\n\nuse Carbon\\CarbonImmutable;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityActualDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityUpdatedDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\DealInsights\\ClosingPeriodFilter;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionCollection;\nuse Jiminny\\Component\\ActivitySearch\\Service\\ActivitySearch;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\Activity\\SearchFilter;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\ElasticActivityRepository;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AskJiminnyReportActivityService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\VO\\Repository\\OnDemandActivitySearch\\Criteria;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\n\nclass AskJiminnyReportActivityServiceTest extends TestCase\n{\n private ActivitySearch&MockObject $activitySearch;\n private ElasticActivityRepository&MockObject $elasticRepository;\n private LoggerInterface&MockObject $logger;\n private AskJiminnyReportActivityService $service;\n\n protected function setUp(): void\n {\n $this->activitySearch = $this->createMock(ActivitySearch::class);\n $this->elasticRepository = $this->createMock(ElasticActivityRepository::class);\n $this->logger = $this->createMock(LoggerInterface::class);\n\n $this->service = new AskJiminnyReportActivityService(\n $this->activitySearch,\n $this->elasticRepository,\n $this->logger,\n );\n }\n\n private function makeFilter(string $key, ?string $value): SearchFilter&MockObject\n {\n $filter = $this->createMock(SearchFilter::class);\n $filter->method('getFilterProperty')->willReturn($key);\n $filter->method('getFilterValue')->willReturn($value);\n\n return $filter;\n }\n\n private function makeUser(): User&MockObject\n {\n $tz = new \\DateTimeZone('UTC');\n $user = $this->createMock(User::class);\n $user->method('getTimezone')->willReturn($tz);\n $user->method('getId')->willReturn(1);\n $user->method('getUuid')->willReturn('user-uuid');\n\n return $user;\n }\n\n private function makeSavedSearch(array $filters): Search&MockObject\n {\n $savedSearch = $this->createMock(Search::class);\n $savedSearch->method('getId')->willReturn(42);\n $savedSearch->method('getFilters')->willReturn(new \\Illuminate\\Support\\LazyCollection($filters));\n\n return $savedSearch;\n }\n\n public function testGetActivityIdsForSavedSearchReturnsIds(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->expects($this->once())\n ->method('getArrayFilterKeys')\n ->with($user)\n ->willReturn([]);\n\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n\n $this->elasticRepository->expects($this->once())\n ->method('onDemandSearchIdsOnly')\n ->willReturn(['id-1', 'id-2', 'id-3']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[AskJiminnyReport] Fetched activity IDs for saved search');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1', 'id-2', 'id-3'], $result);\n }\n\n public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $this->logger->expects($this->once())->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEmpty($result);\n }\n\n public function testGetActivityIdsFiltersOutDateFilters(): void\n {\n $user = $this->makeUser();\n\n $nonDateFilter = $this->makeFilter('owner_id', '123');\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');\n $updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');\n $updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');\n\n $savedSearch = $this->makeSavedSearch([\n $nonDateFilter,\n $startDateFilter,\n $endDateFilter,\n $updatedFromFilter,\n $updatedToFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n }\n\n public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void\n {\n $user = $this->makeUser();\n\n $closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');\n $closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');\n $regularFilter = $this->makeFilter('rep_id', '99');\n\n $savedSearch = $this->makeSavedSearch([\n $closingStartFilter,\n $closingEndFilter,\n $regularFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesArrayFilters(): void\n {\n $user = $this->makeUser();\n\n $filter1 = $this->makeFilter('outcome', 'positive');\n $filter2 = $this->makeFilter('outcome', 'negative');\n\n $savedSearch = $this->makeSavedSearch([$filter1, $filter2]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesScalarFilters(): void\n {\n $user = $this->makeUser();\n\n $filter = $this->makeFilter('direction', 'inbound');\n $savedSearch = $this->makeSavedSearch([$filter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-5'], $result);\n }\n\n public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertFalse($capturedCriteria->isFirstRequest());\n }\n\n public function testGetActivityIdsLogsWithCorrectContext(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with(\n '[AskJiminnyReport] Fetched activity IDs for saved search',\n $this->callback(fn ($context) => $context['saved_search_id'] === 42\n && $context['user_id'] === 1\n && $context['activity_count'] === 2)\n );\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n }\n\n public static function frequencyDateRangeProvider(): array\n {\n return [\n 'daily' => [\n AutomatedReportsService::FREQUENCY_DAILY,\n '2025-06-15 00:00:00',\n '2025-06-15 23:59:59',\n ],\n 'weekly' => [\n AutomatedReportsService::FREQUENCY_WEEKLY,\n '2025-06-09 00:00:00',\n '2025-06-15 23:59:59',\n ],\n 'monthly' => [\n AutomatedReportsService::FREQUENCY_MONTHLY,\n '2025-05-01 00:00:00',\n '2025-05-31 23:59:59',\n ],\n 'quarterly' => [\n AutomatedReportsService::FREQUENCY_QUARTERLY,\n '2025-01-01 00:00:00',\n '2025-03-31 23:59:59',\n ],\n ];\n }\n\n /**\n * @dataProvider frequencyDateRangeProvider\n */\n public function testGetActivityIdsInjectsDateRangeForFrequency(\n string $frequency,\n string $expectedStartDate,\n string $expectedEndDate,\n ): void {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n\n public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void\n {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');\n $savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":4,"bounds":{"left":0.4225399,"top":0.09736632,"width":0.30618352,"height":0.8818835},"value":"","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Acl, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Activity, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"EventSubscriber, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"FilterDefinition, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights, folder","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"Security","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"TeamInsights","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityActualDate.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityChannel.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityDurationRange.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityFilter.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityPlaylistIn.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityProviderIn.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityRecorded.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityRecordingStopped.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityScheduledDate.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityStatusIn.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityType.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityUpdatedDate.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoreFilter.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"AutoScoreFilter.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ClosedDealsFilter.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedbackAverageScore.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedbackCoachUserIn.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"CommentCountRange.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"CrmFieldCollection.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"CurrentStage.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"Customer.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"CustomerMonologueDuration.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"CustomerQuestionCount.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"DealAge.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"DealCloseDate.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"DealValue.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"EngagingQuestionCount.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ExternalId.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"HasPendingAiCrmNotes.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"HasTopicTriggersFilterDefinition.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"HasTranscription.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"InputTypeEnum.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"InsightfulQuestionCount.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"LanguageFilterDefinition.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"LoggedToCrm.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"NudgeRunId.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"OnlyActiveUsers.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"OrganiserGroupIn.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"OrganiserTeamIn.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"OrganiserUserIn.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"OrganiserUserNotIn.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantUserIn.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"PartnerFilterDefinition.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"PatienceRange.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackTopicFilterDefinition.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ProviderFilterDefinition.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ShowInternalExternalActivitiesFilter.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"SortBy.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"SpeechRate.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"StageAtCallFilterDefinition.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"TalkTimeRatio.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"TeamMemberUserIn.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"TranscriptionComposite.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"UserGroupInOptionalFilter.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"UserMonologueDuration.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"UserQuestionCount.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"Service","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"AbstractStageFilterDefinition.php, abstract class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearchServiceProvider.php, final class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"DealInsightsPeriodFilterFactory.php","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"DealInsightsPeriodFilterFactoryInterface.php, interface","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"FilterDefinition.php, abstract class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"FilterDefinitionCollection.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"FilterDefinitionQuery.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"FilterDefinitionQueryCollection.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"FilteredValueContainerInterface.php, interface","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"IntMinMaxRange.php, class","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"AiActivityType","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiAutomation","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoring","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AskAnything","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AskJiminnyAi","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"AWS","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"BillingManagement","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Cache","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedback","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Country","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"CustomerApi","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Database","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Datadog","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DateTime","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"DealRisks","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ElasticSearch","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Eloquent","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Encoding","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Encryption","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ES","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Faker","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"FeatureFlags","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"FFMpeg","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"FileSystem","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Gecko","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Gong","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"GuzzleHttp","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"KeyPoints","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Kiosk","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"LanguageDetection","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"LiveFeed","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Locks","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Math","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"MediaPipeline","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"MeetingBot","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"MobileSettings","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Model","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Notification","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Nudge","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ParagraphBreaker","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ParticipantSpeech","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"PartitionedCookie","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"PlaybackPage","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Playlist","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Prophet","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ProphetAi","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ProsperWorks","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Queue","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Router","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Saml2","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"SCIM","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Seeder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Sentry","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Serializer","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Settings","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Sidekick","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Slack","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"TeamInsights","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"TimeMemoryMapper","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Transcription","depth":9,"role_description":"text"}]...
|
-7383354862135176937
|
956156635419710870
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Services\Kiosk\AutomatedReports;
use Carbon\CarbonImmutable;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityActualDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityUpdatedDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\DealInsights\ClosingPeriodFilter;
use Jiminny\Component\ActivitySearch\FilterDefinitionCollection;
use Jiminny\Component\ActivitySearch\Service\ActivitySearch;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\Activity\SearchFilter;
use Jiminny\Models\User;
use Jiminny\Repositories\ElasticActivityRepository;
use Jiminny\Services\Kiosk\AutomatedReports\AskJiminnyReportActivityService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\VO\Repository\OnDemandActivitySearch\Criteria;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
class AskJiminnyReportActivityServiceTest extends TestCase
{
private ActivitySearch&MockObject $activitySearch;
private ElasticActivityRepository&MockObject $elasticRepository;
private LoggerInterface&MockObject $logger;
private AskJiminnyReportActivityService $service;
protected function setUp(): void
{
$this->activitySearch = $this->createMock(ActivitySearch::class);
$this->elasticRepository = $this->createMock(ElasticActivityRepository::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->service = new AskJiminnyReportActivityService(
$this->activitySearch,
$this->elasticRepository,
$this->logger,
);
}
private function makeFilter(string $key, ?string $value): SearchFilter&MockObject
{
$filter = $this->createMock(SearchFilter::class);
$filter->method('getFilterProperty')->willReturn($key);
$filter->method('getFilterValue')->willReturn($value);
return $filter;
}
private function makeUser(): User&MockObject
{
$tz = new \DateTimeZone('UTC');
$user = $this->createMock(User::class);
$user->method('getTimezone')->willReturn($tz);
$user->method('getId')->willReturn(1);
$user->method('getUuid')->willReturn('user-uuid');
return $user;
}
private function makeSavedSearch(array $filters): Search&MockObject
{
$savedSearch = $this->createMock(Search::class);
$savedSearch->method('getId')->willReturn(42);
$savedSearch->method('getFilters')->willReturn(new \Illuminate\Support\LazyCollection($filters));
return $savedSearch;
}
public function testGetActivityIdsForSavedSearchReturnsIds(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->expects($this->once())
->method('getArrayFilterKeys')
->with($user)
->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->expects($this->once())
->method('onDemandSearchIdsOnly')
->willReturn(['id-1', 'id-2', 'id-3']);
$this->logger->expects($this->once())
->method('info')
->with('[AskJiminnyReport] Fetched activity IDs for saved search');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1', 'id-2', 'id-3'], $result);
}
public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->expects($this->once())->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEmpty($result);
}
public function testGetActivityIdsFiltersOutDateFilters(): void
{
$user = $this->makeUser();
$nonDateFilter = $this->makeFilter('owner_id', '123');
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');
$updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');
$updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');
$savedSearch = $this->makeSavedSearch([
$nonDateFilter,
$startDateFilter,
$endDateFilter,
$updatedFromFilter,
$updatedToFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
}
public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void
{
$user = $this->makeUser();
$closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');
$closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');
$regularFilter = $this->makeFilter('rep_id', '99');
$savedSearch = $this->makeSavedSearch([
$closingStartFilter,
$closingEndFilter,
$regularFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesArrayFilters(): void
{
$user = $this->makeUser();
$filter1 = $this->makeFilter('outcome', 'positive');
$filter2 = $this->makeFilter('outcome', 'negative');
$savedSearch = $this->makeSavedSearch([$filter1, $filter2]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesScalarFilters(): void
{
$user = $this->makeUser();
$filter = $this->makeFilter('direction', 'inbound');
$savedSearch = $this->makeSavedSearch([$filter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-5'], $result);
}
public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
$this->assertFalse($capturedCriteria->isFirstRequest());
}
public function testGetActivityIdsLogsWithCorrectContext(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);
$this->logger->expects($this->once())
->method('info')
->with(
'[AskJiminnyReport] Fetched activity IDs for saved search',
$this->callback(fn ($context) => $context['saved_search_id'] === 42
&& $context['user_id'] === 1
&& $context['activity_count'] === 2)
);
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
}
public static function frequencyDateRangeProvider(): array
{
return [
'daily' => [
AutomatedReportsService::FREQUENCY_DAILY,
'2025-06-15 00:00:00',
'2025-06-15 23:59:59',
],
'weekly' => [
AutomatedReportsService::FREQUENCY_WEEKLY,
'2025-06-09 00:00:00',
'2025-06-15 23:59:59',
],
'monthly' => [
AutomatedReportsService::FREQUENCY_MONTHLY,
'2025-05-01 00:00:00',
'2025-05-31 23:59:59',
],
'quarterly' => [
AutomatedReportsService::FREQUENCY_QUARTERLY,
'2025-01-01 00:00:00',
'2025-03-31 23:59:59',
],
];
}
/**
* @dataProvider frequencyDateRangeProvider
*/
public function testGetActivityIdsInjectsDateRangeForFrequency(
string $frequency,
string $expectedStartDate,
string $expectedEndDate,
): void {
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);
$this->assertNotNull($capturedCriteria);
$this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void
{
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');
$savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);
$this->assertNotNull($capturedCriteria);
$this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl, folder
ActionItems, folder
Activity, folder
ActivityAnalytics, folder
ActivitySearch, folder
EventSubscriber, folder
FilterDefinition, folder
DealInsights, folder
Security
TeamInsights
ActivityActualDate.php, class
ActivityChannel.php, final class
ActivityDurationRange.php, class
ActivityFilter.php, final class
ActivityPlaylistIn.php, final class
ActivityProviderIn.php, final class
ActivityRecorded.php, class
ActivityRecordingStopped.php, final class
ActivityScheduledDate.php, final class
ActivityStatusIn.php, class
ActivityType.php, final class
ActivityUpdatedDate.php, final class
AiCallScoreFilter.php, final class
AutoScoreFilter.php, final class
ClosedDealsFilter.php, final class
CoachingFeedbackAverageScore.php, final class
CoachingFeedbackCoachUserIn.php, final class
CommentCountRange.php, final class
CrmFieldCollection.php, final class
CurrentStage.php, final class
Customer.php, final class
CustomerMonologueDuration.php, final class
CustomerQuestionCount.php, final class
DealAge.php, final class
DealCloseDate.php, final class
DealValue.php, final class
EngagingQuestionCount.php, final class
ExternalId.php, final class
HasPendingAiCrmNotes.php, final class
HasTopicTriggersFilterDefinition.php, final class
HasTranscription.php, final class
InputTypeEnum.php, final class
InsightfulQuestionCount.php, final class
LanguageFilterDefinition.php, final class
LoggedToCrm.php, final class
NudgeRunId.php, final class
OnlyActiveUsers.php, final class
OrganiserGroupIn.php, class
OrganiserTeamIn.php, final class
OrganiserUserIn.php, class
OrganiserUserNotIn.php, final class
ParticipantUserIn.php, final class
PartnerFilterDefinition.php, final class
PatienceRange.php, final class
PlaybackTopicFilterDefinition.php, final class
ProviderFilterDefinition.php, final class
ShowInternalExternalActivitiesFilter.php, final class
SortBy.php, final class
SpeechRate.php, final class
StageAtCallFilterDefinition.php, class
TalkTimeRatio.php, final class
TeamMemberUserIn.php, final class
TranscriptionComposite.php, final class
UserGroupInOptionalFilter.php, final class
UserMonologueDuration.php, final class
UserQuestionCount.php, final class
Service
AbstractStageFilterDefinition.php, abstract class
ActivitySearchServiceProvider.php, final class
DealInsightsPeriodFilterFactory.php
DealInsightsPeriodFilterFactoryInterface.php, interface
FilterDefinition.php, abstract class
FilterDefinitionCollection.php, class
FilterDefinitionQuery.php, class
FilterDefinitionQueryCollection.php, class
FilteredValueContainerInterface.php, interface
IntMinMaxRange.php, class
AiActivityType
AiAutomation
AiCallScoring
AskAnything
AskJiminnyAi
AWS
BillingManagement
Cache
CoachingFeedback
Country
CustomerApi
Database
Datadog
DateTime
DealInsights
DealRisks
ElasticSearch
Eloquent
Encoding
Encryption
ES
Faker
FeatureFlags
FFMpeg
FileSystem
Gecko
Gong
GuzzleHttp
KeyPoints
Kiosk
LanguageDetection
LiveFeed
Locks
Math
MediaPipeline
MeetingBot
MobileSettings
Model
Notification
Nudge
ParagraphBreaker
ParticipantSpeech
PartitionedCookie
PlaybackPage
Playlist
Prophet
ProphetAi
ProsperWorks
Queue
Router
Saml2
SCIM
Seeder
Sentry
Serializer
Settings
Sidekick
Slack
TeamInsights
TimeMemoryMapper
Transcription...
|
NULL
|
|
54882
|
NULL
|
0
|
2026-04-20T09:22:27.697787+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776676947697_m1.jpg...
|
PhpStorm
|
faVsco.js – AskJiminnyReportActivityServiceTest.ph faVsco.js – AskJiminnyReportActivityServiceTest.php...
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Services\Kiosk\AutomatedReports;
use Carbon\CarbonImmutable;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityActualDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityUpdatedDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\DealInsights\ClosingPeriodFilter;
use Jiminny\Component\ActivitySearch\FilterDefinitionCollection;
use Jiminny\Component\ActivitySearch\Service\ActivitySearch;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\Activity\SearchFilter;
use Jiminny\Models\User;
use Jiminny\Repositories\ElasticActivityRepository;
use Jiminny\Services\Kiosk\AutomatedReports\AskJiminnyReportActivityService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\VO\Repository\OnDemandActivitySearch\Criteria;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
class AskJiminnyReportActivityServiceTest extends TestCase
{
private ActivitySearch&MockObject $activitySearch;
private ElasticActivityRepository&MockObject $elasticRepository;
private LoggerInterface&MockObject $logger;
private AskJiminnyReportActivityService $service;
protected function setUp(): void
{
$this->activitySearch = $this->createMock(ActivitySearch::class);
$this->elasticRepository = $this->createMock(ElasticActivityRepository::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->service = new AskJiminnyReportActivityService(
$this->activitySearch,
$this->elasticRepository,
$this->logger,
);
}
private function makeFilter(string $key, ?string $value): SearchFilter&MockObject
{
$filter = $this->createMock(SearchFilter::class);
$filter->method('getFilterProperty')->willReturn($key);
$filter->method('getFilterValue')->willReturn($value);
return $filter;
}
private function makeUser(): User&MockObject
{
$tz = new \DateTimeZone('UTC');
$user = $this->createMock(User::class);
$user->method('getTimezone')->willReturn($tz);
$user->method('getId')->willReturn(1);
$user->method('getUuid')->willReturn('user-uuid');
return $user;
}
private function makeSavedSearch(array $filters): Search&MockObject
{
$savedSearch = $this->createMock(Search::class);
$savedSearch->method('getId')->willReturn(42);
$savedSearch->method('getFilters')->willReturn(new \Illuminate\Support\LazyCollection($filters));
return $savedSearch;
}
public function testGetActivityIdsForSavedSearchReturnsIds(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->expects($this->once())
->method('getArrayFilterKeys')
->with($user)
->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->expects($this->once())
->method('onDemandSearchIdsOnly')
->willReturn(['id-1', 'id-2', 'id-3']);
$this->logger->expects($this->once())
->method('info')
->with('[AskJiminnyReport] Fetched activity IDs for saved search');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1', 'id-2', 'id-3'], $result);
}
public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->expects($this->once())->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEmpty($result);
}
public function testGetActivityIdsFiltersOutDateFilters(): void
{
$user = $this->makeUser();
$nonDateFilter = $this->makeFilter('owner_id', '123');
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');
$updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');
$updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');
$savedSearch = $this->makeSavedSearch([
$nonDateFilter,
$startDateFilter,
$endDateFilter,
$updatedFromFilter,
$updatedToFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
}
public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void
{
$user = $this->makeUser();
$closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');
$closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');
$regularFilter = $this->makeFilter('rep_id', '99');
$savedSearch = $this->makeSavedSearch([
$closingStartFilter,
$closingEndFilter,
$regularFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesArrayFilters(): void
{
$user = $this->makeUser();
$filter1 = $this->makeFilter('outcome', 'positive');
$filter2 = $this->makeFilter('outcome', 'negative');
$savedSearch = $this->makeSavedSearch([$filter1, $filter2]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesScalarFilters(): void
{
$user = $this->makeUser();
$filter = $this->makeFilter('direction', 'inbound');
$savedSearch = $this->makeSavedSearch([$filter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-5'], $result);
}
public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
$this->assertFalse($capturedCriteria->isFirstRequest());
}
public function testGetActivityIdsLogsWithCorrectContext(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);
$this->logger->expects($this->once())
->method('info')
->with(
'[AskJiminnyReport] Fetched activity IDs for saved search',
$this->callback(fn ($context) => $context['saved_search_id'] === 42
&& $context['user_id'] === 1
&& $context['activity_count'] === 2)
);
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
}
public static function frequencyDateRangeProvider(): array
{
return [
'daily' => [
AutomatedReportsService::FREQUENCY_DAILY,
'2025-06-15 00:00:00',
'2025-06-15 23:59:59',
],
'weekly' => [
AutomatedReportsService::FREQUENCY_WEEKLY,
'2025-06-09 00:00:00',
'2025-06-15 23:59:59',
],
'monthly' => [
AutomatedReportsService::FREQUENCY_MONTHLY,
'2025-05-01 00:00:00',
'2025-05-31 23:59:59',
],
'quarterly' => [
AutomatedReportsService::FREQUENCY_QUARTERLY,
'2025-01-01 00:00:00',
'2025-03-31 23:59:59',
],
];
}
/**
* @dataProvider frequencyDateRangeProvider
*/
public function testGetActivityIdsInjectsDateRangeForFrequency(
string $frequency,
string $expectedStartDate,
string $expectedEndDate,
): void {
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);
$this->assertNotNull($capturedCriteria);
$this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void
{
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');
$savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);
$this->assertNotNull($capturedCriteria);
$this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl, folder
ActionItems, folder
Activity, folder
ActivityAnalytics, folder
ActivitySearch, folder
EventSubscriber, folder
FilterDefinition, folder
DealInsights, folder
Security
TeamInsights
ActivityActualDate.php, class
ActivityChannel.php, final class
ActivityDurationRange.php, class
ActivityFilter.php, final class
ActivityPlaylistIn.php, final class
ActivityProviderIn.php, final class
ActivityRecorded.php, class
ActivityRecordingStopped.php, final class
ActivityScheduledDate.php, final class
ActivityStatusIn.php, class
ActivityType.php, final class
ActivityUpdatedDate.php, final class
AiCallScoreFilter.php, final class
AutoScoreFilter.php, final class
ClosedDealsFilter.php, final class
CoachingFeedbackAverageScore.php, final class
CoachingFeedbackCoachUserIn.php, final class
CommentCountRange.php, final class
CrmFieldCollection.php, final class
CurrentStage.php, final class
Customer.php, final class
CustomerMonologueDuration.php, final class
CustomerQuestionCount.php, final class
DealAge.php, final class
DealCloseDate.php, final class
DealValue.php, final class
EngagingQuestionCount.php, final class
ExternalId.php, final class
HasPendingAiCrmNotes.php, final class
HasTopicTriggersFilterDefinition.php, final class...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11894 on JY-18909-automated-reports-ask-jiminny, menu","depth":5,"help_text":"Pull request #11894 exists for current branch JY-18909-automated-reports-ask-jiminny","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.016666668,"height":0.02111111},"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.016666668,"height":0.02111111},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.025555555},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.014583333,"height":0.025555555},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Services\\Kiosk\\AutomatedReports;\n\nuse Carbon\\CarbonImmutable;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityActualDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityUpdatedDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\DealInsights\\ClosingPeriodFilter;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionCollection;\nuse Jiminny\\Component\\ActivitySearch\\Service\\ActivitySearch;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\Activity\\SearchFilter;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\ElasticActivityRepository;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AskJiminnyReportActivityService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\VO\\Repository\\OnDemandActivitySearch\\Criteria;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\n\nclass AskJiminnyReportActivityServiceTest extends TestCase\n{\n private ActivitySearch&MockObject $activitySearch;\n private ElasticActivityRepository&MockObject $elasticRepository;\n private LoggerInterface&MockObject $logger;\n private AskJiminnyReportActivityService $service;\n\n protected function setUp(): void\n {\n $this->activitySearch = $this->createMock(ActivitySearch::class);\n $this->elasticRepository = $this->createMock(ElasticActivityRepository::class);\n $this->logger = $this->createMock(LoggerInterface::class);\n\n $this->service = new AskJiminnyReportActivityService(\n $this->activitySearch,\n $this->elasticRepository,\n $this->logger,\n );\n }\n\n private function makeFilter(string $key, ?string $value): SearchFilter&MockObject\n {\n $filter = $this->createMock(SearchFilter::class);\n $filter->method('getFilterProperty')->willReturn($key);\n $filter->method('getFilterValue')->willReturn($value);\n\n return $filter;\n }\n\n private function makeUser(): User&MockObject\n {\n $tz = new \\DateTimeZone('UTC');\n $user = $this->createMock(User::class);\n $user->method('getTimezone')->willReturn($tz);\n $user->method('getId')->willReturn(1);\n $user->method('getUuid')->willReturn('user-uuid');\n\n return $user;\n }\n\n private function makeSavedSearch(array $filters): Search&MockObject\n {\n $savedSearch = $this->createMock(Search::class);\n $savedSearch->method('getId')->willReturn(42);\n $savedSearch->method('getFilters')->willReturn(new \\Illuminate\\Support\\LazyCollection($filters));\n\n return $savedSearch;\n }\n\n public function testGetActivityIdsForSavedSearchReturnsIds(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->expects($this->once())\n ->method('getArrayFilterKeys')\n ->with($user)\n ->willReturn([]);\n\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n\n $this->elasticRepository->expects($this->once())\n ->method('onDemandSearchIdsOnly')\n ->willReturn(['id-1', 'id-2', 'id-3']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[AskJiminnyReport] Fetched activity IDs for saved search');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1', 'id-2', 'id-3'], $result);\n }\n\n public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $this->logger->expects($this->once())->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEmpty($result);\n }\n\n public function testGetActivityIdsFiltersOutDateFilters(): void\n {\n $user = $this->makeUser();\n\n $nonDateFilter = $this->makeFilter('owner_id', '123');\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');\n $updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');\n $updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');\n\n $savedSearch = $this->makeSavedSearch([\n $nonDateFilter,\n $startDateFilter,\n $endDateFilter,\n $updatedFromFilter,\n $updatedToFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n }\n\n public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void\n {\n $user = $this->makeUser();\n\n $closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');\n $closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');\n $regularFilter = $this->makeFilter('rep_id', '99');\n\n $savedSearch = $this->makeSavedSearch([\n $closingStartFilter,\n $closingEndFilter,\n $regularFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesArrayFilters(): void\n {\n $user = $this->makeUser();\n\n $filter1 = $this->makeFilter('outcome', 'positive');\n $filter2 = $this->makeFilter('outcome', 'negative');\n\n $savedSearch = $this->makeSavedSearch([$filter1, $filter2]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesScalarFilters(): void\n {\n $user = $this->makeUser();\n\n $filter = $this->makeFilter('direction', 'inbound');\n $savedSearch = $this->makeSavedSearch([$filter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-5'], $result);\n }\n\n public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertFalse($capturedCriteria->isFirstRequest());\n }\n\n public function testGetActivityIdsLogsWithCorrectContext(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with(\n '[AskJiminnyReport] Fetched activity IDs for saved search',\n $this->callback(fn ($context) => $context['saved_search_id'] === 42\n && $context['user_id'] === 1\n && $context['activity_count'] === 2)\n );\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n }\n\n public static function frequencyDateRangeProvider(): array\n {\n return [\n 'daily' => [\n AutomatedReportsService::FREQUENCY_DAILY,\n '2025-06-15 00:00:00',\n '2025-06-15 23:59:59',\n ],\n 'weekly' => [\n AutomatedReportsService::FREQUENCY_WEEKLY,\n '2025-06-09 00:00:00',\n '2025-06-15 23:59:59',\n ],\n 'monthly' => [\n AutomatedReportsService::FREQUENCY_MONTHLY,\n '2025-05-01 00:00:00',\n '2025-05-31 23:59:59',\n ],\n 'quarterly' => [\n AutomatedReportsService::FREQUENCY_QUARTERLY,\n '2025-01-01 00:00:00',\n '2025-03-31 23:59:59',\n ],\n ];\n }\n\n /**\n * @dataProvider frequencyDateRangeProvider\n */\n public function testGetActivityIdsInjectsDateRangeForFrequency(\n string $frequency,\n string $expectedStartDate,\n string $expectedEndDate,\n ): void {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n\n public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void\n {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');\n $savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Services\\Kiosk\\AutomatedReports;\n\nuse Carbon\\CarbonImmutable;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityActualDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityUpdatedDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\DealInsights\\ClosingPeriodFilter;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionCollection;\nuse Jiminny\\Component\\ActivitySearch\\Service\\ActivitySearch;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\Activity\\SearchFilter;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\ElasticActivityRepository;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AskJiminnyReportActivityService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\VO\\Repository\\OnDemandActivitySearch\\Criteria;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\n\nclass AskJiminnyReportActivityServiceTest extends TestCase\n{\n private ActivitySearch&MockObject $activitySearch;\n private ElasticActivityRepository&MockObject $elasticRepository;\n private LoggerInterface&MockObject $logger;\n private AskJiminnyReportActivityService $service;\n\n protected function setUp(): void\n {\n $this->activitySearch = $this->createMock(ActivitySearch::class);\n $this->elasticRepository = $this->createMock(ElasticActivityRepository::class);\n $this->logger = $this->createMock(LoggerInterface::class);\n\n $this->service = new AskJiminnyReportActivityService(\n $this->activitySearch,\n $this->elasticRepository,\n $this->logger,\n );\n }\n\n private function makeFilter(string $key, ?string $value): SearchFilter&MockObject\n {\n $filter = $this->createMock(SearchFilter::class);\n $filter->method('getFilterProperty')->willReturn($key);\n $filter->method('getFilterValue')->willReturn($value);\n\n return $filter;\n }\n\n private function makeUser(): User&MockObject\n {\n $tz = new \\DateTimeZone('UTC');\n $user = $this->createMock(User::class);\n $user->method('getTimezone')->willReturn($tz);\n $user->method('getId')->willReturn(1);\n $user->method('getUuid')->willReturn('user-uuid');\n\n return $user;\n }\n\n private function makeSavedSearch(array $filters): Search&MockObject\n {\n $savedSearch = $this->createMock(Search::class);\n $savedSearch->method('getId')->willReturn(42);\n $savedSearch->method('getFilters')->willReturn(new \\Illuminate\\Support\\LazyCollection($filters));\n\n return $savedSearch;\n }\n\n public function testGetActivityIdsForSavedSearchReturnsIds(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->expects($this->once())\n ->method('getArrayFilterKeys')\n ->with($user)\n ->willReturn([]);\n\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n\n $this->elasticRepository->expects($this->once())\n ->method('onDemandSearchIdsOnly')\n ->willReturn(['id-1', 'id-2', 'id-3']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[AskJiminnyReport] Fetched activity IDs for saved search');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1', 'id-2', 'id-3'], $result);\n }\n\n public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $this->logger->expects($this->once())->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEmpty($result);\n }\n\n public function testGetActivityIdsFiltersOutDateFilters(): void\n {\n $user = $this->makeUser();\n\n $nonDateFilter = $this->makeFilter('owner_id', '123');\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');\n $updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');\n $updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');\n\n $savedSearch = $this->makeSavedSearch([\n $nonDateFilter,\n $startDateFilter,\n $endDateFilter,\n $updatedFromFilter,\n $updatedToFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n }\n\n public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void\n {\n $user = $this->makeUser();\n\n $closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');\n $closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');\n $regularFilter = $this->makeFilter('rep_id', '99');\n\n $savedSearch = $this->makeSavedSearch([\n $closingStartFilter,\n $closingEndFilter,\n $regularFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesArrayFilters(): void\n {\n $user = $this->makeUser();\n\n $filter1 = $this->makeFilter('outcome', 'positive');\n $filter2 = $this->makeFilter('outcome', 'negative');\n\n $savedSearch = $this->makeSavedSearch([$filter1, $filter2]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesScalarFilters(): void\n {\n $user = $this->makeUser();\n\n $filter = $this->makeFilter('direction', 'inbound');\n $savedSearch = $this->makeSavedSearch([$filter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-5'], $result);\n }\n\n public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertFalse($capturedCriteria->isFirstRequest());\n }\n\n public function testGetActivityIdsLogsWithCorrectContext(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with(\n '[AskJiminnyReport] Fetched activity IDs for saved search',\n $this->callback(fn ($context) => $context['saved_search_id'] === 42\n && $context['user_id'] === 1\n && $context['activity_count'] === 2)\n );\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n }\n\n public static function frequencyDateRangeProvider(): array\n {\n return [\n 'daily' => [\n AutomatedReportsService::FREQUENCY_DAILY,\n '2025-06-15 00:00:00',\n '2025-06-15 23:59:59',\n ],\n 'weekly' => [\n AutomatedReportsService::FREQUENCY_WEEKLY,\n '2025-06-09 00:00:00',\n '2025-06-15 23:59:59',\n ],\n 'monthly' => [\n AutomatedReportsService::FREQUENCY_MONTHLY,\n '2025-05-01 00:00:00',\n '2025-05-31 23:59:59',\n ],\n 'quarterly' => [\n AutomatedReportsService::FREQUENCY_QUARTERLY,\n '2025-01-01 00:00:00',\n '2025-03-31 23:59:59',\n ],\n ];\n }\n\n /**\n * @dataProvider frequencyDateRangeProvider\n */\n public function testGetActivityIdsInjectsDateRangeForFrequency(\n string $frequency,\n string $expectedStartDate,\n string $expectedEndDate,\n ): void {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n\n public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void\n {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');\n $savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"","depth":4,"value":"","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"app ~/jiminny/app","depth":6,"role_description":"text"},{"role":"AXStaticText","text":".circleci","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".cursor","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".github","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".sonarlint","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".vscode","depth":7,"role_description":"text"},{"role":"AXStaticText","text":".windsurf","depth":7,"role_description":"text"},{"role":"AXStaticText","text":"app, sources root","depth":7,"role_description":"text"},{"role":"AXStaticText","text":"Actions","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Component","depth":8,"role_description":"text"},{"role":"AXStaticText","text":"Acl, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActionItems, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"Activity, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActivityAnalytics, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"ActivitySearch, folder","depth":9,"role_description":"text"},{"role":"AXStaticText","text":"EventSubscriber, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"FilterDefinition, folder","depth":10,"role_description":"text"},{"role":"AXStaticText","text":"DealInsights, folder","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"Security","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"TeamInsights","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityActualDate.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityChannel.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityDurationRange.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityFilter.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityPlaylistIn.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityProviderIn.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityRecorded.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityRecordingStopped.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityScheduledDate.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityStatusIn.php, class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityType.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ActivityUpdatedDate.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"AiCallScoreFilter.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"AutoScoreFilter.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ClosedDealsFilter.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedbackAverageScore.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"CoachingFeedbackCoachUserIn.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"CommentCountRange.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"CrmFieldCollection.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"CurrentStage.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"Customer.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"CustomerMonologueDuration.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"CustomerQuestionCount.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"DealAge.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"DealCloseDate.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"DealValue.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"EngagingQuestionCount.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"ExternalId.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"HasPendingAiCrmNotes.php, final class","depth":11,"role_description":"text"},{"role":"AXStaticText","text":"HasTopicTriggersFilterDefinition.php, final class","depth":11,"role_description":"text"}]...
|
9186995013950281446
|
956156618775664006
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Services\Kiosk\AutomatedReports;
use Carbon\CarbonImmutable;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityActualDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityUpdatedDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\DealInsights\ClosingPeriodFilter;
use Jiminny\Component\ActivitySearch\FilterDefinitionCollection;
use Jiminny\Component\ActivitySearch\Service\ActivitySearch;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\Activity\SearchFilter;
use Jiminny\Models\User;
use Jiminny\Repositories\ElasticActivityRepository;
use Jiminny\Services\Kiosk\AutomatedReports\AskJiminnyReportActivityService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\VO\Repository\OnDemandActivitySearch\Criteria;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
class AskJiminnyReportActivityServiceTest extends TestCase
{
private ActivitySearch&MockObject $activitySearch;
private ElasticActivityRepository&MockObject $elasticRepository;
private LoggerInterface&MockObject $logger;
private AskJiminnyReportActivityService $service;
protected function setUp(): void
{
$this->activitySearch = $this->createMock(ActivitySearch::class);
$this->elasticRepository = $this->createMock(ElasticActivityRepository::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->service = new AskJiminnyReportActivityService(
$this->activitySearch,
$this->elasticRepository,
$this->logger,
);
}
private function makeFilter(string $key, ?string $value): SearchFilter&MockObject
{
$filter = $this->createMock(SearchFilter::class);
$filter->method('getFilterProperty')->willReturn($key);
$filter->method('getFilterValue')->willReturn($value);
return $filter;
}
private function makeUser(): User&MockObject
{
$tz = new \DateTimeZone('UTC');
$user = $this->createMock(User::class);
$user->method('getTimezone')->willReturn($tz);
$user->method('getId')->willReturn(1);
$user->method('getUuid')->willReturn('user-uuid');
return $user;
}
private function makeSavedSearch(array $filters): Search&MockObject
{
$savedSearch = $this->createMock(Search::class);
$savedSearch->method('getId')->willReturn(42);
$savedSearch->method('getFilters')->willReturn(new \Illuminate\Support\LazyCollection($filters));
return $savedSearch;
}
public function testGetActivityIdsForSavedSearchReturnsIds(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->expects($this->once())
->method('getArrayFilterKeys')
->with($user)
->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->expects($this->once())
->method('onDemandSearchIdsOnly')
->willReturn(['id-1', 'id-2', 'id-3']);
$this->logger->expects($this->once())
->method('info')
->with('[AskJiminnyReport] Fetched activity IDs for saved search');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1', 'id-2', 'id-3'], $result);
}
public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->expects($this->once())->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEmpty($result);
}
public function testGetActivityIdsFiltersOutDateFilters(): void
{
$user = $this->makeUser();
$nonDateFilter = $this->makeFilter('owner_id', '123');
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');
$updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');
$updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');
$savedSearch = $this->makeSavedSearch([
$nonDateFilter,
$startDateFilter,
$endDateFilter,
$updatedFromFilter,
$updatedToFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
}
public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void
{
$user = $this->makeUser();
$closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');
$closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');
$regularFilter = $this->makeFilter('rep_id', '99');
$savedSearch = $this->makeSavedSearch([
$closingStartFilter,
$closingEndFilter,
$regularFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesArrayFilters(): void
{
$user = $this->makeUser();
$filter1 = $this->makeFilter('outcome', 'positive');
$filter2 = $this->makeFilter('outcome', 'negative');
$savedSearch = $this->makeSavedSearch([$filter1, $filter2]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesScalarFilters(): void
{
$user = $this->makeUser();
$filter = $this->makeFilter('direction', 'inbound');
$savedSearch = $this->makeSavedSearch([$filter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-5'], $result);
}
public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
$this->assertFalse($capturedCriteria->isFirstRequest());
}
public function testGetActivityIdsLogsWithCorrectContext(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);
$this->logger->expects($this->once())
->method('info')
->with(
'[AskJiminnyReport] Fetched activity IDs for saved search',
$this->callback(fn ($context) => $context['saved_search_id'] === 42
&& $context['user_id'] === 1
&& $context['activity_count'] === 2)
);
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
}
public static function frequencyDateRangeProvider(): array
{
return [
'daily' => [
AutomatedReportsService::FREQUENCY_DAILY,
'2025-06-15 00:00:00',
'2025-06-15 23:59:59',
],
'weekly' => [
AutomatedReportsService::FREQUENCY_WEEKLY,
'2025-06-09 00:00:00',
'2025-06-15 23:59:59',
],
'monthly' => [
AutomatedReportsService::FREQUENCY_MONTHLY,
'2025-05-01 00:00:00',
'2025-05-31 23:59:59',
],
'quarterly' => [
AutomatedReportsService::FREQUENCY_QUARTERLY,
'2025-01-01 00:00:00',
'2025-03-31 23:59:59',
],
];
}
/**
* @dataProvider frequencyDateRangeProvider
*/
public function testGetActivityIdsInjectsDateRangeForFrequency(
string $frequency,
string $expectedStartDate,
string $expectedEndDate,
): void {
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);
$this->assertNotNull($capturedCriteria);
$this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void
{
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');
$savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);
$this->assertNotNull($capturedCriteria);
$this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
}
Code changed:
Hide
Sync Changes
Hide This Notification
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide
app ~/jiminny/app
.circleci
.cursor
.github
.sonarlint
.vscode
.windsurf
app, sources root
Actions
Component
Acl, folder
ActionItems, folder
Activity, folder
ActivityAnalytics, folder
ActivitySearch, folder
EventSubscriber, folder
FilterDefinition, folder
DealInsights, folder
Security
TeamInsights
ActivityActualDate.php, class
ActivityChannel.php, final class
ActivityDurationRange.php, class
ActivityFilter.php, final class
ActivityPlaylistIn.php, final class
ActivityProviderIn.php, final class
ActivityRecorded.php, class
ActivityRecordingStopped.php, final class
ActivityScheduledDate.php, final class
ActivityStatusIn.php, class
ActivityType.php, final class
ActivityUpdatedDate.php, final class
AiCallScoreFilter.php, final class
AutoScoreFilter.php, final class
ClosedDealsFilter.php, final class
CoachingFeedbackAverageScore.php, final class
CoachingFeedbackCoachUserIn.php, final class
CommentCountRange.php, final class
CrmFieldCollection.php, final class
CurrentStage.php, final class
Customer.php, final class
CustomerMonologueDuration.php, final class
CustomerQuestionCount.php, final class
DealAge.php, final class
DealCloseDate.php, final class
DealValue.php, final class
EngagingQuestionCount.php, final class
ExternalId.php, final class
HasPendingAiCrmNotes.php, final class
HasTopicTriggersFilterDefinition.php, final class...
|
54879
|
|
54729
|
NULL
|
0
|
2026-04-20T09:17:19.473373+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776676639473_m1.jpg...
|
PhpStorm
|
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
January
February
March
April
May
June
July
August
September
October
November
December
2026
10
:
30
:
0...
|
[{"role":"AXStaticText","text& [{"role":"AXStaticText","text":"1","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"4","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"5","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"6","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"7","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"8","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"9","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"10","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"11","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"12","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"13","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"14","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"15","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"16","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"18","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"19","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"20","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"21","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"22","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"23","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"24","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"25","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"26","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"27","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"28","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"29","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"30","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"31","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"January","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"February","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"March","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"April","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"May","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"June","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"July","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"August","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"September","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"October","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"November","depth":6,"role_description":"text"},{"role":"AXStaticText","text":"December","depth":6,"role_description":"text"},{"role":"AXTextField","text":"2026","depth":2,"value":"2026","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"10","depth":2,"value":"10","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":":","depth":1,"role_description":"text"},{"role":"AXTextField","text":"30","depth":2,"value":"30","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":":","depth":1,"role_description":"text"},{"role":"AXTextField","text":"0","depth":2,"value":"0","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4438512630616932095
|
-350000261908515320
|
click
|
accessibility
|
NULL
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
January
February
March
April
May
June
July
August
September
October
November
December
2026
10
:
30
:
0...
|
NULL
|
|
54728
|
NULL
|
0
|
2026-04-20T09:17:15.768156+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776676635768_m2.jpg...
|
PhpStorm
|
faVsco.js – SF [jiminny@localhost]
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Services\Kiosk\AutomatedReports;
use Carbon\CarbonImmutable;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityActualDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityUpdatedDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\DealInsights\ClosingPeriodFilter;
use Jiminny\Component\ActivitySearch\FilterDefinitionCollection;
use Jiminny\Component\ActivitySearch\Service\ActivitySearch;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\Activity\SearchFilter;
use Jiminny\Models\User;
use Jiminny\Repositories\ElasticActivityRepository;
use Jiminny\Services\Kiosk\AutomatedReports\AskJiminnyReportActivityService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\VO\Repository\OnDemandActivitySearch\Criteria;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
class AskJiminnyReportActivityServiceTest extends TestCase
{
private ActivitySearch&MockObject $activitySearch;
private ElasticActivityRepository&MockObject $elasticRepository;
private LoggerInterface&MockObject $logger;
private AskJiminnyReportActivityService $service;
protected function setUp(): void
{
$this->activitySearch = $this->createMock(ActivitySearch::class);
$this->elasticRepository = $this->createMock(ElasticActivityRepository::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->service = new AskJiminnyReportActivityService(
$this->activitySearch,
$this->elasticRepository,
$this->logger,
);
}
private function makeFilter(string $key, ?string $value): SearchFilter&MockObject
{
$filter = $this->createMock(SearchFilter::class);
$filter->method('getFilterProperty')->willReturn($key);
$filter->method('getFilterValue')->willReturn($value);
return $filter;
}
private function makeUser(): User&MockObject
{
$tz = new \DateTimeZone('UTC');
$user = $this->createMock(User::class);
$user->method('getTimezone')->willReturn($tz);
$user->method('getId')->willReturn(1);
$user->method('getUuid')->willReturn('user-uuid');
return $user;
}
private function makeSavedSearch(array $filters): Search&MockObject
{
$savedSearch = $this->createMock(Search::class);
$savedSearch->method('getId')->willReturn(42);
$savedSearch->method('getFilters')->willReturn(new \Illuminate\Support\LazyCollection($filters));
return $savedSearch;
}
public function testGetActivityIdsForSavedSearchReturnsIds(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->expects($this->once())
->method('getArrayFilterKeys')
->with($user)
->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->expects($this->once())
->method('onDemandSearchIdsOnly')
->willReturn(['id-1', 'id-2', 'id-3']);
$this->logger->expects($this->once())
->method('info')
->with('[AskJiminnyReport] Fetched activity IDs for saved search');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1', 'id-2', 'id-3'], $result);
}
public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->expects($this->once())->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEmpty($result);
}
public function testGetActivityIdsFiltersOutDateFilters(): void
{
$user = $this->makeUser();
$nonDateFilter = $this->makeFilter('owner_id', '123');
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');
$updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');
$updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');
$savedSearch = $this->makeSavedSearch([
$nonDateFilter,
$startDateFilter,
$endDateFilter,
$updatedFromFilter,
$updatedToFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
}
public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void
{
$user = $this->makeUser();
$closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');
$closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');
$regularFilter = $this->makeFilter('rep_id', '99');
$savedSearch = $this->makeSavedSearch([
$closingStartFilter,
$closingEndFilter,
$regularFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesArrayFilters(): void
{
$user = $this->makeUser();
$filter1 = $this->makeFilter('outcome', 'positive');
$filter2 = $this->makeFilter('outcome', 'negative');
$savedSearch = $this->makeSavedSearch([$filter1, $filter2]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesScalarFilters(): void
{
$user = $this->makeUser();
$filter = $this->makeFilter('direction', 'inbound');
$savedSearch = $this->makeSavedSearch([$filter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-5'], $result);
}
public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
$this->assertFalse($capturedCriteria->isFirstRequest());
}
public function testGetActivityIdsLogsWithCorrectContext(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);
$this->logger->expects($this->once())
->method('info')
->with(
'[AskJiminnyReport] Fetched activity IDs for saved search',
$this->callback(fn ($context) => $context['saved_search_id'] === 42
&& $context['user_id'] === 1
&& $context['activity_count'] === 2)
);
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
}
public static function frequencyDateRangeProvider(): array
{
return [
'daily' => [
AutomatedReportsService::FREQUENCY_DAILY,
'2025-06-15 00:00:00',
'2025-06-15 23:59:59',
],
'weekly' => [
AutomatedReportsService::FREQUENCY_WEEKLY,
'2025-06-09 00:00:00',
'2025-06-15 23:59:59',
],
'monthly' => [
AutomatedReportsService::FREQUENCY_MONTHLY,
'2025-05-01 00:00:00',
'2025-05-31 23:59:59',
],
'quarterly' => [
AutomatedReportsService::FREQUENCY_QUARTERLY,
'2025-01-01 00:00:00',
'2025-03-31 23:59:59',
],
];
}
/**
* @dataProvider frequencyDateRangeProvider
*/
public function testGetActivityIdsInjectsDateRangeForFrequency(
string $frequency,
string $expectedStartDate,
string $expectedEndDate,
): void {
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);
$this->assertNotNull($capturedCriteria);
$this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void
{
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');
$savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);
$this->assertNotNull($capturedCriteria);
$this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
10
12
2
4
Previous Highlighted Error
Next Highlighted Error
SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o
JOIN activities a ON o.id = a.opportunity_id
WHERE a.crm_configuration_id = 39
AND a.actual_start_time > '2025-10-13'
AND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM activities
WHERE crm_configuration_id = 39 and user_id = 143
and actual_start_time >= '2025-10-13'
AND type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM opportunities WHERE account_id IN (178);
select * from activities where id IN (620137, 620187, 620188, 620189, 620230);
# HS
SELECT * FROM opportunities WHERE id IN (238);
select * from activities where id IN (477,2076);
select * from users;
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM activities;
SELECT COUNT(*) FROM opportunities;
UPDATE activities
SET
actual_start_time = '2025-12-19 09:00:00',
actual_end_time = '2025-12-19 10:30:00',
scheduled_start_time = '2025-12-19 09:00:00',
scheduled_end_time = '2025-12-19 10:30:00'
WHERE id IN (407509,407375);
select * from partners;
SELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id
FROM activities
WHERE user_id = 143
AND actual_start_time >= '2025-10-13 00:00:00'
AND actual_start_time <= '2026-01-13 23:59:59'
ORDER BY actual_start_time DESC;
SELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;
SELECT * FROM crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;
# lead_id
# account_id 177
# contact_id 3969
# opportunity_id
# stage_id 203
SELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;
SELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'
AND user_id = 143 and actual_start_time >= '2025-10-13';
SELECT * FROM activities a
# JOIN opportunities o ON a.opportunity_id = o.id
WHERE a.crm_configuration_id = 39 AND a.type = 'conference'
and status = 'completed' and recording_state = 'recorded'
and a.actual_start_time >= '2025-10-13'
AND a.user_id = 143
;
select * from leads
where crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310);
SELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198
SELECT * FROM activities WHERE id IN (356001, 356008); # contacts:
SELECT * FROM opportunities WHERE id IN (1707);
SELECT * FROM stages where id IN (204, 198);
SELECT * FROM opportunities WHERE account_id IN (178);
SELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';
SELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal
SELECT * FROM activities where crm_configuration_id = 39
AND opportunity_id IS NULL
AND is_internal = false
and status = 'completed' and recording_state = 'recorded'
AND actual_start_time >= '2025-10-13'
AND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)
# AND lead_id IN (112, 109)
;
SELECT * FROM crm_profiles WHERE user_id = 143;
select * from inboxes; # 212
select * from users where id = 143; # 143
select * from inbox_email_batches where inbox_id = 212
and updated_at >= '2026-01-28 00:00:00' order by id desc;
select * from inbox_emails where inbox_id = 212
and batch_id = 95885 order by id desc;
select * from email_messages where origin_user_id = 143;
select * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';
select * from participants where activity_id = 620247;
select * from crm_profiles where user_id = 143;
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001
select * from transcription where activity_id = 356001; # 6943
select * from ai_prompts where transcription_id = 6943;
SELECT * FROM activity_summary_logs where activity_id = 356001;
SELECT * FROM social_accounts WHERE sociable_id = 143;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;
# 422515 softphone tr. 8100
SELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;
# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS
select * from ai_prompts where transcription_id IN (8100, 7670);
select * from activity_summary_logs where activity_id = 407509;
select * from sidekick_settings;
select * from default_activity_types;
SELECT * FROM contacts WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM leads WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM activity_searches where user_id = 143;
SELECT * FROM groups where team_id = 1;
select * from teams where id = 1;
select * from groups where team_id = 1; # 1150 - 7e75f8025c22
select id, name, group_id, status, deleted_at, email
from users where team_id = 1 order by group_id desc ;
select * from activity_searches where id in (1977, 1978, 1979);
select * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);
select * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277
select * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879
INSERT INTO `activity_search_filters`
(`activity_search_id`, `filter`, `value`) VALUES
(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')
;
select * from crm_configurations where id = 39;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from features;
SELECT * FROM activity_searches where id = 1982; # 1981
SELECT * FROM activity_search_filters WHERE activity_search_id = 1982;
SELECT * FROM automated_reports where id = 68;
SELECT * FROM automated_report_results where id = 275;
SELECT * FROM automated_reports order by id desc;
SELECT * FROM automated_report_results order by id desc;
select * from activity_searches where user_id = 143;
select * from ask_anything_prompts;
SELECT * FROM groups WHERE id = 1439;
SELECT * FROM users WHERE group_id = 1439;
select * from permissions; # 158
select * from roles;
select * from permission_role
select * from teams where id = 1;
select * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;
select * from groups where id = 28;
select * from playbooks where team_id = 1;
select * from playbooks where id = 179;
select * from playbook_categories where id = 1391;
select * from users where id = 143;
select * from crm_profiles where user_id = 143;
select * from activities where crm_configuration_id = 39 and type = 'conference'
and crm_provider_id IS NOT NULL ORDER by id desc;
select * from activities where id = 422003; # 00UO400000pB6fpMAC
SELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type
FROM automated_report_results ar
JOIN automated_reports a ON a.id = ar.report_id
WHERE a.type = 'ask_jiminny'
LIMIT 10;
select * from teams where id = 3143;
select * from crm_configurations where id = 500;
select * from users where name = 'Integration Account'; # 1695
SELECT * FROM social_accounts WHERE sociable_id = 1695;
select * from activities where crm_configuration_id = 39
and recording_state = 'recorded' and duration > 60
and status = 'completed' and actual_start_time >= '2025-12-01'
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11894 on JY-18909-automated-reports-ask-jiminny, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #11894 exists for current branch JY-18909-automated-reports-ask-jiminny","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.006981383,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Services\\Kiosk\\AutomatedReports;\n\nuse Carbon\\CarbonImmutable;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityActualDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityUpdatedDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\DealInsights\\ClosingPeriodFilter;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionCollection;\nuse Jiminny\\Component\\ActivitySearch\\Service\\ActivitySearch;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\Activity\\SearchFilter;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\ElasticActivityRepository;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AskJiminnyReportActivityService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\VO\\Repository\\OnDemandActivitySearch\\Criteria;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\n\nclass AskJiminnyReportActivityServiceTest extends TestCase\n{\n private ActivitySearch&MockObject $activitySearch;\n private ElasticActivityRepository&MockObject $elasticRepository;\n private LoggerInterface&MockObject $logger;\n private AskJiminnyReportActivityService $service;\n\n protected function setUp(): void\n {\n $this->activitySearch = $this->createMock(ActivitySearch::class);\n $this->elasticRepository = $this->createMock(ElasticActivityRepository::class);\n $this->logger = $this->createMock(LoggerInterface::class);\n\n $this->service = new AskJiminnyReportActivityService(\n $this->activitySearch,\n $this->elasticRepository,\n $this->logger,\n );\n }\n\n private function makeFilter(string $key, ?string $value): SearchFilter&MockObject\n {\n $filter = $this->createMock(SearchFilter::class);\n $filter->method('getFilterProperty')->willReturn($key);\n $filter->method('getFilterValue')->willReturn($value);\n\n return $filter;\n }\n\n private function makeUser(): User&MockObject\n {\n $tz = new \\DateTimeZone('UTC');\n $user = $this->createMock(User::class);\n $user->method('getTimezone')->willReturn($tz);\n $user->method('getId')->willReturn(1);\n $user->method('getUuid')->willReturn('user-uuid');\n\n return $user;\n }\n\n private function makeSavedSearch(array $filters): Search&MockObject\n {\n $savedSearch = $this->createMock(Search::class);\n $savedSearch->method('getId')->willReturn(42);\n $savedSearch->method('getFilters')->willReturn(new \\Illuminate\\Support\\LazyCollection($filters));\n\n return $savedSearch;\n }\n\n public function testGetActivityIdsForSavedSearchReturnsIds(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->expects($this->once())\n ->method('getArrayFilterKeys')\n ->with($user)\n ->willReturn([]);\n\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n\n $this->elasticRepository->expects($this->once())\n ->method('onDemandSearchIdsOnly')\n ->willReturn(['id-1', 'id-2', 'id-3']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[AskJiminnyReport] Fetched activity IDs for saved search');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1', 'id-2', 'id-3'], $result);\n }\n\n public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $this->logger->expects($this->once())->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEmpty($result);\n }\n\n public function testGetActivityIdsFiltersOutDateFilters(): void\n {\n $user = $this->makeUser();\n\n $nonDateFilter = $this->makeFilter('owner_id', '123');\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');\n $updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');\n $updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');\n\n $savedSearch = $this->makeSavedSearch([\n $nonDateFilter,\n $startDateFilter,\n $endDateFilter,\n $updatedFromFilter,\n $updatedToFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n }\n\n public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void\n {\n $user = $this->makeUser();\n\n $closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');\n $closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');\n $regularFilter = $this->makeFilter('rep_id', '99');\n\n $savedSearch = $this->makeSavedSearch([\n $closingStartFilter,\n $closingEndFilter,\n $regularFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesArrayFilters(): void\n {\n $user = $this->makeUser();\n\n $filter1 = $this->makeFilter('outcome', 'positive');\n $filter2 = $this->makeFilter('outcome', 'negative');\n\n $savedSearch = $this->makeSavedSearch([$filter1, $filter2]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesScalarFilters(): void\n {\n $user = $this->makeUser();\n\n $filter = $this->makeFilter('direction', 'inbound');\n $savedSearch = $this->makeSavedSearch([$filter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-5'], $result);\n }\n\n public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertFalse($capturedCriteria->isFirstRequest());\n }\n\n public function testGetActivityIdsLogsWithCorrectContext(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with(\n '[AskJiminnyReport] Fetched activity IDs for saved search',\n $this->callback(fn ($context) => $context['saved_search_id'] === 42\n && $context['user_id'] === 1\n && $context['activity_count'] === 2)\n );\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n }\n\n public static function frequencyDateRangeProvider(): array\n {\n return [\n 'daily' => [\n AutomatedReportsService::FREQUENCY_DAILY,\n '2025-06-15 00:00:00',\n '2025-06-15 23:59:59',\n ],\n 'weekly' => [\n AutomatedReportsService::FREQUENCY_WEEKLY,\n '2025-06-09 00:00:00',\n '2025-06-15 23:59:59',\n ],\n 'monthly' => [\n AutomatedReportsService::FREQUENCY_MONTHLY,\n '2025-05-01 00:00:00',\n '2025-05-31 23:59:59',\n ],\n 'quarterly' => [\n AutomatedReportsService::FREQUENCY_QUARTERLY,\n '2025-01-01 00:00:00',\n '2025-03-31 23:59:59',\n ],\n ];\n }\n\n /**\n * @dataProvider frequencyDateRangeProvider\n */\n public function testGetActivityIdsInjectsDateRangeForFrequency(\n string $frequency,\n string $expectedStartDate,\n string $expectedEndDate,\n ): void {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n\n public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void\n {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');\n $savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n}","depth":4,"bounds":{"left":0.13863032,"top":0.27055067,"width":0.34375,"height":0.72944933},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Services\\Kiosk\\AutomatedReports;\n\nuse Carbon\\CarbonImmutable;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityActualDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityUpdatedDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\DealInsights\\ClosingPeriodFilter;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionCollection;\nuse Jiminny\\Component\\ActivitySearch\\Service\\ActivitySearch;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\Activity\\SearchFilter;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\ElasticActivityRepository;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AskJiminnyReportActivityService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\VO\\Repository\\OnDemandActivitySearch\\Criteria;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\n\nclass AskJiminnyReportActivityServiceTest extends TestCase\n{\n private ActivitySearch&MockObject $activitySearch;\n private ElasticActivityRepository&MockObject $elasticRepository;\n private LoggerInterface&MockObject $logger;\n private AskJiminnyReportActivityService $service;\n\n protected function setUp(): void\n {\n $this->activitySearch = $this->createMock(ActivitySearch::class);\n $this->elasticRepository = $this->createMock(ElasticActivityRepository::class);\n $this->logger = $this->createMock(LoggerInterface::class);\n\n $this->service = new AskJiminnyReportActivityService(\n $this->activitySearch,\n $this->elasticRepository,\n $this->logger,\n );\n }\n\n private function makeFilter(string $key, ?string $value): SearchFilter&MockObject\n {\n $filter = $this->createMock(SearchFilter::class);\n $filter->method('getFilterProperty')->willReturn($key);\n $filter->method('getFilterValue')->willReturn($value);\n\n return $filter;\n }\n\n private function makeUser(): User&MockObject\n {\n $tz = new \\DateTimeZone('UTC');\n $user = $this->createMock(User::class);\n $user->method('getTimezone')->willReturn($tz);\n $user->method('getId')->willReturn(1);\n $user->method('getUuid')->willReturn('user-uuid');\n\n return $user;\n }\n\n private function makeSavedSearch(array $filters): Search&MockObject\n {\n $savedSearch = $this->createMock(Search::class);\n $savedSearch->method('getId')->willReturn(42);\n $savedSearch->method('getFilters')->willReturn(new \\Illuminate\\Support\\LazyCollection($filters));\n\n return $savedSearch;\n }\n\n public function testGetActivityIdsForSavedSearchReturnsIds(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->expects($this->once())\n ->method('getArrayFilterKeys')\n ->with($user)\n ->willReturn([]);\n\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n\n $this->elasticRepository->expects($this->once())\n ->method('onDemandSearchIdsOnly')\n ->willReturn(['id-1', 'id-2', 'id-3']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[AskJiminnyReport] Fetched activity IDs for saved search');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1', 'id-2', 'id-3'], $result);\n }\n\n public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $this->logger->expects($this->once())->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEmpty($result);\n }\n\n public function testGetActivityIdsFiltersOutDateFilters(): void\n {\n $user = $this->makeUser();\n\n $nonDateFilter = $this->makeFilter('owner_id', '123');\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');\n $updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');\n $updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');\n\n $savedSearch = $this->makeSavedSearch([\n $nonDateFilter,\n $startDateFilter,\n $endDateFilter,\n $updatedFromFilter,\n $updatedToFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n }\n\n public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void\n {\n $user = $this->makeUser();\n\n $closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');\n $closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');\n $regularFilter = $this->makeFilter('rep_id', '99');\n\n $savedSearch = $this->makeSavedSearch([\n $closingStartFilter,\n $closingEndFilter,\n $regularFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesArrayFilters(): void\n {\n $user = $this->makeUser();\n\n $filter1 = $this->makeFilter('outcome', 'positive');\n $filter2 = $this->makeFilter('outcome', 'negative');\n\n $savedSearch = $this->makeSavedSearch([$filter1, $filter2]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesScalarFilters(): void\n {\n $user = $this->makeUser();\n\n $filter = $this->makeFilter('direction', 'inbound');\n $savedSearch = $this->makeSavedSearch([$filter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-5'], $result);\n }\n\n public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertFalse($capturedCriteria->isFirstRequest());\n }\n\n public function testGetActivityIdsLogsWithCorrectContext(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with(\n '[AskJiminnyReport] Fetched activity IDs for saved search',\n $this->callback(fn ($context) => $context['saved_search_id'] === 42\n && $context['user_id'] === 1\n && $context['activity_count'] === 2)\n );\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n }\n\n public static function frequencyDateRangeProvider(): array\n {\n return [\n 'daily' => [\n AutomatedReportsService::FREQUENCY_DAILY,\n '2025-06-15 00:00:00',\n '2025-06-15 23:59:59',\n ],\n 'weekly' => [\n AutomatedReportsService::FREQUENCY_WEEKLY,\n '2025-06-09 00:00:00',\n '2025-06-15 23:59:59',\n ],\n 'monthly' => [\n AutomatedReportsService::FREQUENCY_MONTHLY,\n '2025-05-01 00:00:00',\n '2025-05-31 23:59:59',\n ],\n 'quarterly' => [\n AutomatedReportsService::FREQUENCY_QUARTERLY,\n '2025-01-01 00:00:00',\n '2025-03-31 23:59:59',\n ],\n ];\n }\n\n /**\n * @dataProvider frequencyDateRangeProvider\n */\n public function testGetActivityIdsInjectsDateRangeForFrequency(\n string $frequency,\n string $expectedStartDate,\n string $expectedEndDate,\n ): void {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n\n public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void\n {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');\n $savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"bounds":{"left":0.40492022,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"bounds":{"left":0.41356382,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"bounds":{"left":0.4245346,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"bounds":{"left":0.4331782,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"bounds":{"left":0.4418218,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"bounds":{"left":0.45279256,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"bounds":{"left":0.4637633,"top":0.09896249,"width":0.024268618,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"bounds":{"left":0.49035904,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"bounds":{"left":0.5013298,"top":0.09896249,"width":0.029587766,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"bounds":{"left":0.69913566,"top":0.09896249,"width":0.02825798,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"10","depth":4,"bounds":{"left":0.6715425,"top":0.123703115,"width":0.009640957,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"12","depth":4,"bounds":{"left":0.6831782,"top":0.123703115,"width":0.009640957,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.69481385,"top":0.123703115,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"bounds":{"left":0.70478725,"top":0.123703115,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7144282,"top":0.12210695,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.72174203,"top":0.12210695,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o\nJOIN activities a ON o.id = a.opportunity_id\nWHERE a.crm_configuration_id = 39\nAND a.actual_start_time > '2025-10-13'\nAND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 39 and user_id = 143\nand actual_start_time >= '2025-10-13'\nAND type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM opportunities WHERE account_id IN (178);\nselect * from activities where id IN (620137, 620187, 620188, 620189, 620230);\n\n# HS\nSELECT * FROM opportunities WHERE id IN (238);\nselect * from activities where id IN (477,2076);\n\nselect * from users;\n\nSELECT COUNT(*) FROM users;\nSELECT COUNT(*) FROM activities;\nSELECT COUNT(*) FROM opportunities;\n\nUPDATE activities\nSET\n actual_start_time = '2025-12-19 09:00:00',\n actual_end_time = '2025-12-19 10:30:00',\n scheduled_start_time = '2025-12-19 09:00:00',\n scheduled_end_time = '2025-12-19 10:30:00'\nWHERE id IN (407509,407375);\n\nselect * from partners;\n\nSELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id\nFROM activities\nWHERE user_id = 143\nAND actual_start_time >= '2025-10-13 00:00:00'\nAND actual_start_time <= '2026-01-13 23:59:59'\nORDER BY actual_start_time DESC;\n\nSELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;\nSELECT * FROM crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;\n# lead_id\n# account_id 177\n# contact_id 3969\n# opportunity_id\n# stage_id 203\n\nSELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;\n\nSELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'\nAND user_id = 143 and actual_start_time >= '2025-10-13';\n\nSELECT * FROM activities a\n# JOIN opportunities o ON a.opportunity_id = o.id\nWHERE a.crm_configuration_id = 39 AND a.type = 'conference'\nand status = 'completed' and recording_state = 'recorded'\nand a.actual_start_time >= '2025-10-13'\nAND a.user_id = 143\n;\n\nselect * from leads\nwhere crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707\n\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310);\nSELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198\nSELECT * FROM activities WHERE id IN (356001, 356008); # contacts:\n\nSELECT * FROM opportunities WHERE id IN (1707);\nSELECT * FROM stages where id IN (204, 198);\nSELECT * FROM opportunities WHERE account_id IN (178);\nSELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';\nSELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal\n\nSELECT * FROM activities where crm_configuration_id = 39\nAND opportunity_id IS NULL\nAND is_internal = false\nand status = 'completed' and recording_state = 'recorded'\nAND actual_start_time >= '2025-10-13'\nAND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)\n# AND lead_id IN (112, 109)\n;\n\nSELECT * FROM crm_profiles WHERE user_id = 143;\n\nselect * from inboxes; # 212\nselect * from users where id = 143; # 143\nselect * from inbox_email_batches where inbox_id = 212\nand updated_at >= '2026-01-28 00:00:00' order by id desc;\nselect * from inbox_emails where inbox_id = 212\nand batch_id = 95885 order by id desc;\nselect * from email_messages where origin_user_id = 143;\nselect * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';\nselect * from participants where activity_id = 620247;\n\nselect * from crm_profiles where user_id = 143;\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001\nselect * from transcription where activity_id = 356001; # 6943\nselect * from ai_prompts where transcription_id = 6943;\nSELECT * FROM activity_summary_logs where activity_id = 356001;\n\nSELECT * FROM social_accounts WHERE sociable_id = 143;\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;\n# 422515 softphone tr. 8100\n\nSELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;\n# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS\n\nselect * from ai_prompts where transcription_id IN (8100, 7670);\nselect * from activity_summary_logs where activity_id = 407509;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nSELECT * FROM contacts WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\nSELECT * FROM leads WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\n\nSELECT * FROM activity_searches where user_id = 143;\nSELECT * FROM groups where team_id = 1;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1; # 1150 - 7e75f8025c22\nselect id, name, group_id, status, deleted_at, email\nfrom users where team_id = 1 order by group_id desc ;\n\nselect * from activity_searches where id in (1977, 1978, 1979);\nselect * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);\nselect * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277\nselect * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879\n\nINSERT INTO `activity_search_filters`\n(`activity_search_id`, `filter`, `value`) VALUES\n(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')\n;\n\nselect * from crm_configurations where id = 39;\n\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\nselect * from features;\n\nSELECT * FROM activity_searches where id = 1982; # 1981\nSELECT * FROM activity_search_filters WHERE activity_search_id = 1982;\n\nSELECT * FROM automated_reports where id = 68;\nSELECT * FROM automated_report_results where id = 275;\n\nSELECT * FROM automated_reports order by id desc;\nSELECT * FROM automated_report_results order by id desc;\nselect * from activity_searches where user_id = 143;\nselect * from ask_anything_prompts;\n\nSELECT * FROM groups WHERE id = 1439;\nSELECT * FROM users WHERE group_id = 1439;\n\nselect * from permissions; # 158\nselect * from roles;\nselect * from permission_role\n\nselect * from teams where id = 1;\nselect * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;\nselect * from groups where id = 28;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 179;\nselect * from playbook_categories where id = 1391;\nselect * from users where id = 143;\nselect * from crm_profiles where user_id = 143;\nselect * from activities where crm_configuration_id = 39 and type = 'conference'\nand crm_provider_id IS NOT NULL ORDER by id desc;\nselect * from activities where id = 422003; # 00UO400000pB6fpMAC\n\nSELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type\nFROM automated_report_results ar\nJOIN automated_reports a ON a.id = ar.report_id\nWHERE a.type = 'ask_jiminny'\nLIMIT 10;\n\n\nselect * from teams where id = 3143;\nselect * from crm_configurations where id = 500;\nselect * from users where name = 'Integration Account'; # 1695\nSELECT * FROM social_accounts WHERE sociable_id = 1695;\n\nselect * from activities where crm_configuration_id = 39\nand recording_state = 'recorded' and duration > 60\nand status = 'completed' and actual_start_time >= '2025-12-01'\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid;","depth":4,"value":"SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o\nJOIN activities a ON o.id = a.opportunity_id\nWHERE a.crm_configuration_id = 39\nAND a.actual_start_time > '2025-10-13'\nAND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 39 and user_id = 143\nand actual_start_time >= '2025-10-13'\nAND type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM opportunities WHERE account_id IN (178);\nselect * from activities where id IN (620137, 620187, 620188, 620189, 620230);\n\n# HS\nSELECT * FROM opportunities WHERE id IN (238);\nselect * from activities where id IN (477,2076);\n\nselect * from users;\n\nSELECT COUNT(*) FROM users;\nSELECT COUNT(*) FROM activities;\nSELECT COUNT(*) FROM opportunities;\n\nUPDATE activities\nSET\n actual_start_time = '2025-12-19 09:00:00',\n actual_end_time = '2025-12-19 10:30:00',\n scheduled_start_time = '2025-12-19 09:00:00',\n scheduled_end_time = '2025-12-19 10:30:00'\nWHERE id IN (407509,407375);\n\nselect * from partners;\n\nSELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id\nFROM activities\nWHERE user_id = 143\nAND actual_start_time >= '2025-10-13 00:00:00'\nAND actual_start_time <= '2026-01-13 23:59:59'\nORDER BY actual_start_time DESC;\n\nSELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;\nSELECT * FROM crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;\n# lead_id\n# account_id 177\n# contact_id 3969\n# opportunity_id\n# stage_id 203\n\nSELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;\n\nSELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'\nAND user_id = 143 and actual_start_time >= '2025-10-13';\n\nSELECT * FROM activities a\n# JOIN opportunities o ON a.opportunity_id = o.id\nWHERE a.crm_configuration_id = 39 AND a.type = 'conference'\nand status = 'completed' and recording_state = 'recorded'\nand a.actual_start_time >= '2025-10-13'\nAND a.user_id = 143\n;\n\nselect * from leads\nwhere crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707\n\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310);\nSELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198\nSELECT * FROM activities WHERE id IN (356001, 356008); # contacts:\n\nSELECT * FROM opportunities WHERE id IN (1707);\nSELECT * FROM stages where id IN (204, 198);\nSELECT * FROM opportunities WHERE account_id IN (178);\nSELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';\nSELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal\n\nSELECT * FROM activities where crm_configuration_id = 39\nAND opportunity_id IS NULL\nAND is_internal = false\nand status = 'completed' and recording_state = 'recorded'\nAND actual_start_time >= '2025-10-13'\nAND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)\n# AND lead_id IN (112, 109)\n;\n\nSELECT * FROM crm_profiles WHERE user_id = 143;\n\nselect * from inboxes; # 212\nselect * from users where id = 143; # 143\nselect * from inbox_email_batches where inbox_id = 212\nand updated_at >= '2026-01-28 00:00:00' order by id desc;\nselect * from inbox_emails where inbox_id = 212\nand batch_id = 95885 order by id desc;\nselect * from email_messages where origin_user_id = 143;\nselect * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';\nselect * from participants where activity_id = 620247;\n\nselect * from crm_profiles where user_id = 143;\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001\nselect * from transcription where activity_id = 356001; # 6943\nselect * from ai_prompts where transcription_id = 6943;\nSELECT * FROM activity_summary_logs where activity_id = 356001;\n\nSELECT * FROM social_accounts WHERE sociable_id = 143;\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;\n# 422515 softphone tr. 8100\n\nSELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;\n# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS\n\nselect * from ai_prompts where transcription_id IN (8100, 7670);\nselect * from activity_summary_logs where activity_id = 407509;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nSELECT * FROM contacts WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\nSELECT * FROM leads WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\n\nSELECT * FROM activity_searches where user_id = 143;\nSELECT * FROM groups where team_id = 1;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1; # 1150 - 7e75f8025c22\nselect id, name, group_id, status, deleted_at, email\nfrom users where team_id = 1 order by group_id desc ;\n\nselect * from activity_searches where id in (1977, 1978, 1979);\nselect * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);\nselect * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277\nselect * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879\n\nINSERT INTO `activity_search_filters`\n(`activity_search_id`, `filter`, `value`) VALUES\n(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')\n;\n\nselect * from crm_configurations where id = 39;\n\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\nselect * from features;\n\nSELECT * FROM activity_searches where id = 1982; # 1981\nSELECT * FROM activity_search_filters WHERE activity_search_id = 1982;\n\nSELECT * FROM automated_reports where id = 68;\nSELECT * FROM automated_report_results where id = 275;\n\nSELECT * FROM automated_reports order by id desc;\nSELECT * FROM automated_report_results order by id desc;\nselect * from activity_searches where user_id = 143;\nselect * from ask_anything_prompts;\n\nSELECT * FROM groups WHERE id = 1439;\nSELECT * FROM users WHERE group_id = 1439;\n\nselect * from permissions; # 158\nselect * from roles;\nselect * from permission_role\n\nselect * from teams where id = 1;\nselect * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;\nselect * from groups where id = 28;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 179;\nselect * from playbook_categories where id = 1391;\nselect * from users where id = 143;\nselect * from crm_profiles where user_id = 143;\nselect * from activities where crm_configuration_id = 39 and type = 'conference'\nand crm_provider_id IS NOT NULL ORDER by id desc;\nselect * from activities where id = 422003; # 00UO400000pB6fpMAC\n\nSELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type\nFROM automated_report_results ar\nJOIN automated_reports a ON a.id = ar.report_id\nWHERE a.type = 'ask_jiminny'\nLIMIT 10;\n\n\nselect * from teams where id = 3143;\nselect * from crm_configurations where id = 500;\nselect * from users where name = 'Integration Account'; # 1695\nSELECT * FROM social_accounts WHERE sociable_id = 1695;\n\nselect * from activities where crm_configuration_id = 39\nand recording_state = 'recorded' and duration > 60\nand status = 'completed' and actual_start_time >= '2025-12-01'\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid;","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
8870240212666235116
|
2146703058527524421
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Services\Kiosk\AutomatedReports;
use Carbon\CarbonImmutable;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityActualDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityUpdatedDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\DealInsights\ClosingPeriodFilter;
use Jiminny\Component\ActivitySearch\FilterDefinitionCollection;
use Jiminny\Component\ActivitySearch\Service\ActivitySearch;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\Activity\SearchFilter;
use Jiminny\Models\User;
use Jiminny\Repositories\ElasticActivityRepository;
use Jiminny\Services\Kiosk\AutomatedReports\AskJiminnyReportActivityService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\VO\Repository\OnDemandActivitySearch\Criteria;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
class AskJiminnyReportActivityServiceTest extends TestCase
{
private ActivitySearch&MockObject $activitySearch;
private ElasticActivityRepository&MockObject $elasticRepository;
private LoggerInterface&MockObject $logger;
private AskJiminnyReportActivityService $service;
protected function setUp(): void
{
$this->activitySearch = $this->createMock(ActivitySearch::class);
$this->elasticRepository = $this->createMock(ElasticActivityRepository::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->service = new AskJiminnyReportActivityService(
$this->activitySearch,
$this->elasticRepository,
$this->logger,
);
}
private function makeFilter(string $key, ?string $value): SearchFilter&MockObject
{
$filter = $this->createMock(SearchFilter::class);
$filter->method('getFilterProperty')->willReturn($key);
$filter->method('getFilterValue')->willReturn($value);
return $filter;
}
private function makeUser(): User&MockObject
{
$tz = new \DateTimeZone('UTC');
$user = $this->createMock(User::class);
$user->method('getTimezone')->willReturn($tz);
$user->method('getId')->willReturn(1);
$user->method('getUuid')->willReturn('user-uuid');
return $user;
}
private function makeSavedSearch(array $filters): Search&MockObject
{
$savedSearch = $this->createMock(Search::class);
$savedSearch->method('getId')->willReturn(42);
$savedSearch->method('getFilters')->willReturn(new \Illuminate\Support\LazyCollection($filters));
return $savedSearch;
}
public function testGetActivityIdsForSavedSearchReturnsIds(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->expects($this->once())
->method('getArrayFilterKeys')
->with($user)
->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->expects($this->once())
->method('onDemandSearchIdsOnly')
->willReturn(['id-1', 'id-2', 'id-3']);
$this->logger->expects($this->once())
->method('info')
->with('[AskJiminnyReport] Fetched activity IDs for saved search');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1', 'id-2', 'id-3'], $result);
}
public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->expects($this->once())->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEmpty($result);
}
public function testGetActivityIdsFiltersOutDateFilters(): void
{
$user = $this->makeUser();
$nonDateFilter = $this->makeFilter('owner_id', '123');
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');
$updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');
$updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');
$savedSearch = $this->makeSavedSearch([
$nonDateFilter,
$startDateFilter,
$endDateFilter,
$updatedFromFilter,
$updatedToFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
}
public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void
{
$user = $this->makeUser();
$closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');
$closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');
$regularFilter = $this->makeFilter('rep_id', '99');
$savedSearch = $this->makeSavedSearch([
$closingStartFilter,
$closingEndFilter,
$regularFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesArrayFilters(): void
{
$user = $this->makeUser();
$filter1 = $this->makeFilter('outcome', 'positive');
$filter2 = $this->makeFilter('outcome', 'negative');
$savedSearch = $this->makeSavedSearch([$filter1, $filter2]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesScalarFilters(): void
{
$user = $this->makeUser();
$filter = $this->makeFilter('direction', 'inbound');
$savedSearch = $this->makeSavedSearch([$filter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-5'], $result);
}
public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
$this->assertFalse($capturedCriteria->isFirstRequest());
}
public function testGetActivityIdsLogsWithCorrectContext(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);
$this->logger->expects($this->once())
->method('info')
->with(
'[AskJiminnyReport] Fetched activity IDs for saved search',
$this->callback(fn ($context) => $context['saved_search_id'] === 42
&& $context['user_id'] === 1
&& $context['activity_count'] === 2)
);
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
}
public static function frequencyDateRangeProvider(): array
{
return [
'daily' => [
AutomatedReportsService::FREQUENCY_DAILY,
'2025-06-15 00:00:00',
'2025-06-15 23:59:59',
],
'weekly' => [
AutomatedReportsService::FREQUENCY_WEEKLY,
'2025-06-09 00:00:00',
'2025-06-15 23:59:59',
],
'monthly' => [
AutomatedReportsService::FREQUENCY_MONTHLY,
'2025-05-01 00:00:00',
'2025-05-31 23:59:59',
],
'quarterly' => [
AutomatedReportsService::FREQUENCY_QUARTERLY,
'2025-01-01 00:00:00',
'2025-03-31 23:59:59',
],
];
}
/**
* @dataProvider frequencyDateRangeProvider
*/
public function testGetActivityIdsInjectsDateRangeForFrequency(
string $frequency,
string $expectedStartDate,
string $expectedEndDate,
): void {
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);
$this->assertNotNull($capturedCriteria);
$this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void
{
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');
$savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);
$this->assertNotNull($capturedCriteria);
$this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
10
12
2
4
Previous Highlighted Error
Next Highlighted Error
SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o
JOIN activities a ON o.id = a.opportunity_id
WHERE a.crm_configuration_id = 39
AND a.actual_start_time > '2025-10-13'
AND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM activities
WHERE crm_configuration_id = 39 and user_id = 143
and actual_start_time >= '2025-10-13'
AND type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM opportunities WHERE account_id IN (178);
select * from activities where id IN (620137, 620187, 620188, 620189, 620230);
# HS
SELECT * FROM opportunities WHERE id IN (238);
select * from activities where id IN (477,2076);
select * from users;
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM activities;
SELECT COUNT(*) FROM opportunities;
UPDATE activities
SET
actual_start_time = '2025-12-19 09:00:00',
actual_end_time = '2025-12-19 10:30:00',
scheduled_start_time = '2025-12-19 09:00:00',
scheduled_end_time = '2025-12-19 10:30:00'
WHERE id IN (407509,407375);
select * from partners;
SELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id
FROM activities
WHERE user_id = 143
AND actual_start_time >= '2025-10-13 00:00:00'
AND actual_start_time <= '2026-01-13 23:59:59'
ORDER BY actual_start_time DESC;
SELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;
SELECT * FROM crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;
# lead_id
# account_id 177
# contact_id 3969
# opportunity_id
# stage_id 203
SELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;
SELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'
AND user_id = 143 and actual_start_time >= '2025-10-13';
SELECT * FROM activities a
# JOIN opportunities o ON a.opportunity_id = o.id
WHERE a.crm_configuration_id = 39 AND a.type = 'conference'
and status = 'completed' and recording_state = 'recorded'
and a.actual_start_time >= '2025-10-13'
AND a.user_id = 143
;
select * from leads
where crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310);
SELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198
SELECT * FROM activities WHERE id IN (356001, 356008); # contacts:
SELECT * FROM opportunities WHERE id IN (1707);
SELECT * FROM stages where id IN (204, 198);
SELECT * FROM opportunities WHERE account_id IN (178);
SELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';
SELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal
SELECT * FROM activities where crm_configuration_id = 39
AND opportunity_id IS NULL
AND is_internal = false
and status = 'completed' and recording_state = 'recorded'
AND actual_start_time >= '2025-10-13'
AND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)
# AND lead_id IN (112, 109)
;
SELECT * FROM crm_profiles WHERE user_id = 143;
select * from inboxes; # 212
select * from users where id = 143; # 143
select * from inbox_email_batches where inbox_id = 212
and updated_at >= '2026-01-28 00:00:00' order by id desc;
select * from inbox_emails where inbox_id = 212
and batch_id = 95885 order by id desc;
select * from email_messages where origin_user_id = 143;
select * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';
select * from participants where activity_id = 620247;
select * from crm_profiles where user_id = 143;
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001
select * from transcription where activity_id = 356001; # 6943
select * from ai_prompts where transcription_id = 6943;
SELECT * FROM activity_summary_logs where activity_id = 356001;
SELECT * FROM social_accounts WHERE sociable_id = 143;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;
# 422515 softphone tr. 8100
SELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;
# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS
select * from ai_prompts where transcription_id IN (8100, 7670);
select * from activity_summary_logs where activity_id = 407509;
select * from sidekick_settings;
select * from default_activity_types;
SELECT * FROM contacts WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM leads WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM activity_searches where user_id = 143;
SELECT * FROM groups where team_id = 1;
select * from teams where id = 1;
select * from groups where team_id = 1; # 1150 - 7e75f8025c22
select id, name, group_id, status, deleted_at, email
from users where team_id = 1 order by group_id desc ;
select * from activity_searches where id in (1977, 1978, 1979);
select * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);
select * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277
select * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879
INSERT INTO `activity_search_filters`
(`activity_search_id`, `filter`, `value`) VALUES
(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')
;
select * from crm_configurations where id = 39;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from features;
SELECT * FROM activity_searches where id = 1982; # 1981
SELECT * FROM activity_search_filters WHERE activity_search_id = 1982;
SELECT * FROM automated_reports where id = 68;
SELECT * FROM automated_report_results where id = 275;
SELECT * FROM automated_reports order by id desc;
SELECT * FROM automated_report_results order by id desc;
select * from activity_searches where user_id = 143;
select * from ask_anything_prompts;
SELECT * FROM groups WHERE id = 1439;
SELECT * FROM users WHERE group_id = 1439;
select * from permissions; # 158
select * from roles;
select * from permission_role
select * from teams where id = 1;
select * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;
select * from groups where id = 28;
select * from playbooks where team_id = 1;
select * from playbooks where id = 179;
select * from playbook_categories where id = 1391;
select * from users where id = 143;
select * from crm_profiles where user_id = 143;
select * from activities where crm_configuration_id = 39 and type = 'conference'
and crm_provider_id IS NOT NULL ORDER by id desc;
select * from activities where id = 422003; # 00UO400000pB6fpMAC
SELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type
FROM automated_report_results ar
JOIN automated_reports a ON a.id = ar.report_id
WHERE a.type = 'ask_jiminny'
LIMIT 10;
select * from teams where id = 3143;
select * from crm_configurations where id = 500;
select * from users where name = 'Integration Account'; # 1695
SELECT * FROM social_accounts WHERE sociable_id = 1695;
select * from activities where crm_configuration_id = 39
and recording_state = 'recorded' and duration > 60
and status = 'completed' and actual_start_time >= '2025-12-01'
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
54727
|
|
54644
|
NULL
|
0
|
2026-04-20T09:12:02.176027+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776676322176_m2.jpg...
|
PhpStorm
|
faVsco.js – SF [jiminny@localhost]
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Services\Kiosk\AutomatedReports;
use Carbon\CarbonImmutable;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityActualDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityUpdatedDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\DealInsights\ClosingPeriodFilter;
use Jiminny\Component\ActivitySearch\FilterDefinitionCollection;
use Jiminny\Component\ActivitySearch\Service\ActivitySearch;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\Activity\SearchFilter;
use Jiminny\Models\User;
use Jiminny\Repositories\ElasticActivityRepository;
use Jiminny\Services\Kiosk\AutomatedReports\AskJiminnyReportActivityService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\VO\Repository\OnDemandActivitySearch\Criteria;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
class AskJiminnyReportActivityServiceTest extends TestCase
{
private ActivitySearch&MockObject $activitySearch;
private ElasticActivityRepository&MockObject $elasticRepository;
private LoggerInterface&MockObject $logger;
private AskJiminnyReportActivityService $service;
protected function setUp(): void
{
$this->activitySearch = $this->createMock(ActivitySearch::class);
$this->elasticRepository = $this->createMock(ElasticActivityRepository::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->service = new AskJiminnyReportActivityService(
$this->activitySearch,
$this->elasticRepository,
$this->logger,
);
}
private function makeFilter(string $key, ?string $value): SearchFilter&MockObject
{
$filter = $this->createMock(SearchFilter::class);
$filter->method('getFilterProperty')->willReturn($key);
$filter->method('getFilterValue')->willReturn($value);
return $filter;
}
private function makeUser(): User&MockObject
{
$tz = new \DateTimeZone('UTC');
$user = $this->createMock(User::class);
$user->method('getTimezone')->willReturn($tz);
$user->method('getId')->willReturn(1);
$user->method('getUuid')->willReturn('user-uuid');
return $user;
}
private function makeSavedSearch(array $filters): Search&MockObject
{
$savedSearch = $this->createMock(Search::class);
$savedSearch->method('getId')->willReturn(42);
$savedSearch->method('getFilters')->willReturn(new \Illuminate\Support\LazyCollection($filters));
return $savedSearch;
}
public function testGetActivityIdsForSavedSearchReturnsIds(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->expects($this->once())
->method('getArrayFilterKeys')
->with($user)
->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->expects($this->once())
->method('onDemandSearchIdsOnly')
->willReturn(['id-1', 'id-2', 'id-3']);
$this->logger->expects($this->once())
->method('info')
->with('[AskJiminnyReport] Fetched activity IDs for saved search');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1', 'id-2', 'id-3'], $result);
}
public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->expects($this->once())->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEmpty($result);
}
public function testGetActivityIdsFiltersOutDateFilters(): void
{
$user = $this->makeUser();
$nonDateFilter = $this->makeFilter('owner_id', '123');
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');
$updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');
$updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');
$savedSearch = $this->makeSavedSearch([
$nonDateFilter,
$startDateFilter,
$endDateFilter,
$updatedFromFilter,
$updatedToFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
}
public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void
{
$user = $this->makeUser();
$closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');
$closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');
$regularFilter = $this->makeFilter('rep_id', '99');
$savedSearch = $this->makeSavedSearch([
$closingStartFilter,
$closingEndFilter,
$regularFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesArrayFilters(): void
{
$user = $this->makeUser();
$filter1 = $this->makeFilter('outcome', 'positive');
$filter2 = $this->makeFilter('outcome', 'negative');
$savedSearch = $this->makeSavedSearch([$filter1, $filter2]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesScalarFilters(): void
{
$user = $this->makeUser();
$filter = $this->makeFilter('direction', 'inbound');
$savedSearch = $this->makeSavedSearch([$filter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-5'], $result);
}
public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
$this->assertFalse($capturedCriteria->isFirstRequest());
}
public function testGetActivityIdsLogsWithCorrectContext(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);
$this->logger->expects($this->once())
->method('info')
->with(
'[AskJiminnyReport] Fetched activity IDs for saved search',
$this->callback(fn ($context) => $context['saved_search_id'] === 42
&& $context['user_id'] === 1
&& $context['activity_count'] === 2)
);
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
}
public static function frequencyDateRangeProvider(): array
{
return [
'daily' => [
AutomatedReportsService::FREQUENCY_DAILY,
'2025-06-15 00:00:00',
'2025-06-15 23:59:59',
],
'weekly' => [
AutomatedReportsService::FREQUENCY_WEEKLY,
'2025-06-09 00:00:00',
'2025-06-15 23:59:59',
],
'monthly' => [
AutomatedReportsService::FREQUENCY_MONTHLY,
'2025-05-01 00:00:00',
'2025-05-31 23:59:59',
],
'quarterly' => [
AutomatedReportsService::FREQUENCY_QUARTERLY,
'2025-01-01 00:00:00',
'2025-03-31 23:59:59',
],
];
}
/**
* @dataProvider frequencyDateRangeProvider
*/
public function testGetActivityIdsInjectsDateRangeForFrequency(
string $frequency,
string $expectedStartDate,
string $expectedEndDate,
): void {
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);
$this->assertNotNull($capturedCriteria);
$this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void
{
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');
$savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);
$this->assertNotNull($capturedCriteria);
$this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
9
12
2
4
Previous Highlighted Error
Next Highlighted Error
SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o
JOIN activities a ON o.id = a.opportunity_id
WHERE a.crm_configuration_id = 39
AND a.actual_start_time > '2025-10-13'
AND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM activities
WHERE crm_configuration_id = 39 and user_id = 143
and actual_start_time >= '2025-10-13'
AND type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM opportunities WHERE account_id IN (178);
select * from activities where id IN (620137, 620187, 620188, 620189, 620230);
# HS
SELECT * FROM opportunities WHERE id IN (238);
select * from activities where id IN (477,2076);
select * from users;
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM activities;
SELECT COUNT(*) FROM opportunities;
UPDATE activities
SET
actual_start_time = '2025-12-19 09:00:00',
actual_end_time = '2025-12-19 10:30:00',
scheduled_start_time = '2025-12-19 09:00:00',
scheduled_end_time = '2025-12-19 10:30:00'
WHERE id IN (407509,407375);
select * from partners;
SELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id
FROM activities
WHERE user_id = 143
AND actual_start_time >= '2025-10-13 00:00:00'
AND actual_start_time <= '2026-01-13 23:59:59'
ORDER BY actual_start_time DESC;
SELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;
SELECT * FROM crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;
# lead_id
# account_id 177
# contact_id 3969
# opportunity_id
# stage_id 203
SELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;
SELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'
AND user_id = 143 and actual_start_time >= '2025-10-13';
SELECT * FROM activities a
# JOIN opportunities o ON a.opportunity_id = o.id
WHERE a.crm_configuration_id = 39 AND a.type = 'conference'
and status = 'completed' and recording_state = 'recorded'
and a.actual_start_time >= '2025-10-13'
AND a.user_id = 143
;
select * from leads
where crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310);
SELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198
SELECT * FROM activities WHERE id IN (356001, 356008); # contacts:
SELECT * FROM opportunities WHERE id IN (1707);
SELECT * FROM stages where id IN (204, 198);
SELECT * FROM opportunities WHERE account_id IN (178);
SELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';
SELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal
SELECT * FROM activities where crm_configuration_id = 39
AND opportunity_id IS NULL
AND is_internal = false
and status = 'completed' and recording_state = 'recorded'
AND actual_start_time >= '2025-10-13'
AND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)
# AND lead_id IN (112, 109)
;
SELECT * FROM crm_profiles WHERE user_id = 143;
select * from inboxes; # 212
select * from users where id = 143; # 143
select * from inbox_email_batches where inbox_id = 212
and updated_at >= '2026-01-28 00:00:00' order by id desc;
select * from inbox_emails where inbox_id = 212
and batch_id = 95885 order by id desc;
select * from email_messages where origin_user_id = 143;
select * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';
select * from participants where activity_id = 620247;
select * from crm_profiles where user_id = 143;
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001
select * from transcription where activity_id = 356001; # 6943
select * from ai_prompts where transcription_id = 6943;
SELECT * FROM activity_summary_logs where activity_id = 356001;
SELECT * FROM social_accounts WHERE sociable_id = 143;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;
# 422515 softphone tr. 8100
SELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;
# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS
select * from ai_prompts where transcription_id IN (8100, 7670);
select * from activity_summary_logs where activity_id = 407509;
select * from sidekick_settings;
select * from default_activity_types;
SELECT * FROM contacts WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM leads WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM activity_searches where user_id = 143;
SELECT * FROM groups where team_id = 1;
select * from teams where id = 1;
select * from groups where team_id = 1; # 1150 - 7e75f8025c22
select id, name, group_id, status, deleted_at, email
from users where team_id = 1 order by group_id desc ;
select * from activity_searches where id in (1977, 1978, 1979);
select * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);
select * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277
select * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879
INSERT INTO `activity_search_filters`
(`activity_search_id`, `filter`, `value`) VALUES
(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')
;
select * from crm_configurations where id = 39;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from features;
SELECT * FROM activity_searches where id = 1982; # 1981
SELECT * FROM activity_search_filters WHERE activity_search_id = 1982;
SELECT * FROM automated_reports where id = 68;
SELECT * FROM automated_report_results where id = 275;
SELECT * FROM automated_reports order by id desc;
SELECT * FROM automated_report_results order by id desc;
select * from activity_searches where user_id = 143;
select * from ask_anything_prompts;
SELECT * FROM groups WHERE id = 1439;
SELECT * FROM users WHERE group_id = 1439;
select * from permissions; # 158
select * from roles;
select * from permission_role
select * from teams where id = 1;
select * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;
select * from groups where id = 28;
select * from playbooks where team_id = 1;
select * from playbooks where id = 179;
select * from playbook_categories where id = 1391;
select * from users where id = 143;
select * from crm_profiles where user_id = 143;
select * from activities where crm_configuration_id = 39 and type = 'conference'
and crm_provider_id IS NOT NULL ORDER by id desc;
select * from activities where id = 422003; # 00UO400000pB6fpMAC
SELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type
FROM automated_report_results ar
JOIN automated_reports a ON a.id = ar.report_id
WHERE a.type = 'ask_jiminny'
LIMIT 10;
select * from teams where id = 3143;
select * from crm_configurations where id = 500;
select * from users where name = 'Integration Account'; # 1695
SELECT * FROM social_accounts WHERE sociable_id = 1695;
select * from activities where crm_configuration_id = 39
and status = 'completed' and actual_start_time >= '2025-01-01'
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11894 on JY-18909-automated-reports-ask-jiminny, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #11894 exists for current branch JY-18909-automated-reports-ask-jiminny","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.006981383,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Services\\Kiosk\\AutomatedReports;\n\nuse Carbon\\CarbonImmutable;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityActualDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityUpdatedDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\DealInsights\\ClosingPeriodFilter;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionCollection;\nuse Jiminny\\Component\\ActivitySearch\\Service\\ActivitySearch;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\Activity\\SearchFilter;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\ElasticActivityRepository;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AskJiminnyReportActivityService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\VO\\Repository\\OnDemandActivitySearch\\Criteria;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\n\nclass AskJiminnyReportActivityServiceTest extends TestCase\n{\n private ActivitySearch&MockObject $activitySearch;\n private ElasticActivityRepository&MockObject $elasticRepository;\n private LoggerInterface&MockObject $logger;\n private AskJiminnyReportActivityService $service;\n\n protected function setUp(): void\n {\n $this->activitySearch = $this->createMock(ActivitySearch::class);\n $this->elasticRepository = $this->createMock(ElasticActivityRepository::class);\n $this->logger = $this->createMock(LoggerInterface::class);\n\n $this->service = new AskJiminnyReportActivityService(\n $this->activitySearch,\n $this->elasticRepository,\n $this->logger,\n );\n }\n\n private function makeFilter(string $key, ?string $value): SearchFilter&MockObject\n {\n $filter = $this->createMock(SearchFilter::class);\n $filter->method('getFilterProperty')->willReturn($key);\n $filter->method('getFilterValue')->willReturn($value);\n\n return $filter;\n }\n\n private function makeUser(): User&MockObject\n {\n $tz = new \\DateTimeZone('UTC');\n $user = $this->createMock(User::class);\n $user->method('getTimezone')->willReturn($tz);\n $user->method('getId')->willReturn(1);\n $user->method('getUuid')->willReturn('user-uuid');\n\n return $user;\n }\n\n private function makeSavedSearch(array $filters): Search&MockObject\n {\n $savedSearch = $this->createMock(Search::class);\n $savedSearch->method('getId')->willReturn(42);\n $savedSearch->method('getFilters')->willReturn(new \\Illuminate\\Support\\LazyCollection($filters));\n\n return $savedSearch;\n }\n\n public function testGetActivityIdsForSavedSearchReturnsIds(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->expects($this->once())\n ->method('getArrayFilterKeys')\n ->with($user)\n ->willReturn([]);\n\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n\n $this->elasticRepository->expects($this->once())\n ->method('onDemandSearchIdsOnly')\n ->willReturn(['id-1', 'id-2', 'id-3']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[AskJiminnyReport] Fetched activity IDs for saved search');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1', 'id-2', 'id-3'], $result);\n }\n\n public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $this->logger->expects($this->once())->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEmpty($result);\n }\n\n public function testGetActivityIdsFiltersOutDateFilters(): void\n {\n $user = $this->makeUser();\n\n $nonDateFilter = $this->makeFilter('owner_id', '123');\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');\n $updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');\n $updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');\n\n $savedSearch = $this->makeSavedSearch([\n $nonDateFilter,\n $startDateFilter,\n $endDateFilter,\n $updatedFromFilter,\n $updatedToFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n }\n\n public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void\n {\n $user = $this->makeUser();\n\n $closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');\n $closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');\n $regularFilter = $this->makeFilter('rep_id', '99');\n\n $savedSearch = $this->makeSavedSearch([\n $closingStartFilter,\n $closingEndFilter,\n $regularFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesArrayFilters(): void\n {\n $user = $this->makeUser();\n\n $filter1 = $this->makeFilter('outcome', 'positive');\n $filter2 = $this->makeFilter('outcome', 'negative');\n\n $savedSearch = $this->makeSavedSearch([$filter1, $filter2]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesScalarFilters(): void\n {\n $user = $this->makeUser();\n\n $filter = $this->makeFilter('direction', 'inbound');\n $savedSearch = $this->makeSavedSearch([$filter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-5'], $result);\n }\n\n public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertFalse($capturedCriteria->isFirstRequest());\n }\n\n public function testGetActivityIdsLogsWithCorrectContext(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with(\n '[AskJiminnyReport] Fetched activity IDs for saved search',\n $this->callback(fn ($context) => $context['saved_search_id'] === 42\n && $context['user_id'] === 1\n && $context['activity_count'] === 2)\n );\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n }\n\n public static function frequencyDateRangeProvider(): array\n {\n return [\n 'daily' => [\n AutomatedReportsService::FREQUENCY_DAILY,\n '2025-06-15 00:00:00',\n '2025-06-15 23:59:59',\n ],\n 'weekly' => [\n AutomatedReportsService::FREQUENCY_WEEKLY,\n '2025-06-09 00:00:00',\n '2025-06-15 23:59:59',\n ],\n 'monthly' => [\n AutomatedReportsService::FREQUENCY_MONTHLY,\n '2025-05-01 00:00:00',\n '2025-05-31 23:59:59',\n ],\n 'quarterly' => [\n AutomatedReportsService::FREQUENCY_QUARTERLY,\n '2025-01-01 00:00:00',\n '2025-03-31 23:59:59',\n ],\n ];\n }\n\n /**\n * @dataProvider frequencyDateRangeProvider\n */\n public function testGetActivityIdsInjectsDateRangeForFrequency(\n string $frequency,\n string $expectedStartDate,\n string $expectedEndDate,\n ): void {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n\n public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void\n {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');\n $savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n}","depth":4,"bounds":{"left":0.13863032,"top":0.27055067,"width":0.34375,"height":0.72944933},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Services\\Kiosk\\AutomatedReports;\n\nuse Carbon\\CarbonImmutable;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityActualDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityUpdatedDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\DealInsights\\ClosingPeriodFilter;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionCollection;\nuse Jiminny\\Component\\ActivitySearch\\Service\\ActivitySearch;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\Activity\\SearchFilter;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\ElasticActivityRepository;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AskJiminnyReportActivityService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\VO\\Repository\\OnDemandActivitySearch\\Criteria;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\n\nclass AskJiminnyReportActivityServiceTest extends TestCase\n{\n private ActivitySearch&MockObject $activitySearch;\n private ElasticActivityRepository&MockObject $elasticRepository;\n private LoggerInterface&MockObject $logger;\n private AskJiminnyReportActivityService $service;\n\n protected function setUp(): void\n {\n $this->activitySearch = $this->createMock(ActivitySearch::class);\n $this->elasticRepository = $this->createMock(ElasticActivityRepository::class);\n $this->logger = $this->createMock(LoggerInterface::class);\n\n $this->service = new AskJiminnyReportActivityService(\n $this->activitySearch,\n $this->elasticRepository,\n $this->logger,\n );\n }\n\n private function makeFilter(string $key, ?string $value): SearchFilter&MockObject\n {\n $filter = $this->createMock(SearchFilter::class);\n $filter->method('getFilterProperty')->willReturn($key);\n $filter->method('getFilterValue')->willReturn($value);\n\n return $filter;\n }\n\n private function makeUser(): User&MockObject\n {\n $tz = new \\DateTimeZone('UTC');\n $user = $this->createMock(User::class);\n $user->method('getTimezone')->willReturn($tz);\n $user->method('getId')->willReturn(1);\n $user->method('getUuid')->willReturn('user-uuid');\n\n return $user;\n }\n\n private function makeSavedSearch(array $filters): Search&MockObject\n {\n $savedSearch = $this->createMock(Search::class);\n $savedSearch->method('getId')->willReturn(42);\n $savedSearch->method('getFilters')->willReturn(new \\Illuminate\\Support\\LazyCollection($filters));\n\n return $savedSearch;\n }\n\n public function testGetActivityIdsForSavedSearchReturnsIds(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->expects($this->once())\n ->method('getArrayFilterKeys')\n ->with($user)\n ->willReturn([]);\n\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n\n $this->elasticRepository->expects($this->once())\n ->method('onDemandSearchIdsOnly')\n ->willReturn(['id-1', 'id-2', 'id-3']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[AskJiminnyReport] Fetched activity IDs for saved search');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1', 'id-2', 'id-3'], $result);\n }\n\n public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $this->logger->expects($this->once())->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEmpty($result);\n }\n\n public function testGetActivityIdsFiltersOutDateFilters(): void\n {\n $user = $this->makeUser();\n\n $nonDateFilter = $this->makeFilter('owner_id', '123');\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');\n $updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');\n $updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');\n\n $savedSearch = $this->makeSavedSearch([\n $nonDateFilter,\n $startDateFilter,\n $endDateFilter,\n $updatedFromFilter,\n $updatedToFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n }\n\n public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void\n {\n $user = $this->makeUser();\n\n $closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');\n $closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');\n $regularFilter = $this->makeFilter('rep_id', '99');\n\n $savedSearch = $this->makeSavedSearch([\n $closingStartFilter,\n $closingEndFilter,\n $regularFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesArrayFilters(): void\n {\n $user = $this->makeUser();\n\n $filter1 = $this->makeFilter('outcome', 'positive');\n $filter2 = $this->makeFilter('outcome', 'negative');\n\n $savedSearch = $this->makeSavedSearch([$filter1, $filter2]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesScalarFilters(): void\n {\n $user = $this->makeUser();\n\n $filter = $this->makeFilter('direction', 'inbound');\n $savedSearch = $this->makeSavedSearch([$filter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-5'], $result);\n }\n\n public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertFalse($capturedCriteria->isFirstRequest());\n }\n\n public function testGetActivityIdsLogsWithCorrectContext(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with(\n '[AskJiminnyReport] Fetched activity IDs for saved search',\n $this->callback(fn ($context) => $context['saved_search_id'] === 42\n && $context['user_id'] === 1\n && $context['activity_count'] === 2)\n );\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n }\n\n public static function frequencyDateRangeProvider(): array\n {\n return [\n 'daily' => [\n AutomatedReportsService::FREQUENCY_DAILY,\n '2025-06-15 00:00:00',\n '2025-06-15 23:59:59',\n ],\n 'weekly' => [\n AutomatedReportsService::FREQUENCY_WEEKLY,\n '2025-06-09 00:00:00',\n '2025-06-15 23:59:59',\n ],\n 'monthly' => [\n AutomatedReportsService::FREQUENCY_MONTHLY,\n '2025-05-01 00:00:00',\n '2025-05-31 23:59:59',\n ],\n 'quarterly' => [\n AutomatedReportsService::FREQUENCY_QUARTERLY,\n '2025-01-01 00:00:00',\n '2025-03-31 23:59:59',\n ],\n ];\n }\n\n /**\n * @dataProvider frequencyDateRangeProvider\n */\n public function testGetActivityIdsInjectsDateRangeForFrequency(\n string $frequency,\n string $expectedStartDate,\n string $expectedEndDate,\n ): void {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n\n public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void\n {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');\n $savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"bounds":{"left":0.40492022,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"bounds":{"left":0.41356382,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"bounds":{"left":0.4245346,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"bounds":{"left":0.4331782,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"bounds":{"left":0.4418218,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"bounds":{"left":0.45279256,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"bounds":{"left":0.4637633,"top":0.09896249,"width":0.024268618,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"bounds":{"left":0.49035904,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"bounds":{"left":0.5013298,"top":0.09896249,"width":0.029587766,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"bounds":{"left":0.69913566,"top":0.09896249,"width":0.02825798,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.6732048,"top":0.123703115,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"12","depth":4,"bounds":{"left":0.6831782,"top":0.123703115,"width":0.009640957,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.69481385,"top":0.123703115,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"bounds":{"left":0.70478725,"top":0.123703115,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7144282,"top":0.12210695,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.72174203,"top":0.12210695,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o\nJOIN activities a ON o.id = a.opportunity_id\nWHERE a.crm_configuration_id = 39\nAND a.actual_start_time > '2025-10-13'\nAND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 39 and user_id = 143\nand actual_start_time >= '2025-10-13'\nAND type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM opportunities WHERE account_id IN (178);\nselect * from activities where id IN (620137, 620187, 620188, 620189, 620230);\n\n# HS\nSELECT * FROM opportunities WHERE id IN (238);\nselect * from activities where id IN (477,2076);\n\nselect * from users;\n\nSELECT COUNT(*) FROM users;\nSELECT COUNT(*) FROM activities;\nSELECT COUNT(*) FROM opportunities;\n\nUPDATE activities\nSET\n actual_start_time = '2025-12-19 09:00:00',\n actual_end_time = '2025-12-19 10:30:00',\n scheduled_start_time = '2025-12-19 09:00:00',\n scheduled_end_time = '2025-12-19 10:30:00'\nWHERE id IN (407509,407375);\n\nselect * from partners;\n\nSELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id\nFROM activities\nWHERE user_id = 143\nAND actual_start_time >= '2025-10-13 00:00:00'\nAND actual_start_time <= '2026-01-13 23:59:59'\nORDER BY actual_start_time DESC;\n\nSELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;\nSELECT * FROM crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;\n# lead_id\n# account_id 177\n# contact_id 3969\n# opportunity_id\n# stage_id 203\n\nSELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;\n\nSELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'\nAND user_id = 143 and actual_start_time >= '2025-10-13';\n\nSELECT * FROM activities a\n# JOIN opportunities o ON a.opportunity_id = o.id\nWHERE a.crm_configuration_id = 39 AND a.type = 'conference'\nand status = 'completed' and recording_state = 'recorded'\nand a.actual_start_time >= '2025-10-13'\nAND a.user_id = 143\n;\n\nselect * from leads\nwhere crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707\n\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310);\nSELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198\nSELECT * FROM activities WHERE id IN (356001, 356008); # contacts:\n\nSELECT * FROM opportunities WHERE id IN (1707);\nSELECT * FROM stages where id IN (204, 198);\nSELECT * FROM opportunities WHERE account_id IN (178);\nSELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';\nSELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal\n\nSELECT * FROM activities where crm_configuration_id = 39\nAND opportunity_id IS NULL\nAND is_internal = false\nand status = 'completed' and recording_state = 'recorded'\nAND actual_start_time >= '2025-10-13'\nAND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)\n# AND lead_id IN (112, 109)\n;\n\nSELECT * FROM crm_profiles WHERE user_id = 143;\n\nselect * from inboxes; # 212\nselect * from users where id = 143; # 143\nselect * from inbox_email_batches where inbox_id = 212\nand updated_at >= '2026-01-28 00:00:00' order by id desc;\nselect * from inbox_emails where inbox_id = 212\nand batch_id = 95885 order by id desc;\nselect * from email_messages where origin_user_id = 143;\nselect * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';\nselect * from participants where activity_id = 620247;\n\nselect * from crm_profiles where user_id = 143;\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001\nselect * from transcription where activity_id = 356001; # 6943\nselect * from ai_prompts where transcription_id = 6943;\nSELECT * FROM activity_summary_logs where activity_id = 356001;\n\nSELECT * FROM social_accounts WHERE sociable_id = 143;\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;\n# 422515 softphone tr. 8100\n\nSELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;\n# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS\n\nselect * from ai_prompts where transcription_id IN (8100, 7670);\nselect * from activity_summary_logs where activity_id = 407509;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nSELECT * FROM contacts WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\nSELECT * FROM leads WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\n\nSELECT * FROM activity_searches where user_id = 143;\nSELECT * FROM groups where team_id = 1;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1; # 1150 - 7e75f8025c22\nselect id, name, group_id, status, deleted_at, email\nfrom users where team_id = 1 order by group_id desc ;\n\nselect * from activity_searches where id in (1977, 1978, 1979);\nselect * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);\nselect * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277\nselect * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879\n\nINSERT INTO `activity_search_filters`\n(`activity_search_id`, `filter`, `value`) VALUES\n(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')\n;\n\nselect * from crm_configurations where id = 39;\n\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\nselect * from features;\n\nSELECT * FROM activity_searches where id = 1982; # 1981\nSELECT * FROM activity_search_filters WHERE activity_search_id = 1982;\n\nSELECT * FROM automated_reports where id = 68;\nSELECT * FROM automated_report_results where id = 275;\n\nSELECT * FROM automated_reports order by id desc;\nSELECT * FROM automated_report_results order by id desc;\nselect * from activity_searches where user_id = 143;\nselect * from ask_anything_prompts;\n\nSELECT * FROM groups WHERE id = 1439;\nSELECT * FROM users WHERE group_id = 1439;\n\nselect * from permissions; # 158\nselect * from roles;\nselect * from permission_role\n\nselect * from teams where id = 1;\nselect * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;\nselect * from groups where id = 28;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 179;\nselect * from playbook_categories where id = 1391;\nselect * from users where id = 143;\nselect * from crm_profiles where user_id = 143;\nselect * from activities where crm_configuration_id = 39 and type = 'conference'\nand crm_provider_id IS NOT NULL ORDER by id desc;\nselect * from activities where id = 422003; # 00UO400000pB6fpMAC\n\nSELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type\nFROM automated_report_results ar\nJOIN automated_reports a ON a.id = ar.report_id\nWHERE a.type = 'ask_jiminny'\nLIMIT 10;\n\n\nselect * from teams where id = 3143;\nselect * from crm_configurations where id = 500;\nselect * from users where name = 'Integration Account'; # 1695\nSELECT * FROM social_accounts WHERE sociable_id = 1695;\n\nselect * from activities where crm_configuration_id = 39\nand status = 'completed' and actual_start_time >= '2025-01-01'","depth":4,"value":"SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o\nJOIN activities a ON o.id = a.opportunity_id\nWHERE a.crm_configuration_id = 39\nAND a.actual_start_time > '2025-10-13'\nAND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 39 and user_id = 143\nand actual_start_time >= '2025-10-13'\nAND type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM opportunities WHERE account_id IN (178);\nselect * from activities where id IN (620137, 620187, 620188, 620189, 620230);\n\n# HS\nSELECT * FROM opportunities WHERE id IN (238);\nselect * from activities where id IN (477,2076);\n\nselect * from users;\n\nSELECT COUNT(*) FROM users;\nSELECT COUNT(*) FROM activities;\nSELECT COUNT(*) FROM opportunities;\n\nUPDATE activities\nSET\n actual_start_time = '2025-12-19 09:00:00',\n actual_end_time = '2025-12-19 10:30:00',\n scheduled_start_time = '2025-12-19 09:00:00',\n scheduled_end_time = '2025-12-19 10:30:00'\nWHERE id IN (407509,407375);\n\nselect * from partners;\n\nSELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id\nFROM activities\nWHERE user_id = 143\nAND actual_start_time >= '2025-10-13 00:00:00'\nAND actual_start_time <= '2026-01-13 23:59:59'\nORDER BY actual_start_time DESC;\n\nSELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;\nSELECT * FROM crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;\n# lead_id\n# account_id 177\n# contact_id 3969\n# opportunity_id\n# stage_id 203\n\nSELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;\n\nSELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'\nAND user_id = 143 and actual_start_time >= '2025-10-13';\n\nSELECT * FROM activities a\n# JOIN opportunities o ON a.opportunity_id = o.id\nWHERE a.crm_configuration_id = 39 AND a.type = 'conference'\nand status = 'completed' and recording_state = 'recorded'\nand a.actual_start_time >= '2025-10-13'\nAND a.user_id = 143\n;\n\nselect * from leads\nwhere crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707\n\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310);\nSELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198\nSELECT * FROM activities WHERE id IN (356001, 356008); # contacts:\n\nSELECT * FROM opportunities WHERE id IN (1707);\nSELECT * FROM stages where id IN (204, 198);\nSELECT * FROM opportunities WHERE account_id IN (178);\nSELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';\nSELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal\n\nSELECT * FROM activities where crm_configuration_id = 39\nAND opportunity_id IS NULL\nAND is_internal = false\nand status = 'completed' and recording_state = 'recorded'\nAND actual_start_time >= '2025-10-13'\nAND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)\n# AND lead_id IN (112, 109)\n;\n\nSELECT * FROM crm_profiles WHERE user_id = 143;\n\nselect * from inboxes; # 212\nselect * from users where id = 143; # 143\nselect * from inbox_email_batches where inbox_id = 212\nand updated_at >= '2026-01-28 00:00:00' order by id desc;\nselect * from inbox_emails where inbox_id = 212\nand batch_id = 95885 order by id desc;\nselect * from email_messages where origin_user_id = 143;\nselect * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';\nselect * from participants where activity_id = 620247;\n\nselect * from crm_profiles where user_id = 143;\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001\nselect * from transcription where activity_id = 356001; # 6943\nselect * from ai_prompts where transcription_id = 6943;\nSELECT * FROM activity_summary_logs where activity_id = 356001;\n\nSELECT * FROM social_accounts WHERE sociable_id = 143;\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;\n# 422515 softphone tr. 8100\n\nSELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;\n# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS\n\nselect * from ai_prompts where transcription_id IN (8100, 7670);\nselect * from activity_summary_logs where activity_id = 407509;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nSELECT * FROM contacts WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\nSELECT * FROM leads WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\n\nSELECT * FROM activity_searches where user_id = 143;\nSELECT * FROM groups where team_id = 1;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1; # 1150 - 7e75f8025c22\nselect id, name, group_id, status, deleted_at, email\nfrom users where team_id = 1 order by group_id desc ;\n\nselect * from activity_searches where id in (1977, 1978, 1979);\nselect * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);\nselect * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277\nselect * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879\n\nINSERT INTO `activity_search_filters`\n(`activity_search_id`, `filter`, `value`) VALUES\n(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')\n;\n\nselect * from crm_configurations where id = 39;\n\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\nselect * from features;\n\nSELECT * FROM activity_searches where id = 1982; # 1981\nSELECT * FROM activity_search_filters WHERE activity_search_id = 1982;\n\nSELECT * FROM automated_reports where id = 68;\nSELECT * FROM automated_report_results where id = 275;\n\nSELECT * FROM automated_reports order by id desc;\nSELECT * FROM automated_report_results order by id desc;\nselect * from activity_searches where user_id = 143;\nselect * from ask_anything_prompts;\n\nSELECT * FROM groups WHERE id = 1439;\nSELECT * FROM users WHERE group_id = 1439;\n\nselect * from permissions; # 158\nselect * from roles;\nselect * from permission_role\n\nselect * from teams where id = 1;\nselect * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;\nselect * from groups where id = 28;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 179;\nselect * from playbook_categories where id = 1391;\nselect * from users where id = 143;\nselect * from crm_profiles where user_id = 143;\nselect * from activities where crm_configuration_id = 39 and type = 'conference'\nand crm_provider_id IS NOT NULL ORDER by id desc;\nselect * from activities where id = 422003; # 00UO400000pB6fpMAC\n\nSELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type\nFROM automated_report_results ar\nJOIN automated_reports a ON a.id = ar.report_id\nWHERE a.type = 'ask_jiminny'\nLIMIT 10;\n\n\nselect * from teams where id = 3143;\nselect * from crm_configurations where id = 500;\nselect * from users where name = 'Integration Account'; # 1695\nSELECT * FROM social_accounts WHERE sociable_id = 1695;\n\nselect * from activities where crm_configuration_id = 39\nand status = 'completed' and actual_start_time >= '2025-01-01'","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-5696139294825716137
|
2146703024167786053
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Services\Kiosk\AutomatedReports;
use Carbon\CarbonImmutable;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityActualDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityUpdatedDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\DealInsights\ClosingPeriodFilter;
use Jiminny\Component\ActivitySearch\FilterDefinitionCollection;
use Jiminny\Component\ActivitySearch\Service\ActivitySearch;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\Activity\SearchFilter;
use Jiminny\Models\User;
use Jiminny\Repositories\ElasticActivityRepository;
use Jiminny\Services\Kiosk\AutomatedReports\AskJiminnyReportActivityService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\VO\Repository\OnDemandActivitySearch\Criteria;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
class AskJiminnyReportActivityServiceTest extends TestCase
{
private ActivitySearch&MockObject $activitySearch;
private ElasticActivityRepository&MockObject $elasticRepository;
private LoggerInterface&MockObject $logger;
private AskJiminnyReportActivityService $service;
protected function setUp(): void
{
$this->activitySearch = $this->createMock(ActivitySearch::class);
$this->elasticRepository = $this->createMock(ElasticActivityRepository::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->service = new AskJiminnyReportActivityService(
$this->activitySearch,
$this->elasticRepository,
$this->logger,
);
}
private function makeFilter(string $key, ?string $value): SearchFilter&MockObject
{
$filter = $this->createMock(SearchFilter::class);
$filter->method('getFilterProperty')->willReturn($key);
$filter->method('getFilterValue')->willReturn($value);
return $filter;
}
private function makeUser(): User&MockObject
{
$tz = new \DateTimeZone('UTC');
$user = $this->createMock(User::class);
$user->method('getTimezone')->willReturn($tz);
$user->method('getId')->willReturn(1);
$user->method('getUuid')->willReturn('user-uuid');
return $user;
}
private function makeSavedSearch(array $filters): Search&MockObject
{
$savedSearch = $this->createMock(Search::class);
$savedSearch->method('getId')->willReturn(42);
$savedSearch->method('getFilters')->willReturn(new \Illuminate\Support\LazyCollection($filters));
return $savedSearch;
}
public function testGetActivityIdsForSavedSearchReturnsIds(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->expects($this->once())
->method('getArrayFilterKeys')
->with($user)
->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->expects($this->once())
->method('onDemandSearchIdsOnly')
->willReturn(['id-1', 'id-2', 'id-3']);
$this->logger->expects($this->once())
->method('info')
->with('[AskJiminnyReport] Fetched activity IDs for saved search');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1', 'id-2', 'id-3'], $result);
}
public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->expects($this->once())->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEmpty($result);
}
public function testGetActivityIdsFiltersOutDateFilters(): void
{
$user = $this->makeUser();
$nonDateFilter = $this->makeFilter('owner_id', '123');
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');
$updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');
$updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');
$savedSearch = $this->makeSavedSearch([
$nonDateFilter,
$startDateFilter,
$endDateFilter,
$updatedFromFilter,
$updatedToFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
}
public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void
{
$user = $this->makeUser();
$closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');
$closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');
$regularFilter = $this->makeFilter('rep_id', '99');
$savedSearch = $this->makeSavedSearch([
$closingStartFilter,
$closingEndFilter,
$regularFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesArrayFilters(): void
{
$user = $this->makeUser();
$filter1 = $this->makeFilter('outcome', 'positive');
$filter2 = $this->makeFilter('outcome', 'negative');
$savedSearch = $this->makeSavedSearch([$filter1, $filter2]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesScalarFilters(): void
{
$user = $this->makeUser();
$filter = $this->makeFilter('direction', 'inbound');
$savedSearch = $this->makeSavedSearch([$filter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-5'], $result);
}
public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
$this->assertFalse($capturedCriteria->isFirstRequest());
}
public function testGetActivityIdsLogsWithCorrectContext(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);
$this->logger->expects($this->once())
->method('info')
->with(
'[AskJiminnyReport] Fetched activity IDs for saved search',
$this->callback(fn ($context) => $context['saved_search_id'] === 42
&& $context['user_id'] === 1
&& $context['activity_count'] === 2)
);
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
}
public static function frequencyDateRangeProvider(): array
{
return [
'daily' => [
AutomatedReportsService::FREQUENCY_DAILY,
'2025-06-15 00:00:00',
'2025-06-15 23:59:59',
],
'weekly' => [
AutomatedReportsService::FREQUENCY_WEEKLY,
'2025-06-09 00:00:00',
'2025-06-15 23:59:59',
],
'monthly' => [
AutomatedReportsService::FREQUENCY_MONTHLY,
'2025-05-01 00:00:00',
'2025-05-31 23:59:59',
],
'quarterly' => [
AutomatedReportsService::FREQUENCY_QUARTERLY,
'2025-01-01 00:00:00',
'2025-03-31 23:59:59',
],
];
}
/**
* @dataProvider frequencyDateRangeProvider
*/
public function testGetActivityIdsInjectsDateRangeForFrequency(
string $frequency,
string $expectedStartDate,
string $expectedEndDate,
): void {
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);
$this->assertNotNull($capturedCriteria);
$this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void
{
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');
$savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);
$this->assertNotNull($capturedCriteria);
$this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
9
12
2
4
Previous Highlighted Error
Next Highlighted Error
SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o
JOIN activities a ON o.id = a.opportunity_id
WHERE a.crm_configuration_id = 39
AND a.actual_start_time > '2025-10-13'
AND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM activities
WHERE crm_configuration_id = 39 and user_id = 143
and actual_start_time >= '2025-10-13'
AND type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM opportunities WHERE account_id IN (178);
select * from activities where id IN (620137, 620187, 620188, 620189, 620230);
# HS
SELECT * FROM opportunities WHERE id IN (238);
select * from activities where id IN (477,2076);
select * from users;
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM activities;
SELECT COUNT(*) FROM opportunities;
UPDATE activities
SET
actual_start_time = '2025-12-19 09:00:00',
actual_end_time = '2025-12-19 10:30:00',
scheduled_start_time = '2025-12-19 09:00:00',
scheduled_end_time = '2025-12-19 10:30:00'
WHERE id IN (407509,407375);
select * from partners;
SELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id
FROM activities
WHERE user_id = 143
AND actual_start_time >= '2025-10-13 00:00:00'
AND actual_start_time <= '2026-01-13 23:59:59'
ORDER BY actual_start_time DESC;
SELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;
SELECT * FROM crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;
# lead_id
# account_id 177
# contact_id 3969
# opportunity_id
# stage_id 203
SELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;
SELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'
AND user_id = 143 and actual_start_time >= '2025-10-13';
SELECT * FROM activities a
# JOIN opportunities o ON a.opportunity_id = o.id
WHERE a.crm_configuration_id = 39 AND a.type = 'conference'
and status = 'completed' and recording_state = 'recorded'
and a.actual_start_time >= '2025-10-13'
AND a.user_id = 143
;
select * from leads
where crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310);
SELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198
SELECT * FROM activities WHERE id IN (356001, 356008); # contacts:
SELECT * FROM opportunities WHERE id IN (1707);
SELECT * FROM stages where id IN (204, 198);
SELECT * FROM opportunities WHERE account_id IN (178);
SELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';
SELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal
SELECT * FROM activities where crm_configuration_id = 39
AND opportunity_id IS NULL
AND is_internal = false
and status = 'completed' and recording_state = 'recorded'
AND actual_start_time >= '2025-10-13'
AND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)
# AND lead_id IN (112, 109)
;
SELECT * FROM crm_profiles WHERE user_id = 143;
select * from inboxes; # 212
select * from users where id = 143; # 143
select * from inbox_email_batches where inbox_id = 212
and updated_at >= '2026-01-28 00:00:00' order by id desc;
select * from inbox_emails where inbox_id = 212
and batch_id = 95885 order by id desc;
select * from email_messages where origin_user_id = 143;
select * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';
select * from participants where activity_id = 620247;
select * from crm_profiles where user_id = 143;
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001
select * from transcription where activity_id = 356001; # 6943
select * from ai_prompts where transcription_id = 6943;
SELECT * FROM activity_summary_logs where activity_id = 356001;
SELECT * FROM social_accounts WHERE sociable_id = 143;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;
# 422515 softphone tr. 8100
SELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;
# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS
select * from ai_prompts where transcription_id IN (8100, 7670);
select * from activity_summary_logs where activity_id = 407509;
select * from sidekick_settings;
select * from default_activity_types;
SELECT * FROM contacts WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM leads WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM activity_searches where user_id = 143;
SELECT * FROM groups where team_id = 1;
select * from teams where id = 1;
select * from groups where team_id = 1; # 1150 - 7e75f8025c22
select id, name, group_id, status, deleted_at, email
from users where team_id = 1 order by group_id desc ;
select * from activity_searches where id in (1977, 1978, 1979);
select * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);
select * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277
select * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879
INSERT INTO `activity_search_filters`
(`activity_search_id`, `filter`, `value`) VALUES
(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')
;
select * from crm_configurations where id = 39;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from features;
SELECT * FROM activity_searches where id = 1982; # 1981
SELECT * FROM activity_search_filters WHERE activity_search_id = 1982;
SELECT * FROM automated_reports where id = 68;
SELECT * FROM automated_report_results where id = 275;
SELECT * FROM automated_reports order by id desc;
SELECT * FROM automated_report_results order by id desc;
select * from activity_searches where user_id = 143;
select * from ask_anything_prompts;
SELECT * FROM groups WHERE id = 1439;
SELECT * FROM users WHERE group_id = 1439;
select * from permissions; # 158
select * from roles;
select * from permission_role
select * from teams where id = 1;
select * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;
select * from groups where id = 28;
select * from playbooks where team_id = 1;
select * from playbooks where id = 179;
select * from playbook_categories where id = 1391;
select * from users where id = 143;
select * from crm_profiles where user_id = 143;
select * from activities where crm_configuration_id = 39 and type = 'conference'
and crm_provider_id IS NOT NULL ORDER by id desc;
select * from activities where id = 422003; # 00UO400000pB6fpMAC
SELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type
FROM automated_report_results ar
JOIN automated_reports a ON a.id = ar.report_id
WHERE a.type = 'ask_jiminny'
LIMIT 10;
select * from teams where id = 3143;
select * from crm_configurations where id = 500;
select * from users where name = 'Integration Account'; # 1695
SELECT * FROM social_accounts WHERE sociable_id = 1695;
select * from activities where crm_configuration_id = 39
and status = 'completed' and actual_start_time >= '2025-01-01'
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
54641
|
|
54643
|
NULL
|
0
|
2026-04-20T09:11:55.090496+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776676315090_m1.jpg...
|
PhpStorm
|
faVsco.js – SF [jiminny@localhost]
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Services\Kiosk\AutomatedReports;
use Carbon\CarbonImmutable;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityActualDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityUpdatedDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\DealInsights\ClosingPeriodFilter;
use Jiminny\Component\ActivitySearch\FilterDefinitionCollection;
use Jiminny\Component\ActivitySearch\Service\ActivitySearch;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\Activity\SearchFilter;
use Jiminny\Models\User;
use Jiminny\Repositories\ElasticActivityRepository;
use Jiminny\Services\Kiosk\AutomatedReports\AskJiminnyReportActivityService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\VO\Repository\OnDemandActivitySearch\Criteria;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
class AskJiminnyReportActivityServiceTest extends TestCase
{
private ActivitySearch&MockObject $activitySearch;
private ElasticActivityRepository&MockObject $elasticRepository;
private LoggerInterface&MockObject $logger;
private AskJiminnyReportActivityService $service;
protected function setUp(): void
{
$this->activitySearch = $this->createMock(ActivitySearch::class);
$this->elasticRepository = $this->createMock(ElasticActivityRepository::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->service = new AskJiminnyReportActivityService(
$this->activitySearch,
$this->elasticRepository,
$this->logger,
);
}
private function makeFilter(string $key, ?string $value): SearchFilter&MockObject
{
$filter = $this->createMock(SearchFilter::class);
$filter->method('getFilterProperty')->willReturn($key);
$filter->method('getFilterValue')->willReturn($value);
return $filter;
}
private function makeUser(): User&MockObject
{
$tz = new \DateTimeZone('UTC');
$user = $this->createMock(User::class);
$user->method('getTimezone')->willReturn($tz);
$user->method('getId')->willReturn(1);
$user->method('getUuid')->willReturn('user-uuid');
return $user;
}
private function makeSavedSearch(array $filters): Search&MockObject
{
$savedSearch = $this->createMock(Search::class);
$savedSearch->method('getId')->willReturn(42);
$savedSearch->method('getFilters')->willReturn(new \Illuminate\Support\LazyCollection($filters));
return $savedSearch;
}
public function testGetActivityIdsForSavedSearchReturnsIds(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->expects($this->once())
->method('getArrayFilterKeys')
->with($user)
->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->expects($this->once())
->method('onDemandSearchIdsOnly')
->willReturn(['id-1', 'id-2', 'id-3']);
$this->logger->expects($this->once())
->method('info')
->with('[AskJiminnyReport] Fetched activity IDs for saved search');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1', 'id-2', 'id-3'], $result);
}
public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->expects($this->once())->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEmpty($result);
}
public function testGetActivityIdsFiltersOutDateFilters(): void
{
$user = $this->makeUser();
$nonDateFilter = $this->makeFilter('owner_id', '123');
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');
$updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');
$updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');
$savedSearch = $this->makeSavedSearch([
$nonDateFilter,
$startDateFilter,
$endDateFilter,
$updatedFromFilter,
$updatedToFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
}
public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void
{
$user = $this->makeUser();
$closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');
$closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');
$regularFilter = $this->makeFilter('rep_id', '99');
$savedSearch = $this->makeSavedSearch([
$closingStartFilter,
$closingEndFilter,
$regularFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesArrayFilters(): void
{
$user = $this->makeUser();
$filter1 = $this->makeFilter('outcome', 'positive');
$filter2 = $this->makeFilter('outcome', 'negative');
$savedSearch = $this->makeSavedSearch([$filter1, $filter2]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesScalarFilters(): void
{
$user = $this->makeUser();
$filter = $this->makeFilter('direction', 'inbound');
$savedSearch = $this->makeSavedSearch([$filter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-5'], $result);
}
public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
$this->assertFalse($capturedCriteria->isFirstRequest());
}
public function testGetActivityIdsLogsWithCorrectContext(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);
$this->logger->expects($this->once())
->method('info')
->with(
'[AskJiminnyReport] Fetched activity IDs for saved search',
$this->callback(fn ($context) => $context['saved_search_id'] === 42
&& $context['user_id'] === 1
&& $context['activity_count'] === 2)
);
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
}
public static function frequencyDateRangeProvider(): array
{
return [
'daily' => [
AutomatedReportsService::FREQUENCY_DAILY,
'2025-06-15 00:00:00',
'2025-06-15 23:59:59',
],
'weekly' => [
AutomatedReportsService::FREQUENCY_WEEKLY,
'2025-06-09 00:00:00',
'2025-06-15 23:59:59',
],
'monthly' => [
AutomatedReportsService::FREQUENCY_MONTHLY,
'2025-05-01 00:00:00',
'2025-05-31 23:59:59',
],
'quarterly' => [
AutomatedReportsService::FREQUENCY_QUARTERLY,
'2025-01-01 00:00:00',
'2025-03-31 23:59:59',
],
];
}
/**
* @dataProvider frequencyDateRangeProvider
*/
public function testGetActivityIdsInjectsDateRangeForFrequency(
string $frequency,
string $expectedStartDate,
string $expectedEndDate,
): void {
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);
$this->assertNotNull($capturedCriteria);
$this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void
{
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');
$savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);
$this->assertNotNull($capturedCriteria);
$this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
9
12
2
4
Previous Highlighted Error
Next Highlighted Error
SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o
JOIN activities a ON o.id = a.opportunity_id
WHERE a.crm_configuration_id = 39
AND a.actual_start_time > '2025-10-13'
AND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM activities
WHERE crm_configuration_id = 39 and user_id = 143
and actual_start_time >= '2025-10-13'
AND type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM opportunities WHERE account_id IN (178);
select * from activities where id IN (620137, 620187, 620188, 620189, 620230);
# HS
SELECT * FROM opportunities WHERE id IN (238);
select * from activities where id IN (477,2076);
select * from users;
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM activities;
SELECT COUNT(*) FROM opportunities;
UPDATE activities
SET
actual_start_time = '2025-12-19 09:00:00',
actual_end_time = '2025-12-19 10:30:00',
scheduled_start_time = '2025-12-19 09:00:00',
scheduled_end_time = '2025-12-19 10:30:00'
WHERE id IN (407509,407375);
select * from partners;
SELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id
FROM activities
WHERE user_id = 143
AND actual_start_time >= '2025-10-13 00:00:00'
AND actual_start_time <= '2026-01-13 23:59:59'
ORDER BY actual_start_time DESC;
SELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;
SELECT * FROM crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;
# lead_id
# account_id 177
# contact_id 3969
# opportunity_id
# stage_id 203
SELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;
SELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'
AND user_id = 143 and actual_start_time >= '2025-10-13';
SELECT * FROM activities a
# JOIN opportunities o ON a.opportunity_id = o.id
WHERE a.crm_configuration_id = 39 AND a.type = 'conference'
and status = 'completed' and recording_state = 'recorded'
and a.actual_start_time >= '2025-10-13'
AND a.user_id = 143
;
select * from leads
where crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310);
SELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198
SELECT * FROM activities WHERE id IN (356001, 356008); # contacts:
SELECT * FROM opportunities WHERE id IN (1707);
SELECT * FROM stages where id IN (204, 198);
SELECT * FROM opportunities WHERE account_id IN (178);
SELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';
SELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal
SELECT * FROM activities where crm_configuration_id = 39
AND opportunity_id IS NULL
AND is_internal = false
and status = 'completed' and recording_state = 'recorded'
AND actual_start_time >= '2025-10-13'
AND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)
# AND lead_id IN (112, 109)
;
SELECT * FROM crm_profiles WHERE user_id = 143;
select * from inboxes; # 212
select * from users where id = 143; # 143
select * from inbox_email_batches where inbox_id = 212
and updated_at >= '2026-01-28 00:00:00' order by id desc;
select * from inbox_emails where inbox_id = 212
and batch_id = 95885 order by id desc;
select * from email_messages where origin_user_id = 143;
select * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';
select * from participants where activity_id = 620247;
select * from crm_profiles where user_id = 143;
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001
select * from transcription where activity_id = 356001; # 6943
select * from ai_prompts where transcription_id = 6943;
SELECT * FROM activity_summary_logs where activity_id = 356001;
SELECT * FROM social_accounts WHERE sociable_id = 143;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;
# 422515 softphone tr. 8100
SELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;
# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS
select * from ai_prompts where transcription_id IN (8100, 7670);
select * from activity_summary_logs where activity_id = 407509;
select * from sidekick_settings;
select * from default_activity_types;
SELECT * FROM contacts WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM leads WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM activity_searches where user_id = 143;
SELECT * FROM groups where team_id = 1;
select * from teams where id = 1;
select * from groups where team_id = 1; # 1150 - 7e75f8025c22
select id, name, group_id, status, deleted_at, email
from users where team_id = 1 order by group_id desc ;
select * from activity_searches where id in (1977, 1978, 1979);
select * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);
select * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277
select * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879
INSERT INTO `activity_search_filters`
(`activity_search_id`, `filter`, `value`) VALUES
(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')
;
select * from crm_configurations where id = 39;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from features;
SELECT * FROM activity_searches where id = 1982; # 1981
SELECT * FROM activity_search_filters WHERE activity_search_id = 1982;
SELECT * FROM automated_reports where id = 68;
SELECT * FROM automated_report_results where id = 275;
SELECT * FROM automated_reports order by id desc;
SELECT * FROM automated_report_results order by id desc;
select * from activity_searches where user_id = 143;
select * from ask_anything_prompts;
SELECT * FROM groups WHERE id = 1439;
SELECT * FROM users WHERE group_id = 1439;
select * from permissions; # 158
select * from roles;
select * from permission_role
select * from teams where id = 1;
select * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;
select * from groups where id = 28;
select * from playbooks where team_id = 1;
select * from playbooks where id = 179;
select * from playbook_categories where id = 1391;
select * from users where id = 143;
select * from crm_profiles where user_id = 143;
select * from activities where crm_configuration_id = 39 and type = 'conference'
and crm_provider_id IS NOT NULL ORDER by id desc;
select * from activities where id = 422003; # 00UO400000pB6fpMAC
SELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type
FROM automated_report_results ar
JOIN automated_reports a ON a.id = ar.report_id
WHERE a.type = 'ask_jiminny'
LIMIT 10;
select * from teams where id = 3143;
select * from crm_configurations where id = 500;
select * from users where name = 'Integration Account'; # 1695
SELECT * FROM social_accounts WHERE sociable_id = 1695;
select * from activities where crm_configuration_id = 39
and status = 'completed' and actual_start_time >= '2025-01-01'
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11894 on JY-18909-automated-reports-ask-jiminny, menu","depth":5,"help_text":"Pull request #11894 exists for current branch JY-18909-automated-reports-ask-jiminny","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.016666668,"height":0.02111111},"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.016666668,"height":0.02111111},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.025555555},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.014583333,"height":0.025555555},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Services\\Kiosk\\AutomatedReports;\n\nuse Carbon\\CarbonImmutable;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityActualDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityUpdatedDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\DealInsights\\ClosingPeriodFilter;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionCollection;\nuse Jiminny\\Component\\ActivitySearch\\Service\\ActivitySearch;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\Activity\\SearchFilter;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\ElasticActivityRepository;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AskJiminnyReportActivityService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\VO\\Repository\\OnDemandActivitySearch\\Criteria;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\n\nclass AskJiminnyReportActivityServiceTest extends TestCase\n{\n private ActivitySearch&MockObject $activitySearch;\n private ElasticActivityRepository&MockObject $elasticRepository;\n private LoggerInterface&MockObject $logger;\n private AskJiminnyReportActivityService $service;\n\n protected function setUp(): void\n {\n $this->activitySearch = $this->createMock(ActivitySearch::class);\n $this->elasticRepository = $this->createMock(ElasticActivityRepository::class);\n $this->logger = $this->createMock(LoggerInterface::class);\n\n $this->service = new AskJiminnyReportActivityService(\n $this->activitySearch,\n $this->elasticRepository,\n $this->logger,\n );\n }\n\n private function makeFilter(string $key, ?string $value): SearchFilter&MockObject\n {\n $filter = $this->createMock(SearchFilter::class);\n $filter->method('getFilterProperty')->willReturn($key);\n $filter->method('getFilterValue')->willReturn($value);\n\n return $filter;\n }\n\n private function makeUser(): User&MockObject\n {\n $tz = new \\DateTimeZone('UTC');\n $user = $this->createMock(User::class);\n $user->method('getTimezone')->willReturn($tz);\n $user->method('getId')->willReturn(1);\n $user->method('getUuid')->willReturn('user-uuid');\n\n return $user;\n }\n\n private function makeSavedSearch(array $filters): Search&MockObject\n {\n $savedSearch = $this->createMock(Search::class);\n $savedSearch->method('getId')->willReturn(42);\n $savedSearch->method('getFilters')->willReturn(new \\Illuminate\\Support\\LazyCollection($filters));\n\n return $savedSearch;\n }\n\n public function testGetActivityIdsForSavedSearchReturnsIds(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->expects($this->once())\n ->method('getArrayFilterKeys')\n ->with($user)\n ->willReturn([]);\n\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n\n $this->elasticRepository->expects($this->once())\n ->method('onDemandSearchIdsOnly')\n ->willReturn(['id-1', 'id-2', 'id-3']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[AskJiminnyReport] Fetched activity IDs for saved search');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1', 'id-2', 'id-3'], $result);\n }\n\n public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $this->logger->expects($this->once())->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEmpty($result);\n }\n\n public function testGetActivityIdsFiltersOutDateFilters(): void\n {\n $user = $this->makeUser();\n\n $nonDateFilter = $this->makeFilter('owner_id', '123');\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');\n $updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');\n $updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');\n\n $savedSearch = $this->makeSavedSearch([\n $nonDateFilter,\n $startDateFilter,\n $endDateFilter,\n $updatedFromFilter,\n $updatedToFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n }\n\n public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void\n {\n $user = $this->makeUser();\n\n $closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');\n $closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');\n $regularFilter = $this->makeFilter('rep_id', '99');\n\n $savedSearch = $this->makeSavedSearch([\n $closingStartFilter,\n $closingEndFilter,\n $regularFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesArrayFilters(): void\n {\n $user = $this->makeUser();\n\n $filter1 = $this->makeFilter('outcome', 'positive');\n $filter2 = $this->makeFilter('outcome', 'negative');\n\n $savedSearch = $this->makeSavedSearch([$filter1, $filter2]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesScalarFilters(): void\n {\n $user = $this->makeUser();\n\n $filter = $this->makeFilter('direction', 'inbound');\n $savedSearch = $this->makeSavedSearch([$filter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-5'], $result);\n }\n\n public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertFalse($capturedCriteria->isFirstRequest());\n }\n\n public function testGetActivityIdsLogsWithCorrectContext(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with(\n '[AskJiminnyReport] Fetched activity IDs for saved search',\n $this->callback(fn ($context) => $context['saved_search_id'] === 42\n && $context['user_id'] === 1\n && $context['activity_count'] === 2)\n );\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n }\n\n public static function frequencyDateRangeProvider(): array\n {\n return [\n 'daily' => [\n AutomatedReportsService::FREQUENCY_DAILY,\n '2025-06-15 00:00:00',\n '2025-06-15 23:59:59',\n ],\n 'weekly' => [\n AutomatedReportsService::FREQUENCY_WEEKLY,\n '2025-06-09 00:00:00',\n '2025-06-15 23:59:59',\n ],\n 'monthly' => [\n AutomatedReportsService::FREQUENCY_MONTHLY,\n '2025-05-01 00:00:00',\n '2025-05-31 23:59:59',\n ],\n 'quarterly' => [\n AutomatedReportsService::FREQUENCY_QUARTERLY,\n '2025-01-01 00:00:00',\n '2025-03-31 23:59:59',\n ],\n ];\n }\n\n /**\n * @dataProvider frequencyDateRangeProvider\n */\n public function testGetActivityIdsInjectsDateRangeForFrequency(\n string $frequency,\n string $expectedStartDate,\n string $expectedEndDate,\n ): void {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n\n public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void\n {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');\n $savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Services\\Kiosk\\AutomatedReports;\n\nuse Carbon\\CarbonImmutable;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityActualDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\ActivityUpdatedDate;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\DealInsights\\ClosingPeriodFilter;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinitionCollection;\nuse Jiminny\\Component\\ActivitySearch\\Service\\ActivitySearch;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\Activity\\SearchFilter;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\ElasticActivityRepository;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AskJiminnyReportActivityService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\VO\\Repository\\OnDemandActivitySearch\\Criteria;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\n\nclass AskJiminnyReportActivityServiceTest extends TestCase\n{\n private ActivitySearch&MockObject $activitySearch;\n private ElasticActivityRepository&MockObject $elasticRepository;\n private LoggerInterface&MockObject $logger;\n private AskJiminnyReportActivityService $service;\n\n protected function setUp(): void\n {\n $this->activitySearch = $this->createMock(ActivitySearch::class);\n $this->elasticRepository = $this->createMock(ElasticActivityRepository::class);\n $this->logger = $this->createMock(LoggerInterface::class);\n\n $this->service = new AskJiminnyReportActivityService(\n $this->activitySearch,\n $this->elasticRepository,\n $this->logger,\n );\n }\n\n private function makeFilter(string $key, ?string $value): SearchFilter&MockObject\n {\n $filter = $this->createMock(SearchFilter::class);\n $filter->method('getFilterProperty')->willReturn($key);\n $filter->method('getFilterValue')->willReturn($value);\n\n return $filter;\n }\n\n private function makeUser(): User&MockObject\n {\n $tz = new \\DateTimeZone('UTC');\n $user = $this->createMock(User::class);\n $user->method('getTimezone')->willReturn($tz);\n $user->method('getId')->willReturn(1);\n $user->method('getUuid')->willReturn('user-uuid');\n\n return $user;\n }\n\n private function makeSavedSearch(array $filters): Search&MockObject\n {\n $savedSearch = $this->createMock(Search::class);\n $savedSearch->method('getId')->willReturn(42);\n $savedSearch->method('getFilters')->willReturn(new \\Illuminate\\Support\\LazyCollection($filters));\n\n return $savedSearch;\n }\n\n public function testGetActivityIdsForSavedSearchReturnsIds(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->expects($this->once())\n ->method('getArrayFilterKeys')\n ->with($user)\n ->willReturn([]);\n\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n\n $this->elasticRepository->expects($this->once())\n ->method('onDemandSearchIdsOnly')\n ->willReturn(['id-1', 'id-2', 'id-3']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with('[AskJiminnyReport] Fetched activity IDs for saved search');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1', 'id-2', 'id-3'], $result);\n }\n\n public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $this->logger->expects($this->once())->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEmpty($result);\n }\n\n public function testGetActivityIdsFiltersOutDateFilters(): void\n {\n $user = $this->makeUser();\n\n $nonDateFilter = $this->makeFilter('owner_id', '123');\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');\n $updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');\n $updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');\n\n $savedSearch = $this->makeSavedSearch([\n $nonDateFilter,\n $startDateFilter,\n $endDateFilter,\n $updatedFromFilter,\n $updatedToFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n }\n\n public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void\n {\n $user = $this->makeUser();\n\n $closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');\n $closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');\n $regularFilter = $this->makeFilter('rep_id', '99');\n\n $savedSearch = $this->makeSavedSearch([\n $closingStartFilter,\n $closingEndFilter,\n $regularFilter,\n ]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesArrayFilters(): void\n {\n $user = $this->makeUser();\n\n $filter1 = $this->makeFilter('outcome', 'positive');\n $filter2 = $this->makeFilter('outcome', 'negative');\n\n $savedSearch = $this->makeSavedSearch([$filter1, $filter2]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-1'], $result);\n }\n\n public function testGetActivityIdsHandlesScalarFilters(): void\n {\n $user = $this->makeUser();\n\n $filter = $this->makeFilter('direction', 'inbound');\n $savedSearch = $this->makeSavedSearch([$filter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);\n $this->logger->method('info');\n\n $result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertEquals(['id-5'], $result);\n }\n\n public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n $this->logger->method('info');\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertFalse($capturedCriteria->isFirstRequest());\n }\n\n public function testGetActivityIdsLogsWithCorrectContext(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with(\n '[AskJiminnyReport] Fetched activity IDs for saved search',\n $this->callback(fn ($context) => $context['saved_search_id'] === 42\n && $context['user_id'] === 1\n && $context['activity_count'] === 2)\n );\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user);\n }\n\n public static function frequencyDateRangeProvider(): array\n {\n return [\n 'daily' => [\n AutomatedReportsService::FREQUENCY_DAILY,\n '2025-06-15 00:00:00',\n '2025-06-15 23:59:59',\n ],\n 'weekly' => [\n AutomatedReportsService::FREQUENCY_WEEKLY,\n '2025-06-09 00:00:00',\n '2025-06-15 23:59:59',\n ],\n 'monthly' => [\n AutomatedReportsService::FREQUENCY_MONTHLY,\n '2025-05-01 00:00:00',\n '2025-05-31 23:59:59',\n ],\n 'quarterly' => [\n AutomatedReportsService::FREQUENCY_QUARTERLY,\n '2025-01-01 00:00:00',\n '2025-03-31 23:59:59',\n ],\n ];\n }\n\n /**\n * @dataProvider frequencyDateRangeProvider\n */\n public function testGetActivityIdsInjectsDateRangeForFrequency(\n string $frequency,\n string $expectedStartDate,\n string $expectedEndDate,\n ): void {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n\n public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void\n {\n $user = $this->makeUser();\n $savedSearch = $this->makeSavedSearch([]);\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertNull($capturedCriteria->getStartDate());\n $this->assertNull($capturedCriteria->getEndDate());\n }\n\n public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void\n {\n CarbonImmutable::setTestNow('2025-06-16 12:00:00');\n\n try {\n $user = $this->makeUser();\n\n $startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');\n $endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');\n $savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);\n\n $filterSet = $this->createMock(FilterDefinitionCollection::class);\n\n $this->activitySearch->method('getArrayFilterKeys')->willReturn([]);\n $this->logger->method('info');\n $this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);\n\n $capturedCriteria = null;\n $this->activitySearch->expects($this->once())\n ->method('getOnDemandPageFilterSet')\n ->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {\n $capturedCriteria = $criteria;\n\n return $filterSet;\n });\n\n $this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);\n\n $this->assertNotNull($capturedCriteria);\n $this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));\n $this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));\n } finally {\n CarbonImmutable::setTestNow();\n }\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"12","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o\nJOIN activities a ON o.id = a.opportunity_id\nWHERE a.crm_configuration_id = 39\nAND a.actual_start_time > '2025-10-13'\nAND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 39 and user_id = 143\nand actual_start_time >= '2025-10-13'\nAND type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM opportunities WHERE account_id IN (178);\nselect * from activities where id IN (620137, 620187, 620188, 620189, 620230);\n\n# HS\nSELECT * FROM opportunities WHERE id IN (238);\nselect * from activities where id IN (477,2076);\n\nselect * from users;\n\nSELECT COUNT(*) FROM users;\nSELECT COUNT(*) FROM activities;\nSELECT COUNT(*) FROM opportunities;\n\nUPDATE activities\nSET\n actual_start_time = '2025-12-19 09:00:00',\n actual_end_time = '2025-12-19 10:30:00',\n scheduled_start_time = '2025-12-19 09:00:00',\n scheduled_end_time = '2025-12-19 10:30:00'\nWHERE id IN (407509,407375);\n\nselect * from partners;\n\nSELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id\nFROM activities\nWHERE user_id = 143\nAND actual_start_time >= '2025-10-13 00:00:00'\nAND actual_start_time <= '2026-01-13 23:59:59'\nORDER BY actual_start_time DESC;\n\nSELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;\nSELECT * FROM crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;\n# lead_id\n# account_id 177\n# contact_id 3969\n# opportunity_id\n# stage_id 203\n\nSELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;\n\nSELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'\nAND user_id = 143 and actual_start_time >= '2025-10-13';\n\nSELECT * FROM activities a\n# JOIN opportunities o ON a.opportunity_id = o.id\nWHERE a.crm_configuration_id = 39 AND a.type = 'conference'\nand status = 'completed' and recording_state = 'recorded'\nand a.actual_start_time >= '2025-10-13'\nAND a.user_id = 143\n;\n\nselect * from leads\nwhere crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707\n\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310);\nSELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198\nSELECT * FROM activities WHERE id IN (356001, 356008); # contacts:\n\nSELECT * FROM opportunities WHERE id IN (1707);\nSELECT * FROM stages where id IN (204, 198);\nSELECT * FROM opportunities WHERE account_id IN (178);\nSELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';\nSELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal\n\nSELECT * FROM activities where crm_configuration_id = 39\nAND opportunity_id IS NULL\nAND is_internal = false\nand status = 'completed' and recording_state = 'recorded'\nAND actual_start_time >= '2025-10-13'\nAND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)\n# AND lead_id IN (112, 109)\n;\n\nSELECT * FROM crm_profiles WHERE user_id = 143;\n\nselect * from inboxes; # 212\nselect * from users where id = 143; # 143\nselect * from inbox_email_batches where inbox_id = 212\nand updated_at >= '2026-01-28 00:00:00' order by id desc;\nselect * from inbox_emails where inbox_id = 212\nand batch_id = 95885 order by id desc;\nselect * from email_messages where origin_user_id = 143;\nselect * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';\nselect * from participants where activity_id = 620247;\n\nselect * from crm_profiles where user_id = 143;\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001\nselect * from transcription where activity_id = 356001; # 6943\nselect * from ai_prompts where transcription_id = 6943;\nSELECT * FROM activity_summary_logs where activity_id = 356001;\n\nSELECT * FROM social_accounts WHERE sociable_id = 143;\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;\n# 422515 softphone tr. 8100\n\nSELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;\n# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS\n\nselect * from ai_prompts where transcription_id IN (8100, 7670);\nselect * from activity_summary_logs where activity_id = 407509;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nSELECT * FROM contacts WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\nSELECT * FROM leads WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\n\nSELECT * FROM activity_searches where user_id = 143;\nSELECT * FROM groups where team_id = 1;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1; # 1150 - 7e75f8025c22\nselect id, name, group_id, status, deleted_at, email\nfrom users where team_id = 1 order by group_id desc ;\n\nselect * from activity_searches where id in (1977, 1978, 1979);\nselect * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);\nselect * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277\nselect * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879\n\nINSERT INTO `activity_search_filters`\n(`activity_search_id`, `filter`, `value`) VALUES\n(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')\n;\n\nselect * from crm_configurations where id = 39;\n\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\nselect * from features;\n\nSELECT * FROM activity_searches where id = 1982; # 1981\nSELECT * FROM activity_search_filters WHERE activity_search_id = 1982;\n\nSELECT * FROM automated_reports where id = 68;\nSELECT * FROM automated_report_results where id = 275;\n\nSELECT * FROM automated_reports order by id desc;\nSELECT * FROM automated_report_results order by id desc;\nselect * from activity_searches where user_id = 143;\nselect * from ask_anything_prompts;\n\nSELECT * FROM groups WHERE id = 1439;\nSELECT * FROM users WHERE group_id = 1439;\n\nselect * from permissions; # 158\nselect * from roles;\nselect * from permission_role\n\nselect * from teams where id = 1;\nselect * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;\nselect * from groups where id = 28;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 179;\nselect * from playbook_categories where id = 1391;\nselect * from users where id = 143;\nselect * from crm_profiles where user_id = 143;\nselect * from activities where crm_configuration_id = 39 and type = 'conference'\nand crm_provider_id IS NOT NULL ORDER by id desc;\nselect * from activities where id = 422003; # 00UO400000pB6fpMAC\n\nSELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type\nFROM automated_report_results ar\nJOIN automated_reports a ON a.id = ar.report_id\nWHERE a.type = 'ask_jiminny'\nLIMIT 10;\n\n\nselect * from teams where id = 3143;\nselect * from crm_configurations where id = 500;\nselect * from users where name = 'Integration Account'; # 1695\nSELECT * FROM social_accounts WHERE sociable_id = 1695;\n\nselect * from activities where crm_configuration_id = 39\nand status = 'completed' and actual_start_time >= '2025-01-01'","depth":4,"value":"SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o\nJOIN activities a ON o.id = a.opportunity_id\nWHERE a.crm_configuration_id = 39\nAND a.actual_start_time > '2025-10-13'\nAND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 39 and user_id = 143\nand actual_start_time >= '2025-10-13'\nAND type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM opportunities WHERE account_id IN (178);\nselect * from activities where id IN (620137, 620187, 620188, 620189, 620230);\n\n# HS\nSELECT * FROM opportunities WHERE id IN (238);\nselect * from activities where id IN (477,2076);\n\nselect * from users;\n\nSELECT COUNT(*) FROM users;\nSELECT COUNT(*) FROM activities;\nSELECT COUNT(*) FROM opportunities;\n\nUPDATE activities\nSET\n actual_start_time = '2025-12-19 09:00:00',\n actual_end_time = '2025-12-19 10:30:00',\n scheduled_start_time = '2025-12-19 09:00:00',\n scheduled_end_time = '2025-12-19 10:30:00'\nWHERE id IN (407509,407375);\n\nselect * from partners;\n\nSELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id\nFROM activities\nWHERE user_id = 143\nAND actual_start_time >= '2025-10-13 00:00:00'\nAND actual_start_time <= '2026-01-13 23:59:59'\nORDER BY actual_start_time DESC;\n\nSELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;\nSELECT * FROM crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;\n# lead_id\n# account_id 177\n# contact_id 3969\n# opportunity_id\n# stage_id 203\n\nSELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;\n\nSELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'\nAND user_id = 143 and actual_start_time >= '2025-10-13';\n\nSELECT * FROM activities a\n# JOIN opportunities o ON a.opportunity_id = o.id\nWHERE a.crm_configuration_id = 39 AND a.type = 'conference'\nand status = 'completed' and recording_state = 'recorded'\nand a.actual_start_time >= '2025-10-13'\nAND a.user_id = 143\n;\n\nselect * from leads\nwhere crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707\n\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310);\nSELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198\nSELECT * FROM activities WHERE id IN (356001, 356008); # contacts:\n\nSELECT * FROM opportunities WHERE id IN (1707);\nSELECT * FROM stages where id IN (204, 198);\nSELECT * FROM opportunities WHERE account_id IN (178);\nSELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';\nSELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal\n\nSELECT * FROM activities where crm_configuration_id = 39\nAND opportunity_id IS NULL\nAND is_internal = false\nand status = 'completed' and recording_state = 'recorded'\nAND actual_start_time >= '2025-10-13'\nAND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)\n# AND lead_id IN (112, 109)\n;\n\nSELECT * FROM crm_profiles WHERE user_id = 143;\n\nselect * from inboxes; # 212\nselect * from users where id = 143; # 143\nselect * from inbox_email_batches where inbox_id = 212\nand updated_at >= '2026-01-28 00:00:00' order by id desc;\nselect * from inbox_emails where inbox_id = 212\nand batch_id = 95885 order by id desc;\nselect * from email_messages where origin_user_id = 143;\nselect * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';\nselect * from participants where activity_id = 620247;\n\nselect * from crm_profiles where user_id = 143;\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001\nselect * from transcription where activity_id = 356001; # 6943\nselect * from ai_prompts where transcription_id = 6943;\nSELECT * FROM activity_summary_logs where activity_id = 356001;\n\nSELECT * FROM social_accounts WHERE sociable_id = 143;\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;\n# 422515 softphone tr. 8100\n\nSELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;\n# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS\n\nselect * from ai_prompts where transcription_id IN (8100, 7670);\nselect * from activity_summary_logs where activity_id = 407509;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nSELECT * FROM contacts WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\nSELECT * FROM leads WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\n\nSELECT * FROM activity_searches where user_id = 143;\nSELECT * FROM groups where team_id = 1;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1; # 1150 - 7e75f8025c22\nselect id, name, group_id, status, deleted_at, email\nfrom users where team_id = 1 order by group_id desc ;\n\nselect * from activity_searches where id in (1977, 1978, 1979);\nselect * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);\nselect * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277\nselect * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879\n\nINSERT INTO `activity_search_filters`\n(`activity_search_id`, `filter`, `value`) VALUES\n(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')\n;\n\nselect * from crm_configurations where id = 39;\n\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\nselect * from features;\n\nSELECT * FROM activity_searches where id = 1982; # 1981\nSELECT * FROM activity_search_filters WHERE activity_search_id = 1982;\n\nSELECT * FROM automated_reports where id = 68;\nSELECT * FROM automated_report_results where id = 275;\n\nSELECT * FROM automated_reports order by id desc;\nSELECT * FROM automated_report_results order by id desc;\nselect * from activity_searches where user_id = 143;\nselect * from ask_anything_prompts;\n\nSELECT * FROM groups WHERE id = 1439;\nSELECT * FROM users WHERE group_id = 1439;\n\nselect * from permissions; # 158\nselect * from roles;\nselect * from permission_role\n\nselect * from teams where id = 1;\nselect * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;\nselect * from groups where id = 28;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 179;\nselect * from playbook_categories where id = 1391;\nselect * from users where id = 143;\nselect * from crm_profiles where user_id = 143;\nselect * from activities where crm_configuration_id = 39 and type = 'conference'\nand crm_provider_id IS NOT NULL ORDER by id desc;\nselect * from activities where id = 422003; # 00UO400000pB6fpMAC\n\nSELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type\nFROM automated_report_results ar\nJOIN automated_reports a ON a.id = ar.report_id\nWHERE a.type = 'ask_jiminny'\nLIMIT 10;\n\n\nselect * from teams where id = 3143;\nselect * from crm_configurations where id = 500;\nselect * from users where name = 'Integration Account'; # 1695\nSELECT * FROM social_accounts WHERE sociable_id = 1695;\n\nselect * from activities where crm_configuration_id = 39\nand status = 'completed' and actual_start_time >= '2025-01-01'","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-5696139294825716137
|
2146703024167786053
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
3
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Services\Kiosk\AutomatedReports;
use Carbon\CarbonImmutable;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityActualDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\ActivityUpdatedDate;
use Jiminny\Component\ActivitySearch\FilterDefinition\DealInsights\ClosingPeriodFilter;
use Jiminny\Component\ActivitySearch\FilterDefinitionCollection;
use Jiminny\Component\ActivitySearch\Service\ActivitySearch;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\Activity\SearchFilter;
use Jiminny\Models\User;
use Jiminny\Repositories\ElasticActivityRepository;
use Jiminny\Services\Kiosk\AutomatedReports\AskJiminnyReportActivityService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\VO\Repository\OnDemandActivitySearch\Criteria;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
class AskJiminnyReportActivityServiceTest extends TestCase
{
private ActivitySearch&MockObject $activitySearch;
private ElasticActivityRepository&MockObject $elasticRepository;
private LoggerInterface&MockObject $logger;
private AskJiminnyReportActivityService $service;
protected function setUp(): void
{
$this->activitySearch = $this->createMock(ActivitySearch::class);
$this->elasticRepository = $this->createMock(ElasticActivityRepository::class);
$this->logger = $this->createMock(LoggerInterface::class);
$this->service = new AskJiminnyReportActivityService(
$this->activitySearch,
$this->elasticRepository,
$this->logger,
);
}
private function makeFilter(string $key, ?string $value): SearchFilter&MockObject
{
$filter = $this->createMock(SearchFilter::class);
$filter->method('getFilterProperty')->willReturn($key);
$filter->method('getFilterValue')->willReturn($value);
return $filter;
}
private function makeUser(): User&MockObject
{
$tz = new \DateTimeZone('UTC');
$user = $this->createMock(User::class);
$user->method('getTimezone')->willReturn($tz);
$user->method('getId')->willReturn(1);
$user->method('getUuid')->willReturn('user-uuid');
return $user;
}
private function makeSavedSearch(array $filters): Search&MockObject
{
$savedSearch = $this->createMock(Search::class);
$savedSearch->method('getId')->willReturn(42);
$savedSearch->method('getFilters')->willReturn(new \Illuminate\Support\LazyCollection($filters));
return $savedSearch;
}
public function testGetActivityIdsForSavedSearchReturnsIds(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->expects($this->once())
->method('getArrayFilterKeys')
->with($user)
->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->expects($this->once())
->method('onDemandSearchIdsOnly')
->willReturn(['id-1', 'id-2', 'id-3']);
$this->logger->expects($this->once())
->method('info')
->with('[AskJiminnyReport] Fetched activity IDs for saved search');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1', 'id-2', 'id-3'], $result);
}
public function testGetActivityIdsForSavedSearchReturnsEmptyWhenNoResults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->expects($this->once())->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEmpty($result);
}
public function testGetActivityIdsFiltersOutDateFilters(): void
{
$user = $this->makeUser();
$nonDateFilter = $this->makeFilter('owner_id', '123');
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2025-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2025-01-31 23:59:59');
$updatedFromFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_FROM, '2025-01-01 00:00:00');
$updatedToFilter = $this->makeFilter(ActivityUpdatedDate::PARAM_UPDATED_TO, '2025-01-31 23:59:59');
$savedSearch = $this->makeSavedSearch([
$nonDateFilter,
$startDateFilter,
$endDateFilter,
$updatedFromFilter,
$updatedToFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
}
public function testGetActivityIdsFiltersOutClosingPeriodDateFilters(): void
{
$user = $this->makeUser();
$closingStartFilter = $this->makeFilter(ClosingPeriodFilter::KEY_START_DATE, '2025-01-01');
$closingEndFilter = $this->makeFilter(ClosingPeriodFilter::KEY_END_DATE, '2025-03-31');
$regularFilter = $this->makeFilter('rep_id', '99');
$savedSearch = $this->makeSavedSearch([
$closingStartFilter,
$closingEndFilter,
$regularFilter,
]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesArrayFilters(): void
{
$user = $this->makeUser();
$filter1 = $this->makeFilter('outcome', 'positive');
$filter2 = $this->makeFilter('outcome', 'negative');
$savedSearch = $this->makeSavedSearch([$filter1, $filter2]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn(['outcome']);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-1']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-1'], $result);
}
public function testGetActivityIdsHandlesScalarFilters(): void
{
$user = $this->makeUser();
$filter = $this->makeFilter('direction', 'inbound');
$savedSearch = $this->makeSavedSearch([$filter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['id-5']);
$this->logger->method('info');
$result = $this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertEquals(['id-5'], $result);
}
public function testGetActivityIdsPassesNonZeroSequenceNumberToDisableFirstRequestDefaults(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$this->logger->method('info');
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
$this->assertNotNull($capturedCriteria);
$this->assertFalse($capturedCriteria->isFirstRequest());
}
public function testGetActivityIdsLogsWithCorrectContext(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->activitySearch->method('getOnDemandPageFilterSet')->willReturn($filterSet);
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn(['a', 'b']);
$this->logger->expects($this->once())
->method('info')
->with(
'[AskJiminnyReport] Fetched activity IDs for saved search',
$this->callback(fn ($context) => $context['saved_search_id'] === 42
&& $context['user_id'] === 1
&& $context['activity_count'] === 2)
);
$this->service->getActivityIdsForSavedSearch($savedSearch, $user);
}
public static function frequencyDateRangeProvider(): array
{
return [
'daily' => [
AutomatedReportsService::FREQUENCY_DAILY,
'2025-06-15 00:00:00',
'2025-06-15 23:59:59',
],
'weekly' => [
AutomatedReportsService::FREQUENCY_WEEKLY,
'2025-06-09 00:00:00',
'2025-06-15 23:59:59',
],
'monthly' => [
AutomatedReportsService::FREQUENCY_MONTHLY,
'2025-05-01 00:00:00',
'2025-05-31 23:59:59',
],
'quarterly' => [
AutomatedReportsService::FREQUENCY_QUARTERLY,
'2025-01-01 00:00:00',
'2025-03-31 23:59:59',
],
];
}
/**
* @dataProvider frequencyDateRangeProvider
*/
public function testGetActivityIdsInjectsDateRangeForFrequency(
string $frequency,
string $expectedStartDate,
string $expectedEndDate,
): void {
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, $frequency);
$this->assertNotNull($capturedCriteria);
$this->assertSame($expectedStartDate, $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame($expectedEndDate, $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
public function testGetActivityIdsWithNullFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, null);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsWithUnknownFrequencyDoesNotInjectDates(): void
{
$user = $this->makeUser();
$savedSearch = $this->makeSavedSearch([]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_ONE_OFF);
$this->assertNotNull($capturedCriteria);
$this->assertNull($capturedCriteria->getStartDate());
$this->assertNull($capturedCriteria->getEndDate());
}
public function testGetActivityIdsFrequencyDateRangeOverridesSavedSearchDateFilters(): void
{
CarbonImmutable::setTestNow('2025-06-16 12:00:00');
try {
$user = $this->makeUser();
$startDateFilter = $this->makeFilter(ActivityActualDate::PARAM_START_DATE, '2024-01-01 00:00:00');
$endDateFilter = $this->makeFilter(ActivityActualDate::PARAM_END_DATE, '2024-12-31 23:59:59');
$savedSearch = $this->makeSavedSearch([$startDateFilter, $endDateFilter]);
$filterSet = $this->createMock(FilterDefinitionCollection::class);
$this->activitySearch->method('getArrayFilterKeys')->willReturn([]);
$this->logger->method('info');
$this->elasticRepository->method('onDemandSearchIdsOnly')->willReturn([]);
$capturedCriteria = null;
$this->activitySearch->expects($this->once())
->method('getOnDemandPageFilterSet')
->willReturnCallback(function (Criteria $criteria) use ($filterSet, &$capturedCriteria) {
$capturedCriteria = $criteria;
return $filterSet;
});
$this->service->getActivityIdsForSavedSearch($savedSearch, $user, AutomatedReportsService::FREQUENCY_DAILY);
$this->assertNotNull($capturedCriteria);
$this->assertSame('2025-06-15 00:00:00', $capturedCriteria->getStartDate()->format('Y-m-d H:i:s'));
$this->assertSame('2025-06-15 23:59:59', $capturedCriteria->getEndDate()->format('Y-m-d H:i:s'));
} finally {
CarbonImmutable::setTestNow();
}
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
9
12
2
4
Previous Highlighted Error
Next Highlighted Error
SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o
JOIN activities a ON o.id = a.opportunity_id
WHERE a.crm_configuration_id = 39
AND a.actual_start_time > '2025-10-13'
AND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM activities
WHERE crm_configuration_id = 39 and user_id = 143
and actual_start_time >= '2025-10-13'
AND type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM opportunities WHERE account_id IN (178);
select * from activities where id IN (620137, 620187, 620188, 620189, 620230);
# HS
SELECT * FROM opportunities WHERE id IN (238);
select * from activities where id IN (477,2076);
select * from users;
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM activities;
SELECT COUNT(*) FROM opportunities;
UPDATE activities
SET
actual_start_time = '2025-12-19 09:00:00',
actual_end_time = '2025-12-19 10:30:00',
scheduled_start_time = '2025-12-19 09:00:00',
scheduled_end_time = '2025-12-19 10:30:00'
WHERE id IN (407509,407375);
select * from partners;
SELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id
FROM activities
WHERE user_id = 143
AND actual_start_time >= '2025-10-13 00:00:00'
AND actual_start_time <= '2026-01-13 23:59:59'
ORDER BY actual_start_time DESC;
SELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;
SELECT * FROM crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;
# lead_id
# account_id 177
# contact_id 3969
# opportunity_id
# stage_id 203
SELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;
SELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'
AND user_id = 143 and actual_start_time >= '2025-10-13';
SELECT * FROM activities a
# JOIN opportunities o ON a.opportunity_id = o.id
WHERE a.crm_configuration_id = 39 AND a.type = 'conference'
and status = 'completed' and recording_state = 'recorded'
and a.actual_start_time >= '2025-10-13'
AND a.user_id = 143
;
select * from leads
where crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310);
SELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198
SELECT * FROM activities WHERE id IN (356001, 356008); # contacts:
SELECT * FROM opportunities WHERE id IN (1707);
SELECT * FROM stages where id IN (204, 198);
SELECT * FROM opportunities WHERE account_id IN (178);
SELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';
SELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal
SELECT * FROM activities where crm_configuration_id = 39
AND opportunity_id IS NULL
AND is_internal = false
and status = 'completed' and recording_state = 'recorded'
AND actual_start_time >= '2025-10-13'
AND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)
# AND lead_id IN (112, 109)
;
SELECT * FROM crm_profiles WHERE user_id = 143;
select * from inboxes; # 212
select * from users where id = 143; # 143
select * from inbox_email_batches where inbox_id = 212
and updated_at >= '2026-01-28 00:00:00' order by id desc;
select * from inbox_emails where inbox_id = 212
and batch_id = 95885 order by id desc;
select * from email_messages where origin_user_id = 143;
select * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';
select * from participants where activity_id = 620247;
select * from crm_profiles where user_id = 143;
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001
select * from transcription where activity_id = 356001; # 6943
select * from ai_prompts where transcription_id = 6943;
SELECT * FROM activity_summary_logs where activity_id = 356001;
SELECT * FROM social_accounts WHERE sociable_id = 143;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;
# 422515 softphone tr. 8100
SELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;
# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS
select * from ai_prompts where transcription_id IN (8100, 7670);
select * from activity_summary_logs where activity_id = 407509;
select * from sidekick_settings;
select * from default_activity_types;
SELECT * FROM contacts WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM leads WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM activity_searches where user_id = 143;
SELECT * FROM groups where team_id = 1;
select * from teams where id = 1;
select * from groups where team_id = 1; # 1150 - 7e75f8025c22
select id, name, group_id, status, deleted_at, email
from users where team_id = 1 order by group_id desc ;
select * from activity_searches where id in (1977, 1978, 1979);
select * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);
select * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277
select * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879
INSERT INTO `activity_search_filters`
(`activity_search_id`, `filter`, `value`) VALUES
(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')
;
select * from crm_configurations where id = 39;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from features;
SELECT * FROM activity_searches where id = 1982; # 1981
SELECT * FROM activity_search_filters WHERE activity_search_id = 1982;
SELECT * FROM automated_reports where id = 68;
SELECT * FROM automated_report_results where id = 275;
SELECT * FROM automated_reports order by id desc;
SELECT * FROM automated_report_results order by id desc;
select * from activity_searches where user_id = 143;
select * from ask_anything_prompts;
SELECT * FROM groups WHERE id = 1439;
SELECT * FROM users WHERE group_id = 1439;
select * from permissions; # 158
select * from roles;
select * from permission_role
select * from teams where id = 1;
select * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;
select * from groups where id = 28;
select * from playbooks where team_id = 1;
select * from playbooks where id = 179;
select * from playbook_categories where id = 1391;
select * from users where id = 143;
select * from crm_profiles where user_id = 143;
select * from activities where crm_configuration_id = 39 and type = 'conference'
and crm_provider_id IS NOT NULL ORDER by id desc;
select * from activities where id = 422003; # 00UO400000pB6fpMAC
SELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type
FROM automated_report_results ar
JOIN automated_reports a ON a.id = ar.report_id
WHERE a.type = 'ask_jiminny'
LIMIT 10;
select * from teams where id = 3143;
select * from crm_configurations where id = 500;
select * from users where name = 'Integration Account'; # 1695
SELECT * FROM social_accounts WHERE sociable_id = 1695;
select * from activities where crm_configuration_id = 39
and status = 'completed' and actual_start_time >= '2025-01-01'
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
54642
|
|
54588
|
NULL
|
0
|
2026-04-20T09:06:37.882284+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776675997882_m1.jpg...
|
iTerm2
|
-zsh
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Last login: Mon Apr 20 10:16:57 on ttys010
Poetry Last login: Mon Apr 20 10:16:57 on ttys010
Poetry could not find a pyproject.toml file in /Users/lukas or its parents
Poetry could not find a pyproject.toml file in /Users/lukas or its parents
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ du -sh ~/.screenpipe
8.8G /Users/lukas/.screenpipe
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ du -sh ~/.screenpipe/*
4.0K /Users/lukas/.screenpipe/config.json
4.9G /Users/lukas/.screenpipe/data
3.9G /Users/lukas/.screenpipe/db.sqlite
64K /Users/lukas/.screenpipe/db.sqlite-shm
15M /Users/lukas/.screenpipe/db.sqlite-wal
36K /Users/lukas/.screenpipe/pipes
132K /Users/lukas/.screenpipe/screenpipe.2026-04-09.0.log
96K /Users/lukas/.screenpipe/screenpipe.2026-04-11.0.log
72K /Users/lukas/.screenpipe/screenpipe.2026-04-12.0.log
72K /Users/lukas/.screenpipe/screenpipe.2026-04-13.0.log
160K /Users/lukas/.screenpipe/screenpipe.2026-04-14.0.log
172K /Users/lukas/.screenpipe/screenpipe.2026-04-15.0.log
196K /Users/lukas/.screenpipe/screenpipe.2026-04-16.0.log
204K /Users/lukas/.screenpipe/screenpipe.2026-04-17.0.log
64K /Users/lukas/.screenpipe/screenpipe.2026-04-18.0.log
196K /Users/lukas/.screenpipe/screenpipe.2026-04-20.0.log
16K /Users/lukas/.screenpipe/screenpipe_sync.sh
24K /Users/lukas/.screenpipe/sync.log
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $
DOCKER
Close Tab
DEV (docker)
Close Tab
APP (-zsh)
Close Tab
-zsh
Close Tab
screenpipe"
Close Tab
-zsh
Close Tab
⌥⌘1
-zsh...
|
[{"role":"AXTextArea","text [{"role":"AXTextArea","text":"Last login: Mon Apr 20 10:16:57 on ttys010\n\nPoetry could not find a pyproject.toml file in /Users/lukas or its parents\n\nPoetry could not find a pyproject.toml file in /Users/lukas or its parents\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ du -sh ~/.screenpipe \n8.8G\u0000\u0000\u0000\t/Users/lukas/.screenpipe\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ du -sh ~/.screenpipe/*\n4.0K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/config.json\n4.9G\u0000\u0000\u0000\t/Users/lukas/.screenpipe/data\n3.9G\u0000\u0000\u0000\t/Users/lukas/.screenpipe/db.sqlite\n 64K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/db.sqlite-shm\n 15M\u0000\u0000\u0000\t/Users/lukas/.screenpipe/db.sqlite-wal\n 36K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/pipes\n132K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-09.0.log\n 96K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-11.0.log\n 72K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-12.0.log\n 72K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-13.0.log\n160K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-14.0.log\n172K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-15.0.log\n196K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-16.0.log\n204K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-17.0.log\n 64K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-18.0.log\n196K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-20.0.log\n 16K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe_sync.sh\n 24K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/sync.log\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $","depth":4,"bounds":{"left":0.0,"top":0.08777778,"width":1.0,"height":0.9122222},"value":"Last login: Mon Apr 20 10:16:57 on ttys010\n\nPoetry could not find a pyproject.toml file in /Users/lukas or its parents\n\nPoetry could not find a pyproject.toml file in /Users/lukas or its parents\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ du -sh ~/.screenpipe \n8.8G\u0000\u0000\u0000\t/Users/lukas/.screenpipe\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ du -sh ~/.screenpipe/*\n4.0K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/config.json\n4.9G\u0000\u0000\u0000\t/Users/lukas/.screenpipe/data\n3.9G\u0000\u0000\u0000\t/Users/lukas/.screenpipe/db.sqlite\n 64K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/db.sqlite-shm\n 15M\u0000\u0000\u0000\t/Users/lukas/.screenpipe/db.sqlite-wal\n 36K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/pipes\n132K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-09.0.log\n 96K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-11.0.log\n 72K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-12.0.log\n 72K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-13.0.log\n160K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-14.0.log\n172K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-15.0.log\n196K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-16.0.log\n204K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-17.0.log\n 64K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-18.0.log\n196K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-20.0.log\n 16K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe_sync.sh\n 24K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/sync.log\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $","is_focused":true},{"role":"AXRadioButton","text":"DOCKER","depth":2,"bounds":{"left":0.0,"top":0.05888889,"width":0.16458334,"height":0.026666667},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.004166667,"top":0.06333333,"width":0.011111111,"height":0.017777778},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"DEV (docker)","depth":2,"bounds":{"left":0.16458334,"top":0.05888889,"width":0.16458334,"height":0.026666667},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.16875,"top":0.06333333,"width":0.011111111,"height":0.017777778},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"APP (-zsh)","depth":2,"bounds":{"left":0.32916668,"top":0.05888889,"width":0.16423611,"height":0.026666667},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.33333334,"top":0.06333333,"width":0.011111111,"height":0.017777778},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"-zsh","depth":2,"bounds":{"left":0.49340278,"top":0.05888889,"width":0.16423611,"height":0.026666667},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.49756944,"top":0.06333333,"width":0.011111111,"height":0.017777778},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"screenpipe\"","depth":2,"bounds":{"left":0.6576389,"top":0.05888889,"width":0.16423611,"height":0.026666667},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.66180557,"top":0.06333333,"width":0.011111111,"height":0.017777778},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"-zsh","depth":2,"bounds":{"left":0.821875,"top":0.05888889,"width":0.16423611,"height":0.026666667},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.82604164,"top":0.06333333,"width":0.011111111,"height":0.017777778},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"⌥⌘1","depth":1,"bounds":{"left":0.95763886,"top":0.032222223,"width":0.03888889,"height":0.018888889},"automation_id":"_NS:8","role_description":"text"},{"role":"AXStaticText","text":"-zsh","depth":1,"bounds":{"left":0.48958334,"top":0.033333335,"width":0.022916667,"height":0.017777778},"role_description":"text"}]...
|
3394355443974518968
|
-3061367755569443119
|
visual_change
|
accessibility
|
NULL
|
Last login: Mon Apr 20 10:16:57 on ttys010
Poetry Last login: Mon Apr 20 10:16:57 on ttys010
Poetry could not find a pyproject.toml file in /Users/lukas or its parents
Poetry could not find a pyproject.toml file in /Users/lukas or its parents
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ du -sh ~/.screenpipe
8.8G /Users/lukas/.screenpipe
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ du -sh ~/.screenpipe/*
4.0K /Users/lukas/.screenpipe/config.json
4.9G /Users/lukas/.screenpipe/data
3.9G /Users/lukas/.screenpipe/db.sqlite
64K /Users/lukas/.screenpipe/db.sqlite-shm
15M /Users/lukas/.screenpipe/db.sqlite-wal
36K /Users/lukas/.screenpipe/pipes
132K /Users/lukas/.screenpipe/screenpipe.2026-04-09.0.log
96K /Users/lukas/.screenpipe/screenpipe.2026-04-11.0.log
72K /Users/lukas/.screenpipe/screenpipe.2026-04-12.0.log
72K /Users/lukas/.screenpipe/screenpipe.2026-04-13.0.log
160K /Users/lukas/.screenpipe/screenpipe.2026-04-14.0.log
172K /Users/lukas/.screenpipe/screenpipe.2026-04-15.0.log
196K /Users/lukas/.screenpipe/screenpipe.2026-04-16.0.log
204K /Users/lukas/.screenpipe/screenpipe.2026-04-17.0.log
64K /Users/lukas/.screenpipe/screenpipe.2026-04-18.0.log
196K /Users/lukas/.screenpipe/screenpipe.2026-04-20.0.log
16K /Users/lukas/.screenpipe/screenpipe_sync.sh
24K /Users/lukas/.screenpipe/sync.log
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $
DOCKER
Close Tab
DEV (docker)
Close Tab
APP (-zsh)
Close Tab
-zsh
Close Tab
screenpipe"
Close Tab
-zsh
Close Tab
⌥⌘1
-zsh...
|
NULL
|
|
54587
|
NULL
|
0
|
2026-04-20T09:06:35.645363+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776675995645_m2.jpg...
|
iTerm2
|
-zsh
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Last login: Mon Apr 20 10:16:57 on ttys010
Poetry Last login: Mon Apr 20 10:16:57 on ttys010
Poetry could not find a pyproject.toml file in /Users/lukas or its parents
Poetry could not find a pyproject.toml file in /Users/lukas or its parents
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ du -sh ~/.screenpipe
8.8G /Users/lukas/.screenpipe
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ du -sh ~/.screenpipe/*
4.0K /Users/lukas/.screenpipe/config.json
4.9G /Users/lukas/.screenpipe/data
3.9G /Users/lukas/.screenpipe/db.sqlite
64K /Users/lukas/.screenpipe/db.sqlite-shm
15M /Users/lukas/.screenpipe/db.sqlite-wal
36K /Users/lukas/.screenpipe/pipes
132K /Users/lukas/.screenpipe/screenpipe.2026-04-09.0.log
96K /Users/lukas/.screenpipe/screenpipe.2026-04-11.0.log
72K /Users/lukas/.screenpipe/screenpipe.2026-04-12.0.log
72K /Users/lukas/.screenpipe/screenpipe.2026-04-13.0.log
160K /Users/lukas/.screenpipe/screenpipe.2026-04-14.0.log
172K /Users/lukas/.screenpipe/screenpipe.2026-04-15.0.log
196K /Users/lukas/.screenpipe/screenpipe.2026-04-16.0.log
204K /Users/lukas/.screenpipe/screenpipe.2026-04-17.0.log
64K /Users/lukas/.screenpipe/screenpipe.2026-04-18.0.log
196K /Users/lukas/.screenpipe/screenpipe.2026-04-20.0.log
16K /Users/lukas/.screenpipe/screenpipe_sync.sh
24K /Users/lukas/.screenpipe/sync.log
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $
DOCKER
Close Tab
DEV (docker)
Close Tab
APP (-zsh)
Close Tab
-zsh
Close Tab
screenpipe"
Close Tab
-zsh
Close Tab
⌥⌘1
-zsh...
|
[{"role":"AXTextArea","text [{"role":"AXTextArea","text":"Last login: Mon Apr 20 10:16:57 on ttys010\n\nPoetry could not find a pyproject.toml file in /Users/lukas or its parents\n\nPoetry could not find a pyproject.toml file in /Users/lukas or its parents\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ du -sh ~/.screenpipe \n8.8G\u0000\u0000\u0000\t/Users/lukas/.screenpipe\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ du -sh ~/.screenpipe/*\n4.0K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/config.json\n4.9G\u0000\u0000\u0000\t/Users/lukas/.screenpipe/data\n3.9G\u0000\u0000\u0000\t/Users/lukas/.screenpipe/db.sqlite\n 64K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/db.sqlite-shm\n 15M\u0000\u0000\u0000\t/Users/lukas/.screenpipe/db.sqlite-wal\n 36K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/pipes\n132K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-09.0.log\n 96K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-11.0.log\n 72K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-12.0.log\n 72K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-13.0.log\n160K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-14.0.log\n172K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-15.0.log\n196K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-16.0.log\n204K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-17.0.log\n 64K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-18.0.log\n196K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-20.0.log\n 16K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe_sync.sh\n 24K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/sync.log\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.4800532,"height":-0.06304872},"value":"Last login: Mon Apr 20 10:16:57 on ttys010\n\nPoetry could not find a pyproject.toml file in /Users/lukas or its parents\n\nPoetry could not find a pyproject.toml file in /Users/lukas or its parents\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ du -sh ~/.screenpipe \n8.8G\u0000\u0000\u0000\t/Users/lukas/.screenpipe\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ du -sh ~/.screenpipe/*\n4.0K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/config.json\n4.9G\u0000\u0000\u0000\t/Users/lukas/.screenpipe/data\n3.9G\u0000\u0000\u0000\t/Users/lukas/.screenpipe/db.sqlite\n 64K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/db.sqlite-shm\n 15M\u0000\u0000\u0000\t/Users/lukas/.screenpipe/db.sqlite-wal\n 36K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/pipes\n132K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-09.0.log\n 96K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-11.0.log\n 72K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-12.0.log\n 72K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-13.0.log\n160K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-14.0.log\n172K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-15.0.log\n196K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-16.0.log\n204K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-17.0.log\n 64K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-18.0.log\n196K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe.2026-04-20.0.log\n 16K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/screenpipe_sync.sh\n 24K\u0000\u0000\u0000\t/Users/lukas/.screenpipe/sync.log\nlukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $","is_focused":true},{"role":"AXRadioButton","text":"DOCKER","depth":2,"bounds":{"left":0.27027926,"top":1.0,"width":0.0787899,"height":-0.042298436},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.27227393,"top":1.0,"width":0.005319149,"height":-0.04549086},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"DEV (docker)","depth":2,"bounds":{"left":0.34906915,"top":1.0,"width":0.0787899,"height":-0.042298436},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.35106382,"top":1.0,"width":0.005319149,"height":-0.04549086},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"APP (-zsh)","depth":2,"bounds":{"left":0.42785904,"top":1.0,"width":0.07862367,"height":-0.042298436},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.42985374,"top":1.0,"width":0.005319149,"height":-0.04549086},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"-zsh","depth":2,"bounds":{"left":0.5064827,"top":1.0,"width":0.07862367,"height":-0.042298436},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.5084774,"top":1.0,"width":0.005319149,"height":-0.04549086},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"screenpipe\"","depth":2,"bounds":{"left":0.5851064,"top":1.0,"width":0.07862367,"height":-0.042298436},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.58710104,"top":1.0,"width":0.005319149,"height":-0.04549086},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXRadioButton","text":"-zsh","depth":2,"bounds":{"left":0.66373,"top":1.0,"width":0.07862367,"height":-0.042298436},"role_description":"radio button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Close Tab","depth":3,"bounds":{"left":0.66572475,"top":1.0,"width":0.005319149,"height":-0.04549086},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"⌥⌘1","depth":1,"bounds":{"left":0.7287234,"top":1.0,"width":0.01861702,"height":-0.023144484},"automation_id":"_NS:8","role_description":"text"},{"role":"AXStaticText","text":"-zsh","depth":1,"bounds":{"left":0.5046542,"top":1.0,"width":0.010970744,"height":-0.02394259},"role_description":"text"}]...
|
3394355443974518968
|
-3061367755569443119
|
visual_change
|
accessibility
|
NULL
|
Last login: Mon Apr 20 10:16:57 on ttys010
Poetry Last login: Mon Apr 20 10:16:57 on ttys010
Poetry could not find a pyproject.toml file in /Users/lukas or its parents
Poetry could not find a pyproject.toml file in /Users/lukas or its parents
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ du -sh ~/.screenpipe
8.8G /Users/lukas/.screenpipe
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $ du -sh ~/.screenpipe/*
4.0K /Users/lukas/.screenpipe/config.json
4.9G /Users/lukas/.screenpipe/data
3.9G /Users/lukas/.screenpipe/db.sqlite
64K /Users/lukas/.screenpipe/db.sqlite-shm
15M /Users/lukas/.screenpipe/db.sqlite-wal
36K /Users/lukas/.screenpipe/pipes
132K /Users/lukas/.screenpipe/screenpipe.2026-04-09.0.log
96K /Users/lukas/.screenpipe/screenpipe.2026-04-11.0.log
72K /Users/lukas/.screenpipe/screenpipe.2026-04-12.0.log
72K /Users/lukas/.screenpipe/screenpipe.2026-04-13.0.log
160K /Users/lukas/.screenpipe/screenpipe.2026-04-14.0.log
172K /Users/lukas/.screenpipe/screenpipe.2026-04-15.0.log
196K /Users/lukas/.screenpipe/screenpipe.2026-04-16.0.log
204K /Users/lukas/.screenpipe/screenpipe.2026-04-17.0.log
64K /Users/lukas/.screenpipe/screenpipe.2026-04-18.0.log
196K /Users/lukas/.screenpipe/screenpipe.2026-04-20.0.log
16K /Users/lukas/.screenpipe/screenpipe_sync.sh
24K /Users/lukas/.screenpipe/sync.log
lukas@Lukas-Kovaliks-MacBook-Pro-Jiminny ~ $
DOCKER
Close Tab
DEV (docker)
Close Tab
APP (-zsh)
Close Tab
-zsh
Close Tab
screenpipe"
Close Tab
-zsh
Close Tab
⌥⌘1
-zsh...
|
54584
|
|
54503
|
NULL
|
0
|
2026-04-20T09:01:53.535017+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776675713535_m1.jpg...
|
PhpStorm
|
faVsco.js – RequestGenerateAskJiminnyReportJobTest faVsco.js – RequestGenerateAskJiminnyReportJobTest.php...
|
True
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
RequestGenerateAskJiminnyReportJobTest
Run 'RequestGenerateAskJiminnyReportJobTest'
Debug 'RequestGenerateAskJiminnyReportJobTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
14
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\AutomatedReports;
use Carbon\Carbon;
use Jiminny\Component\ProphetAi\Exceptions\ProphetException;
use Jiminny\Component\ProphetAi\ProphetClient;
use Jiminny\Jobs\AutomatedReports\RequestGenerateAskJiminnyReportJob;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AskJiminnyReportActivityService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
class RequestGenerateAskJiminnyReportJobTest extends TestCase
{
private AutomatedReportsService&MockObject $reportService;
private AskJiminnyReportActivityService&MockObject $activityService;
private ProphetClient&MockObject $prophetClient;
private LoggerInterface&MockObject $logger;
protected function setUp(): void
{
$this->reportService = $this->createMock(AutomatedReportsService::class);
$this->activityService = $this->createMock(AskJiminnyReportActivityService::class);
$this->prophetClient = $this->createMock(ProphetClient::class);
$this->logger = $this->createMock(LoggerInterface::class);
}
private function makeJob(string $uuid = 'report-uuid'): RequestGenerateAskJiminnyReportJob
{
return new RequestGenerateAskJiminnyReportJob($uuid);
}
private function makeActiveReport(
string $type = AutomatedReportsService::TYPE_ASK_JIMINNY,
bool $status = true,
string $teamStatus = Team::STATUS_ACTIVE,
): AutomatedReport&MockObject { // @phpstan-ignore-line
$team = $this->createMock(Team::class);
$team->method('getStatus')->willReturn($teamStatus);
$report = $this->createMock(AutomatedReport::class);
$report->method('getType')->willReturn($type);
$report->method('getStatus')->willReturn($status);
$report->method('getTeam')->willReturn($team);
return $report;
}
public function testUniqueIdReturnsReportUuid(): void
{
$job = $this->makeJob('my-unique-uuid');
$this->assertEquals('my-unique-uuid', $job->uniqueId());
}
public function testHandleSkipsWhenReportTypeIsNotAskJiminny(): void
{
$report = $this->makeActiveReport(type: 'exec_summary');
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->once())
->method('info')
->with($this->stringContains('Started'));
$this->logger->expects($this->once())
->method('warning')
->with($this->stringContains('not an ask_jiminny report'));
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSkipsWhenReportIsInactive(): void
{
$report = $this->makeActiveReport(status: false);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->exactly(2))
->method('info');
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSkipsWhenTeamIsInactive(): void
{
$report = $this->makeActiveReport(teamStatus: Team::STATUS_DEACTIVATED);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->exactly(2))
->method('info');
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSkipsWhenCreatorIsNull(): void
{
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn(null);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->once())
->method('warning')
->with($this->stringContains('report creator not found'));
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSkipsWhenSavedSearchIsNull(): void
{
$creator = $this->createMock(User::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn(null);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->once())
->method('warning')
->with($this->stringContains('saved search not found'));
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSkipsWhenPromptIsNull(): void
{
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn(null);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->once())
->method('warning')
->with($this->stringContains('ask anything prompt not found'));
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleFailsReportWhenNotEnoughActivities(): void
{
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$prompt = $this->createMock(\Jiminny\Models\AskAnything\AskAnythingPrompt::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn($prompt);
$reportResult = $this->createMock(AutomatedReportResult::class);
$reportResult->expects($this->once())
->method('update')
->with($this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_FAILED
&& $data['reason'] === AutomatedReportResult::REASON_NOT_ENOUGH_ACTIVITIES));
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->reportService->expects($this->once())
->method('getOrCreateReportResult')
->willReturn($reportResult);
$this->activityService->expects($this->once())
->method('getActivityIdsForSavedSearch')
->willReturn([]);
$this->logger->expects($this->exactly(3))
->method('info');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSuccessfullyRequestsReport(): void
{
Carbon::setTestNow(Carbon::parse('2026-04-07 10:00:00'));
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$prompt = $this->createMock(\Jiminny\Models\AskAnything\AskAnythingPrompt::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn($prompt);
$report->method('getUuid')->willReturn('report-uuid');
$reportResult = $this->createMock(AutomatedReportResult::class);
$reportResult->method('getUuid')->willReturn('result-uuid');
$reportResult->expects($this->once())
->method('update')
->with($this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_REQUESTED
&& isset($data['name'], $data['payload'], $data['requested_at'])));
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->reportService->expects($this->once())
->method('getOrCreateReportResult')
->willReturn($reportResult);
$this->reportService->expects($this->once())
->method('getAskJiminnyGenerateReportPayload')
->willReturn(['key' => 'value']);
$this->reportService->expects($this->once())
->method('getReportFileName')
->willReturn('My Report - 7 Apr 2026');
$this->activityService->expects($this->once())
->method('getActivityIdsForSavedSearch')
->willReturn(['act-1', 'act-2']);
$this->prophetClient->expects($this->once())
->method('sendRequest')
->willReturn(new \Jiminny\Component\ProphetAi\Dtos\ProphetResponseDto([]));
$this->logger->expects($this->exactly(4))
->method('info');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
Carbon::setTestNow();
}
public function testHandleCatchesGenericExceptionAndLogsError(): void
{
$this->reportService->expects($this->once())
->method('getReport')
->willThrowException(new \RuntimeException('DB error'));
$this->logger->expects($this->once())
->method('error')
->with($this->stringContains('Error'));
$job = $this->makeJob();
$reflection = new \ReflectionClass($job);
$triesProp = $reflection->getProperty('tries');
$triesProp->setAccessible(true);
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleCatchesProphetExceptionAndSetsCorrectReason(): void
{
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$prompt = $this->createMock(\Jiminny\Models\AskAnything\AskAnythingPrompt::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn($prompt);
$reportResult = $this->createMock(AutomatedReportResult::class);
$reportResult->method('getUuid')->willReturn('result-uuid');
$reportResult->expects($this->once())
->method('update')
->with($this->callback(fn ($data) => $data['reason'] === AutomatedReportResult::REASON_PROPHET_API_ERROR));
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->reportService->expects($this->once())
->method('getOrCreateReportResult')
->willReturn($reportResult);
$this->activityService->expects($this->once())
->method('getActivityIdsForSavedSearch')
->willThrowException(new ProphetException('Prophet failed'));
$this->logger->expects($this->once())
->method('error');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleCreatesReportResultBeforeActivityFetch(): void
{
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$prompt = $this->createMock(\Jiminny\Models\AskAnything\AskAnythingPrompt::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn($prompt);
$reportResult = $this->createMock(AutomatedReportResult::class);
$reportResult->method('getUuid')->willReturn('result-uuid');
$callOrder = [];
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->reportService->expects($this->once())
->method('getOrCreateReportResult')
->willReturnCallback(function () use ($reportResult, &$callOrder) {
$callOrder[] = 'getOrCreateReportResult';
return $reportResult;
});
$this->activityService->expects($this->once())
->method('getActivityIdsForSavedSearch')
->willReturnCallback(function () use (&$callOrder) {
$callOrder[] = 'getActivityIds';
return [];
});
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
$this->assertEquals(['getOrCreateReportResult', 'getActivityIds'], $callOrder);
}
public function testHandlePassesCorrectDataToCreateReportResult(): void
{
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$prompt = $this->createMock(\Jiminny\Models\AskAnything\AskAnythingPrompt::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn($prompt);
$reportResult = $this->createMock(AutomatedReportResult::class);
$reportResult->method('getUuid')->willReturn('result-uuid');
$reportResult->method('update')->willReturn(true);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->reportService->expects($this->once())
->method('getOrCreateReportResult')
->with(
automatedReport: $report,
data: $this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_DEFAULT
&& $data['media_type'] === AutomatedReportsService::MEDIA_TYPE_PDF)
)
->willReturn($reportResult);
$this->activityService->expects($this->once())
->method('getActivityIdsForSavedSearch')
->willReturn([]);
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
9
12
2
4
Previous Highlighted Error
Next Highlighted Error
SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o
JOIN activities a ON o.id = a.opportunity_id
WHERE a.crm_configuration_id = 39
AND a.actual_start_time > '2025-10-13'
AND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM activities
WHERE crm_configuration_id = 39 and user_id = 143
and actual_start_time >= '2025-10-13'
AND type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM opportunities WHERE account_id IN (178);
select * from activities where id IN (620137, 620187, 620188, 620189, 620230);
# HS
SELECT * FROM opportunities WHERE id IN (238);
select * from activities where id IN (477,2076);
select * from users;
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM activities;
SELECT COUNT(*) FROM opportunities;
UPDATE activities
SET
actual_start_time = '2025-12-19 09:00:00',
actual_end_time = '2025-12-19 10:30:00',
scheduled_start_time = '2025-12-19 09:00:00',
scheduled_end_time = '2025-12-19 10:30:00'
WHERE id IN (407509,407375);
select * from partners;
SELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id
FROM activities
WHERE user_id = 143
AND actual_start_time >= '2025-10-13 00:00:00'
AND actual_start_time <= '2026-01-13 23:59:59'
ORDER BY actual_start_time DESC;
SELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;
SELECT * FROM crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;
# lead_id
# account_id 177
# contact_id 3969
# opportunity_id
# stage_id 203
SELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;
SELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'
AND user_id = 143 and actual_start_time >= '2025-10-13';
SELECT * FROM activities a
# JOIN opportunities o ON a.opportunity_id = o.id
WHERE a.crm_configuration_id = 39 AND a.type = 'conference'
and status = 'completed' and recording_state = 'recorded'
and a.actual_start_time >= '2025-10-13'
AND a.user_id = 143
;
select * from leads
where crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310);
SELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198
SELECT * FROM activities WHERE id IN (356001, 356008); # contacts:
SELECT * FROM opportunities WHERE id IN (1707);
SELECT * FROM stages where id IN (204, 198);
SELECT * FROM opportunities WHERE account_id IN (178);
SELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';
SELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal
SELECT * FROM activities where crm_configuration_id = 39
AND opportunity_id IS NULL
AND is_internal = false
and status = 'completed' and recording_state = 'recorded'
AND actual_start_time >= '2025-10-13'
AND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)
# AND lead_id IN (112, 109)
;
SELECT * FROM crm_profiles WHERE user_id = 143;
select * from inboxes; # 212
select * from users where id = 143; # 143
select * from inbox_email_batches where inbox_id = 212
and updated_at >= '2026-01-28 00:00:00' order by id desc;
select * from inbox_emails where inbox_id = 212
and batch_id = 95885 order by id desc;
select * from email_messages where origin_user_id = 143;
select * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';
select * from participants where activity_id = 620247;
select * from crm_profiles where user_id = 143;
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001
select * from transcription where activity_id = 356001; # 6943
select * from ai_prompts where transcription_id = 6943;
SELECT * FROM activity_summary_logs where activity_id = 356001;
SELECT * FROM social_accounts WHERE sociable_id = 143;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;
# 422515 softphone tr. 8100
SELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;
# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS
select * from ai_prompts where transcription_id IN (8100, 7670);
select * from activity_summary_logs where activity_id = 407509;
select * from sidekick_settings;
select * from default_activity_types;
SELECT * FROM contacts WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM leads WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM activity_searches where user_id = 143;
SELECT * FROM groups where team_id = 1;
select * from teams where id = 1;
select * from groups where team_id = 1; # 1150 - 7e75f8025c22
select id, name, group_id, status, deleted_at, email
from users where team_id = 1 order by group_id desc ;
select * from activity_searches where id in (1977, 1978, 1979);
select * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);
select * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277
select * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879
INSERT INTO `activity_search_filters`
(`activity_search_id`, `filter`, `value`) VALUES
(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')
;
select * from crm_configurations where id = 39;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from features;
SELECT * FROM activity_searches where id = 1982; # 1981
SELECT * FROM activity_search_filters WHERE activity_search_id = 1982;
SELECT * FROM automated_reports where id = 68;
SELECT * FROM automated_report_results where id = 275;
SELECT * FROM automated_reports order by id desc;
SELECT * FROM automated_report_results order by id desc;
select * from activity_searches where user_id = 143;
select * from ask_anything_prompts;
SELECT * FROM groups WHERE id = 1439;
SELECT * FROM users WHERE group_id = 1439;
select * from permissions; # 158
select * from roles;
select * from permission_role
select * from teams where id = 1;
select * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;
select * from groups where id = 28;
select * from playbooks where team_id = 1;
select * from playbooks where id = 179;
select * from playbook_categories where id = 1391;
select * from users where id = 143;
select * from crm_profiles where user_id = 143;
select * from activities where crm_configuration_id = 39 and type = 'conference'
and crm_provider_id IS NOT NULL ORDER by id desc;
select * from activities where id = 422003; # 00UO400000pB6fpMAC
SELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type
FROM automated_report_results ar
JOIN automated_reports a ON a.id = ar.report_id
WHERE a.type = 'ask_jiminny'
LIMIT 10;
select * from teams where id = 3143;
select * from crm_configurations where id = 500;
select * from users where name = 'Integration Account'; # 1695
SELECT * FROM social_accounts WHERE sociable_id = 1695;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11894 on JY-18909-automated-reports-ask-jiminny, menu","depth":5,"help_text":"Pull request #11894 exists for current branch JY-18909-automated-reports-ask-jiminny","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"RequestGenerateAskJiminnyReportJobTest","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'RequestGenerateAskJiminnyReportJobTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'RequestGenerateAskJiminnyReportJobTest'","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"14","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Jobs\\AutomatedReports;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\ProphetAi\\Exceptions\\ProphetException;\nuse Jiminny\\Component\\ProphetAi\\ProphetClient;\nuse Jiminny\\Jobs\\AutomatedReports\\RequestGenerateAskJiminnyReportJob;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AskJiminnyReportActivityService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\n\nclass RequestGenerateAskJiminnyReportJobTest extends TestCase\n{\n private AutomatedReportsService&MockObject $reportService;\n private AskJiminnyReportActivityService&MockObject $activityService;\n private ProphetClient&MockObject $prophetClient;\n private LoggerInterface&MockObject $logger;\n\n protected function setUp(): void\n {\n $this->reportService = $this->createMock(AutomatedReportsService::class);\n $this->activityService = $this->createMock(AskJiminnyReportActivityService::class);\n $this->prophetClient = $this->createMock(ProphetClient::class);\n $this->logger = $this->createMock(LoggerInterface::class);\n }\n\n private function makeJob(string $uuid = 'report-uuid'): RequestGenerateAskJiminnyReportJob\n {\n return new RequestGenerateAskJiminnyReportJob($uuid);\n }\n\n private function makeActiveReport(\n string $type = AutomatedReportsService::TYPE_ASK_JIMINNY,\n bool $status = true,\n string $teamStatus = Team::STATUS_ACTIVE,\n ): AutomatedReport&MockObject { // @phpstan-ignore-line\n $team = $this->createMock(Team::class);\n $team->method('getStatus')->willReturn($teamStatus);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getType')->willReturn($type);\n $report->method('getStatus')->willReturn($status);\n $report->method('getTeam')->willReturn($team);\n\n return $report;\n }\n\n public function testUniqueIdReturnsReportUuid(): void\n {\n $job = $this->makeJob('my-unique-uuid');\n\n $this->assertEquals('my-unique-uuid', $job->uniqueId());\n }\n\n public function testHandleSkipsWhenReportTypeIsNotAskJiminny(): void\n {\n $report = $this->makeActiveReport(type: 'exec_summary');\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with($this->stringContains('Started'));\n\n $this->logger->expects($this->once())\n ->method('warning')\n ->with($this->stringContains('not an ask_jiminny report'));\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSkipsWhenReportIsInactive(): void\n {\n $report = $this->makeActiveReport(status: false);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->exactly(2))\n ->method('info');\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSkipsWhenTeamIsInactive(): void\n {\n $report = $this->makeActiveReport(teamStatus: Team::STATUS_DEACTIVATED);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->exactly(2))\n ->method('info');\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSkipsWhenCreatorIsNull(): void\n {\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn(null);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->once())\n ->method('warning')\n ->with($this->stringContains('report creator not found'));\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSkipsWhenSavedSearchIsNull(): void\n {\n $creator = $this->createMock(User::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn(null);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->once())\n ->method('warning')\n ->with($this->stringContains('saved search not found'));\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSkipsWhenPromptIsNull(): void\n {\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn(null);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->once())\n ->method('warning')\n ->with($this->stringContains('ask anything prompt not found'));\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleFailsReportWhenNotEnoughActivities(): void\n {\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n $prompt = $this->createMock(\\Jiminny\\Models\\AskAnything\\AskAnythingPrompt::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn($prompt);\n\n $reportResult = $this->createMock(AutomatedReportResult::class);\n $reportResult->expects($this->once())\n ->method('update')\n ->with($this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_FAILED\n && $data['reason'] === AutomatedReportResult::REASON_NOT_ENOUGH_ACTIVITIES));\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->reportService->expects($this->once())\n ->method('getOrCreateReportResult')\n ->willReturn($reportResult);\n\n $this->activityService->expects($this->once())\n ->method('getActivityIdsForSavedSearch')\n ->willReturn([]);\n\n $this->logger->expects($this->exactly(3))\n ->method('info');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSuccessfullyRequestsReport(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-04-07 10:00:00'));\n\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n $prompt = $this->createMock(\\Jiminny\\Models\\AskAnything\\AskAnythingPrompt::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn($prompt);\n $report->method('getUuid')->willReturn('report-uuid');\n\n $reportResult = $this->createMock(AutomatedReportResult::class);\n $reportResult->method('getUuid')->willReturn('result-uuid');\n $reportResult->expects($this->once())\n ->method('update')\n ->with($this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_REQUESTED\n && isset($data['name'], $data['payload'], $data['requested_at'])));\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->reportService->expects($this->once())\n ->method('getOrCreateReportResult')\n ->willReturn($reportResult);\n\n $this->reportService->expects($this->once())\n ->method('getAskJiminnyGenerateReportPayload')\n ->willReturn(['key' => 'value']);\n\n $this->reportService->expects($this->once())\n ->method('getReportFileName')\n ->willReturn('My Report - 7 Apr 2026');\n\n $this->activityService->expects($this->once())\n ->method('getActivityIdsForSavedSearch')\n ->willReturn(['act-1', 'act-2']);\n\n $this->prophetClient->expects($this->once())\n ->method('sendRequest')\n ->willReturn(new \\Jiminny\\Component\\ProphetAi\\Dtos\\ProphetResponseDto([]));\n\n $this->logger->expects($this->exactly(4))\n ->method('info');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n\n Carbon::setTestNow();\n }\n\n public function testHandleCatchesGenericExceptionAndLogsError(): void\n {\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willThrowException(new \\RuntimeException('DB error'));\n\n $this->logger->expects($this->once())\n ->method('error')\n ->with($this->stringContains('Error'));\n\n $job = $this->makeJob();\n\n $reflection = new \\ReflectionClass($job);\n $triesProp = $reflection->getProperty('tries');\n $triesProp->setAccessible(true);\n\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleCatchesProphetExceptionAndSetsCorrectReason(): void\n {\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n $prompt = $this->createMock(\\Jiminny\\Models\\AskAnything\\AskAnythingPrompt::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn($prompt);\n\n $reportResult = $this->createMock(AutomatedReportResult::class);\n $reportResult->method('getUuid')->willReturn('result-uuid');\n $reportResult->expects($this->once())\n ->method('update')\n ->with($this->callback(fn ($data) => $data['reason'] === AutomatedReportResult::REASON_PROPHET_API_ERROR));\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->reportService->expects($this->once())\n ->method('getOrCreateReportResult')\n ->willReturn($reportResult);\n\n $this->activityService->expects($this->once())\n ->method('getActivityIdsForSavedSearch')\n ->willThrowException(new ProphetException('Prophet failed'));\n\n $this->logger->expects($this->once())\n ->method('error');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleCreatesReportResultBeforeActivityFetch(): void\n {\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n $prompt = $this->createMock(\\Jiminny\\Models\\AskAnything\\AskAnythingPrompt::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn($prompt);\n\n $reportResult = $this->createMock(AutomatedReportResult::class);\n $reportResult->method('getUuid')->willReturn('result-uuid');\n\n $callOrder = [];\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->reportService->expects($this->once())\n ->method('getOrCreateReportResult')\n ->willReturnCallback(function () use ($reportResult, &$callOrder) {\n $callOrder[] = 'getOrCreateReportResult';\n\n return $reportResult;\n });\n\n $this->activityService->expects($this->once())\n ->method('getActivityIdsForSavedSearch')\n ->willReturnCallback(function () use (&$callOrder) {\n $callOrder[] = 'getActivityIds';\n\n return [];\n });\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n\n $this->assertEquals(['getOrCreateReportResult', 'getActivityIds'], $callOrder);\n }\n\n public function testHandlePassesCorrectDataToCreateReportResult(): void\n {\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n $prompt = $this->createMock(\\Jiminny\\Models\\AskAnything\\AskAnythingPrompt::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn($prompt);\n\n $reportResult = $this->createMock(AutomatedReportResult::class);\n $reportResult->method('getUuid')->willReturn('result-uuid');\n $reportResult->method('update')->willReturn(true);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->reportService->expects($this->once())\n ->method('getOrCreateReportResult')\n ->with(\n automatedReport: $report,\n data: $this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_DEFAULT\n && $data['media_type'] === AutomatedReportsService::MEDIA_TYPE_PDF)\n )\n ->willReturn($reportResult);\n\n $this->activityService->expects($this->once())\n ->method('getActivityIdsForSavedSearch')\n ->willReturn([]);\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n}","depth":4,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Jobs\\AutomatedReports;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\ProphetAi\\Exceptions\\ProphetException;\nuse Jiminny\\Component\\ProphetAi\\ProphetClient;\nuse Jiminny\\Jobs\\AutomatedReports\\RequestGenerateAskJiminnyReportJob;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AskJiminnyReportActivityService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\n\nclass RequestGenerateAskJiminnyReportJobTest extends TestCase\n{\n private AutomatedReportsService&MockObject $reportService;\n private AskJiminnyReportActivityService&MockObject $activityService;\n private ProphetClient&MockObject $prophetClient;\n private LoggerInterface&MockObject $logger;\n\n protected function setUp(): void\n {\n $this->reportService = $this->createMock(AutomatedReportsService::class);\n $this->activityService = $this->createMock(AskJiminnyReportActivityService::class);\n $this->prophetClient = $this->createMock(ProphetClient::class);\n $this->logger = $this->createMock(LoggerInterface::class);\n }\n\n private function makeJob(string $uuid = 'report-uuid'): RequestGenerateAskJiminnyReportJob\n {\n return new RequestGenerateAskJiminnyReportJob($uuid);\n }\n\n private function makeActiveReport(\n string $type = AutomatedReportsService::TYPE_ASK_JIMINNY,\n bool $status = true,\n string $teamStatus = Team::STATUS_ACTIVE,\n ): AutomatedReport&MockObject { // @phpstan-ignore-line\n $team = $this->createMock(Team::class);\n $team->method('getStatus')->willReturn($teamStatus);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getType')->willReturn($type);\n $report->method('getStatus')->willReturn($status);\n $report->method('getTeam')->willReturn($team);\n\n return $report;\n }\n\n public function testUniqueIdReturnsReportUuid(): void\n {\n $job = $this->makeJob('my-unique-uuid');\n\n $this->assertEquals('my-unique-uuid', $job->uniqueId());\n }\n\n public function testHandleSkipsWhenReportTypeIsNotAskJiminny(): void\n {\n $report = $this->makeActiveReport(type: 'exec_summary');\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with($this->stringContains('Started'));\n\n $this->logger->expects($this->once())\n ->method('warning')\n ->with($this->stringContains('not an ask_jiminny report'));\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSkipsWhenReportIsInactive(): void\n {\n $report = $this->makeActiveReport(status: false);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->exactly(2))\n ->method('info');\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSkipsWhenTeamIsInactive(): void\n {\n $report = $this->makeActiveReport(teamStatus: Team::STATUS_DEACTIVATED);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->exactly(2))\n ->method('info');\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSkipsWhenCreatorIsNull(): void\n {\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn(null);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->once())\n ->method('warning')\n ->with($this->stringContains('report creator not found'));\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSkipsWhenSavedSearchIsNull(): void\n {\n $creator = $this->createMock(User::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn(null);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->once())\n ->method('warning')\n ->with($this->stringContains('saved search not found'));\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSkipsWhenPromptIsNull(): void\n {\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn(null);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->once())\n ->method('warning')\n ->with($this->stringContains('ask anything prompt not found'));\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleFailsReportWhenNotEnoughActivities(): void\n {\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n $prompt = $this->createMock(\\Jiminny\\Models\\AskAnything\\AskAnythingPrompt::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn($prompt);\n\n $reportResult = $this->createMock(AutomatedReportResult::class);\n $reportResult->expects($this->once())\n ->method('update')\n ->with($this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_FAILED\n && $data['reason'] === AutomatedReportResult::REASON_NOT_ENOUGH_ACTIVITIES));\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->reportService->expects($this->once())\n ->method('getOrCreateReportResult')\n ->willReturn($reportResult);\n\n $this->activityService->expects($this->once())\n ->method('getActivityIdsForSavedSearch')\n ->willReturn([]);\n\n $this->logger->expects($this->exactly(3))\n ->method('info');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSuccessfullyRequestsReport(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-04-07 10:00:00'));\n\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n $prompt = $this->createMock(\\Jiminny\\Models\\AskAnything\\AskAnythingPrompt::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn($prompt);\n $report->method('getUuid')->willReturn('report-uuid');\n\n $reportResult = $this->createMock(AutomatedReportResult::class);\n $reportResult->method('getUuid')->willReturn('result-uuid');\n $reportResult->expects($this->once())\n ->method('update')\n ->with($this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_REQUESTED\n && isset($data['name'], $data['payload'], $data['requested_at'])));\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->reportService->expects($this->once())\n ->method('getOrCreateReportResult')\n ->willReturn($reportResult);\n\n $this->reportService->expects($this->once())\n ->method('getAskJiminnyGenerateReportPayload')\n ->willReturn(['key' => 'value']);\n\n $this->reportService->expects($this->once())\n ->method('getReportFileName')\n ->willReturn('My Report - 7 Apr 2026');\n\n $this->activityService->expects($this->once())\n ->method('getActivityIdsForSavedSearch')\n ->willReturn(['act-1', 'act-2']);\n\n $this->prophetClient->expects($this->once())\n ->method('sendRequest')\n ->willReturn(new \\Jiminny\\Component\\ProphetAi\\Dtos\\ProphetResponseDto([]));\n\n $this->logger->expects($this->exactly(4))\n ->method('info');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n\n Carbon::setTestNow();\n }\n\n public function testHandleCatchesGenericExceptionAndLogsError(): void\n {\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willThrowException(new \\RuntimeException('DB error'));\n\n $this->logger->expects($this->once())\n ->method('error')\n ->with($this->stringContains('Error'));\n\n $job = $this->makeJob();\n\n $reflection = new \\ReflectionClass($job);\n $triesProp = $reflection->getProperty('tries');\n $triesProp->setAccessible(true);\n\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleCatchesProphetExceptionAndSetsCorrectReason(): void\n {\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n $prompt = $this->createMock(\\Jiminny\\Models\\AskAnything\\AskAnythingPrompt::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn($prompt);\n\n $reportResult = $this->createMock(AutomatedReportResult::class);\n $reportResult->method('getUuid')->willReturn('result-uuid');\n $reportResult->expects($this->once())\n ->method('update')\n ->with($this->callback(fn ($data) => $data['reason'] === AutomatedReportResult::REASON_PROPHET_API_ERROR));\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->reportService->expects($this->once())\n ->method('getOrCreateReportResult')\n ->willReturn($reportResult);\n\n $this->activityService->expects($this->once())\n ->method('getActivityIdsForSavedSearch')\n ->willThrowException(new ProphetException('Prophet failed'));\n\n $this->logger->expects($this->once())\n ->method('error');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleCreatesReportResultBeforeActivityFetch(): void\n {\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n $prompt = $this->createMock(\\Jiminny\\Models\\AskAnything\\AskAnythingPrompt::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn($prompt);\n\n $reportResult = $this->createMock(AutomatedReportResult::class);\n $reportResult->method('getUuid')->willReturn('result-uuid');\n\n $callOrder = [];\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->reportService->expects($this->once())\n ->method('getOrCreateReportResult')\n ->willReturnCallback(function () use ($reportResult, &$callOrder) {\n $callOrder[] = 'getOrCreateReportResult';\n\n return $reportResult;\n });\n\n $this->activityService->expects($this->once())\n ->method('getActivityIdsForSavedSearch')\n ->willReturnCallback(function () use (&$callOrder) {\n $callOrder[] = 'getActivityIds';\n\n return [];\n });\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n\n $this->assertEquals(['getOrCreateReportResult', 'getActivityIds'], $callOrder);\n }\n\n public function testHandlePassesCorrectDataToCreateReportResult(): void\n {\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n $prompt = $this->createMock(\\Jiminny\\Models\\AskAnything\\AskAnythingPrompt::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn($prompt);\n\n $reportResult = $this->createMock(AutomatedReportResult::class);\n $reportResult->method('getUuid')->willReturn('result-uuid');\n $reportResult->method('update')->willReturn(true);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->reportService->expects($this->once())\n ->method('getOrCreateReportResult')\n ->with(\n automatedReport: $report,\n data: $this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_DEFAULT\n && $data['media_type'] === AutomatedReportsService::MEDIA_TYPE_PDF)\n )\n ->willReturn($reportResult);\n\n $this->activityService->expects($this->once())\n ->method('getActivityIdsForSavedSearch')\n ->willReturn([]);\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.088194445,"height":0.027777778},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"12","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o\nJOIN activities a ON o.id = a.opportunity_id\nWHERE a.crm_configuration_id = 39\nAND a.actual_start_time > '2025-10-13'\nAND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 39 and user_id = 143\nand actual_start_time >= '2025-10-13'\nAND type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM opportunities WHERE account_id IN (178);\nselect * from activities where id IN (620137, 620187, 620188, 620189, 620230);\n\n# HS\nSELECT * FROM opportunities WHERE id IN (238);\nselect * from activities where id IN (477,2076);\n\nselect * from users;\n\nSELECT COUNT(*) FROM users;\nSELECT COUNT(*) FROM activities;\nSELECT COUNT(*) FROM opportunities;\n\nUPDATE activities\nSET\n actual_start_time = '2025-12-19 09:00:00',\n actual_end_time = '2025-12-19 10:30:00',\n scheduled_start_time = '2025-12-19 09:00:00',\n scheduled_end_time = '2025-12-19 10:30:00'\nWHERE id IN (407509,407375);\n\nselect * from partners;\n\nSELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id\nFROM activities\nWHERE user_id = 143\nAND actual_start_time >= '2025-10-13 00:00:00'\nAND actual_start_time <= '2026-01-13 23:59:59'\nORDER BY actual_start_time DESC;\n\nSELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;\nSELECT * FROM crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;\n# lead_id\n# account_id 177\n# contact_id 3969\n# opportunity_id\n# stage_id 203\n\nSELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;\n\nSELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'\nAND user_id = 143 and actual_start_time >= '2025-10-13';\n\nSELECT * FROM activities a\n# JOIN opportunities o ON a.opportunity_id = o.id\nWHERE a.crm_configuration_id = 39 AND a.type = 'conference'\nand status = 'completed' and recording_state = 'recorded'\nand a.actual_start_time >= '2025-10-13'\nAND a.user_id = 143\n;\n\nselect * from leads\nwhere crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707\n\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310);\nSELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198\nSELECT * FROM activities WHERE id IN (356001, 356008); # contacts:\n\nSELECT * FROM opportunities WHERE id IN (1707);\nSELECT * FROM stages where id IN (204, 198);\nSELECT * FROM opportunities WHERE account_id IN (178);\nSELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';\nSELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal\n\nSELECT * FROM activities where crm_configuration_id = 39\nAND opportunity_id IS NULL\nAND is_internal = false\nand status = 'completed' and recording_state = 'recorded'\nAND actual_start_time >= '2025-10-13'\nAND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)\n# AND lead_id IN (112, 109)\n;\n\nSELECT * FROM crm_profiles WHERE user_id = 143;\n\nselect * from inboxes; # 212\nselect * from users where id = 143; # 143\nselect * from inbox_email_batches where inbox_id = 212\nand updated_at >= '2026-01-28 00:00:00' order by id desc;\nselect * from inbox_emails where inbox_id = 212\nand batch_id = 95885 order by id desc;\nselect * from email_messages where origin_user_id = 143;\nselect * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';\nselect * from participants where activity_id = 620247;\n\nselect * from crm_profiles where user_id = 143;\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001\nselect * from transcription where activity_id = 356001; # 6943\nselect * from ai_prompts where transcription_id = 6943;\nSELECT * FROM activity_summary_logs where activity_id = 356001;\n\nSELECT * FROM social_accounts WHERE sociable_id = 143;\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;\n# 422515 softphone tr. 8100\n\nSELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;\n# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS\n\nselect * from ai_prompts where transcription_id IN (8100, 7670);\nselect * from activity_summary_logs where activity_id = 407509;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nSELECT * FROM contacts WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\nSELECT * FROM leads WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\n\nSELECT * FROM activity_searches where user_id = 143;\nSELECT * FROM groups where team_id = 1;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1; # 1150 - 7e75f8025c22\nselect id, name, group_id, status, deleted_at, email\nfrom users where team_id = 1 order by group_id desc ;\n\nselect * from activity_searches where id in (1977, 1978, 1979);\nselect * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);\nselect * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277\nselect * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879\n\nINSERT INTO `activity_search_filters`\n(`activity_search_id`, `filter`, `value`) VALUES\n(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')\n;\n\nselect * from crm_configurations where id = 39;\n\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\nselect * from features;\n\nSELECT * FROM activity_searches where id = 1982; # 1981\nSELECT * FROM activity_search_filters WHERE activity_search_id = 1982;\n\nSELECT * FROM automated_reports where id = 68;\nSELECT * FROM automated_report_results where id = 275;\n\nSELECT * FROM automated_reports order by id desc;\nSELECT * FROM automated_report_results order by id desc;\nselect * from activity_searches where user_id = 143;\nselect * from ask_anything_prompts;\n\nSELECT * FROM groups WHERE id = 1439;\nSELECT * FROM users WHERE group_id = 1439;\n\nselect * from permissions; # 158\nselect * from roles;\nselect * from permission_role\n\nselect * from teams where id = 1;\nselect * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;\nselect * from groups where id = 28;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 179;\nselect * from playbook_categories where id = 1391;\nselect * from users where id = 143;\nselect * from crm_profiles where user_id = 143;\nselect * from activities where crm_configuration_id = 39 and type = 'conference'\nand crm_provider_id IS NOT NULL ORDER by id desc;\nselect * from activities where id = 422003; # 00UO400000pB6fpMAC\n\nSELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type\nFROM automated_report_results ar\nJOIN automated_reports a ON a.id = ar.report_id\nWHERE a.type = 'ask_jiminny'\nLIMIT 10;\n\n\nselect * from teams where id = 3143;\nselect * from crm_configurations where id = 500;\nselect * from users where name = 'Integration Account'; # 1695\nSELECT * FROM social_accounts WHERE sociable_id = 1695;","depth":4,"value":"SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o\nJOIN activities a ON o.id = a.opportunity_id\nWHERE a.crm_configuration_id = 39\nAND a.actual_start_time > '2025-10-13'\nAND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 39 and user_id = 143\nand actual_start_time >= '2025-10-13'\nAND type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM opportunities WHERE account_id IN (178);\nselect * from activities where id IN (620137, 620187, 620188, 620189, 620230);\n\n# HS\nSELECT * FROM opportunities WHERE id IN (238);\nselect * from activities where id IN (477,2076);\n\nselect * from users;\n\nSELECT COUNT(*) FROM users;\nSELECT COUNT(*) FROM activities;\nSELECT COUNT(*) FROM opportunities;\n\nUPDATE activities\nSET\n actual_start_time = '2025-12-19 09:00:00',\n actual_end_time = '2025-12-19 10:30:00',\n scheduled_start_time = '2025-12-19 09:00:00',\n scheduled_end_time = '2025-12-19 10:30:00'\nWHERE id IN (407509,407375);\n\nselect * from partners;\n\nSELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id\nFROM activities\nWHERE user_id = 143\nAND actual_start_time >= '2025-10-13 00:00:00'\nAND actual_start_time <= '2026-01-13 23:59:59'\nORDER BY actual_start_time DESC;\n\nSELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;\nSELECT * FROM crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;\n# lead_id\n# account_id 177\n# contact_id 3969\n# opportunity_id\n# stage_id 203\n\nSELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;\n\nSELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'\nAND user_id = 143 and actual_start_time >= '2025-10-13';\n\nSELECT * FROM activities a\n# JOIN opportunities o ON a.opportunity_id = o.id\nWHERE a.crm_configuration_id = 39 AND a.type = 'conference'\nand status = 'completed' and recording_state = 'recorded'\nand a.actual_start_time >= '2025-10-13'\nAND a.user_id = 143\n;\n\nselect * from leads\nwhere crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707\n\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310);\nSELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198\nSELECT * FROM activities WHERE id IN (356001, 356008); # contacts:\n\nSELECT * FROM opportunities WHERE id IN (1707);\nSELECT * FROM stages where id IN (204, 198);\nSELECT * FROM opportunities WHERE account_id IN (178);\nSELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';\nSELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal\n\nSELECT * FROM activities where crm_configuration_id = 39\nAND opportunity_id IS NULL\nAND is_internal = false\nand status = 'completed' and recording_state = 'recorded'\nAND actual_start_time >= '2025-10-13'\nAND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)\n# AND lead_id IN (112, 109)\n;\n\nSELECT * FROM crm_profiles WHERE user_id = 143;\n\nselect * from inboxes; # 212\nselect * from users where id = 143; # 143\nselect * from inbox_email_batches where inbox_id = 212\nand updated_at >= '2026-01-28 00:00:00' order by id desc;\nselect * from inbox_emails where inbox_id = 212\nand batch_id = 95885 order by id desc;\nselect * from email_messages where origin_user_id = 143;\nselect * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';\nselect * from participants where activity_id = 620247;\n\nselect * from crm_profiles where user_id = 143;\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001\nselect * from transcription where activity_id = 356001; # 6943\nselect * from ai_prompts where transcription_id = 6943;\nSELECT * FROM activity_summary_logs where activity_id = 356001;\n\nSELECT * FROM social_accounts WHERE sociable_id = 143;\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;\n# 422515 softphone tr. 8100\n\nSELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;\n# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS\n\nselect * from ai_prompts where transcription_id IN (8100, 7670);\nselect * from activity_summary_logs where activity_id = 407509;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nSELECT * FROM contacts WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\nSELECT * FROM leads WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\n\nSELECT * FROM activity_searches where user_id = 143;\nSELECT * FROM groups where team_id = 1;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1; # 1150 - 7e75f8025c22\nselect id, name, group_id, status, deleted_at, email\nfrom users where team_id = 1 order by group_id desc ;\n\nselect * from activity_searches where id in (1977, 1978, 1979);\nselect * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);\nselect * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277\nselect * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879\n\nINSERT INTO `activity_search_filters`\n(`activity_search_id`, `filter`, `value`) VALUES\n(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')\n;\n\nselect * from crm_configurations where id = 39;\n\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\nselect * from features;\n\nSELECT * FROM activity_searches where id = 1982; # 1981\nSELECT * FROM activity_search_filters WHERE activity_search_id = 1982;\n\nSELECT * FROM automated_reports where id = 68;\nSELECT * FROM automated_report_results where id = 275;\n\nSELECT * FROM automated_reports order by id desc;\nSELECT * FROM automated_report_results order by id desc;\nselect * from activity_searches where user_id = 143;\nselect * from ask_anything_prompts;\n\nSELECT * FROM groups WHERE id = 1439;\nSELECT * FROM users WHERE group_id = 1439;\n\nselect * from permissions; # 158\nselect * from roles;\nselect * from permission_role\n\nselect * from teams where id = 1;\nselect * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;\nselect * from groups where id = 28;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 179;\nselect * from playbook_categories where id = 1391;\nselect * from users where id = 143;\nselect * from crm_profiles where user_id = 143;\nselect * from activities where crm_configuration_id = 39 and type = 'conference'\nand crm_provider_id IS NOT NULL ORDER by id desc;\nselect * from activities where id = 422003; # 00UO400000pB6fpMAC\n\nSELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type\nFROM automated_report_results ar\nJOIN automated_reports a ON a.id = ar.report_id\nWHERE a.type = 'ask_jiminny'\nLIMIT 10;\n\n\nselect * from teams where id = 3143;\nselect * from crm_configurations where id = 500;\nselect * from users where name = 'Integration Account'; # 1695\nSELECT * FROM social_accounts WHERE sociable_id = 1695;","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.018055556,"height":0.026666667},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
467660169672458461
|
6397958702907200333
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
RequestGenerateAskJiminnyReportJobTest
Run 'RequestGenerateAskJiminnyReportJobTest'
Debug 'RequestGenerateAskJiminnyReportJobTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
14
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\AutomatedReports;
use Carbon\Carbon;
use Jiminny\Component\ProphetAi\Exceptions\ProphetException;
use Jiminny\Component\ProphetAi\ProphetClient;
use Jiminny\Jobs\AutomatedReports\RequestGenerateAskJiminnyReportJob;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AskJiminnyReportActivityService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
class RequestGenerateAskJiminnyReportJobTest extends TestCase
{
private AutomatedReportsService&MockObject $reportService;
private AskJiminnyReportActivityService&MockObject $activityService;
private ProphetClient&MockObject $prophetClient;
private LoggerInterface&MockObject $logger;
protected function setUp(): void
{
$this->reportService = $this->createMock(AutomatedReportsService::class);
$this->activityService = $this->createMock(AskJiminnyReportActivityService::class);
$this->prophetClient = $this->createMock(ProphetClient::class);
$this->logger = $this->createMock(LoggerInterface::class);
}
private function makeJob(string $uuid = 'report-uuid'): RequestGenerateAskJiminnyReportJob
{
return new RequestGenerateAskJiminnyReportJob($uuid);
}
private function makeActiveReport(
string $type = AutomatedReportsService::TYPE_ASK_JIMINNY,
bool $status = true,
string $teamStatus = Team::STATUS_ACTIVE,
): AutomatedReport&MockObject { // @phpstan-ignore-line
$team = $this->createMock(Team::class);
$team->method('getStatus')->willReturn($teamStatus);
$report = $this->createMock(AutomatedReport::class);
$report->method('getType')->willReturn($type);
$report->method('getStatus')->willReturn($status);
$report->method('getTeam')->willReturn($team);
return $report;
}
public function testUniqueIdReturnsReportUuid(): void
{
$job = $this->makeJob('my-unique-uuid');
$this->assertEquals('my-unique-uuid', $job->uniqueId());
}
public function testHandleSkipsWhenReportTypeIsNotAskJiminny(): void
{
$report = $this->makeActiveReport(type: 'exec_summary');
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->once())
->method('info')
->with($this->stringContains('Started'));
$this->logger->expects($this->once())
->method('warning')
->with($this->stringContains('not an ask_jiminny report'));
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSkipsWhenReportIsInactive(): void
{
$report = $this->makeActiveReport(status: false);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->exactly(2))
->method('info');
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSkipsWhenTeamIsInactive(): void
{
$report = $this->makeActiveReport(teamStatus: Team::STATUS_DEACTIVATED);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->exactly(2))
->method('info');
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSkipsWhenCreatorIsNull(): void
{
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn(null);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->once())
->method('warning')
->with($this->stringContains('report creator not found'));
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSkipsWhenSavedSearchIsNull(): void
{
$creator = $this->createMock(User::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn(null);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->once())
->method('warning')
->with($this->stringContains('saved search not found'));
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSkipsWhenPromptIsNull(): void
{
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn(null);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->once())
->method('warning')
->with($this->stringContains('ask anything prompt not found'));
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleFailsReportWhenNotEnoughActivities(): void
{
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$prompt = $this->createMock(\Jiminny\Models\AskAnything\AskAnythingPrompt::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn($prompt);
$reportResult = $this->createMock(AutomatedReportResult::class);
$reportResult->expects($this->once())
->method('update')
->with($this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_FAILED
&& $data['reason'] === AutomatedReportResult::REASON_NOT_ENOUGH_ACTIVITIES));
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->reportService->expects($this->once())
->method('getOrCreateReportResult')
->willReturn($reportResult);
$this->activityService->expects($this->once())
->method('getActivityIdsForSavedSearch')
->willReturn([]);
$this->logger->expects($this->exactly(3))
->method('info');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSuccessfullyRequestsReport(): void
{
Carbon::setTestNow(Carbon::parse('2026-04-07 10:00:00'));
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$prompt = $this->createMock(\Jiminny\Models\AskAnything\AskAnythingPrompt::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn($prompt);
$report->method('getUuid')->willReturn('report-uuid');
$reportResult = $this->createMock(AutomatedReportResult::class);
$reportResult->method('getUuid')->willReturn('result-uuid');
$reportResult->expects($this->once())
->method('update')
->with($this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_REQUESTED
&& isset($data['name'], $data['payload'], $data['requested_at'])));
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->reportService->expects($this->once())
->method('getOrCreateReportResult')
->willReturn($reportResult);
$this->reportService->expects($this->once())
->method('getAskJiminnyGenerateReportPayload')
->willReturn(['key' => 'value']);
$this->reportService->expects($this->once())
->method('getReportFileName')
->willReturn('My Report - 7 Apr 2026');
$this->activityService->expects($this->once())
->method('getActivityIdsForSavedSearch')
->willReturn(['act-1', 'act-2']);
$this->prophetClient->expects($this->once())
->method('sendRequest')
->willReturn(new \Jiminny\Component\ProphetAi\Dtos\ProphetResponseDto([]));
$this->logger->expects($this->exactly(4))
->method('info');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
Carbon::setTestNow();
}
public function testHandleCatchesGenericExceptionAndLogsError(): void
{
$this->reportService->expects($this->once())
->method('getReport')
->willThrowException(new \RuntimeException('DB error'));
$this->logger->expects($this->once())
->method('error')
->with($this->stringContains('Error'));
$job = $this->makeJob();
$reflection = new \ReflectionClass($job);
$triesProp = $reflection->getProperty('tries');
$triesProp->setAccessible(true);
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleCatchesProphetExceptionAndSetsCorrectReason(): void
{
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$prompt = $this->createMock(\Jiminny\Models\AskAnything\AskAnythingPrompt::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn($prompt);
$reportResult = $this->createMock(AutomatedReportResult::class);
$reportResult->method('getUuid')->willReturn('result-uuid');
$reportResult->expects($this->once())
->method('update')
->with($this->callback(fn ($data) => $data['reason'] === AutomatedReportResult::REASON_PROPHET_API_ERROR));
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->reportService->expects($this->once())
->method('getOrCreateReportResult')
->willReturn($reportResult);
$this->activityService->expects($this->once())
->method('getActivityIdsForSavedSearch')
->willThrowException(new ProphetException('Prophet failed'));
$this->logger->expects($this->once())
->method('error');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleCreatesReportResultBeforeActivityFetch(): void
{
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$prompt = $this->createMock(\Jiminny\Models\AskAnything\AskAnythingPrompt::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn($prompt);
$reportResult = $this->createMock(AutomatedReportResult::class);
$reportResult->method('getUuid')->willReturn('result-uuid');
$callOrder = [];
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->reportService->expects($this->once())
->method('getOrCreateReportResult')
->willReturnCallback(function () use ($reportResult, &$callOrder) {
$callOrder[] = 'getOrCreateReportResult';
return $reportResult;
});
$this->activityService->expects($this->once())
->method('getActivityIdsForSavedSearch')
->willReturnCallback(function () use (&$callOrder) {
$callOrder[] = 'getActivityIds';
return [];
});
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
$this->assertEquals(['getOrCreateReportResult', 'getActivityIds'], $callOrder);
}
public function testHandlePassesCorrectDataToCreateReportResult(): void
{
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$prompt = $this->createMock(\Jiminny\Models\AskAnything\AskAnythingPrompt::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn($prompt);
$reportResult = $this->createMock(AutomatedReportResult::class);
$reportResult->method('getUuid')->willReturn('result-uuid');
$reportResult->method('update')->willReturn(true);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->reportService->expects($this->once())
->method('getOrCreateReportResult')
->with(
automatedReport: $report,
data: $this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_DEFAULT
&& $data['media_type'] === AutomatedReportsService::MEDIA_TYPE_PDF)
)
->willReturn($reportResult);
$this->activityService->expects($this->once())
->method('getActivityIdsForSavedSearch')
->willReturn([]);
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
9
12
2
4
Previous Highlighted Error
Next Highlighted Error
SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o
JOIN activities a ON o.id = a.opportunity_id
WHERE a.crm_configuration_id = 39
AND a.actual_start_time > '2025-10-13'
AND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM activities
WHERE crm_configuration_id = 39 and user_id = 143
and actual_start_time >= '2025-10-13'
AND type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM opportunities WHERE account_id IN (178);
select * from activities where id IN (620137, 620187, 620188, 620189, 620230);
# HS
SELECT * FROM opportunities WHERE id IN (238);
select * from activities where id IN (477,2076);
select * from users;
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM activities;
SELECT COUNT(*) FROM opportunities;
UPDATE activities
SET
actual_start_time = '2025-12-19 09:00:00',
actual_end_time = '2025-12-19 10:30:00',
scheduled_start_time = '2025-12-19 09:00:00',
scheduled_end_time = '2025-12-19 10:30:00'
WHERE id IN (407509,407375);
select * from partners;
SELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id
FROM activities
WHERE user_id = 143
AND actual_start_time >= '2025-10-13 00:00:00'
AND actual_start_time <= '2026-01-13 23:59:59'
ORDER BY actual_start_time DESC;
SELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;
SELECT * FROM crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;
# lead_id
# account_id 177
# contact_id 3969
# opportunity_id
# stage_id 203
SELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;
SELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'
AND user_id = 143 and actual_start_time >= '2025-10-13';
SELECT * FROM activities a
# JOIN opportunities o ON a.opportunity_id = o.id
WHERE a.crm_configuration_id = 39 AND a.type = 'conference'
and status = 'completed' and recording_state = 'recorded'
and a.actual_start_time >= '2025-10-13'
AND a.user_id = 143
;
select * from leads
where crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310);
SELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198
SELECT * FROM activities WHERE id IN (356001, 356008); # contacts:
SELECT * FROM opportunities WHERE id IN (1707);
SELECT * FROM stages where id IN (204, 198);
SELECT * FROM opportunities WHERE account_id IN (178);
SELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';
SELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal
SELECT * FROM activities where crm_configuration_id = 39
AND opportunity_id IS NULL
AND is_internal = false
and status = 'completed' and recording_state = 'recorded'
AND actual_start_time >= '2025-10-13'
AND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)
# AND lead_id IN (112, 109)
;
SELECT * FROM crm_profiles WHERE user_id = 143;
select * from inboxes; # 212
select * from users where id = 143; # 143
select * from inbox_email_batches where inbox_id = 212
and updated_at >= '2026-01-28 00:00:00' order by id desc;
select * from inbox_emails where inbox_id = 212
and batch_id = 95885 order by id desc;
select * from email_messages where origin_user_id = 143;
select * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';
select * from participants where activity_id = 620247;
select * from crm_profiles where user_id = 143;
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001
select * from transcription where activity_id = 356001; # 6943
select * from ai_prompts where transcription_id = 6943;
SELECT * FROM activity_summary_logs where activity_id = 356001;
SELECT * FROM social_accounts WHERE sociable_id = 143;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;
# 422515 softphone tr. 8100
SELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;
# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS
select * from ai_prompts where transcription_id IN (8100, 7670);
select * from activity_summary_logs where activity_id = 407509;
select * from sidekick_settings;
select * from default_activity_types;
SELECT * FROM contacts WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM leads WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM activity_searches where user_id = 143;
SELECT * FROM groups where team_id = 1;
select * from teams where id = 1;
select * from groups where team_id = 1; # 1150 - 7e75f8025c22
select id, name, group_id, status, deleted_at, email
from users where team_id = 1 order by group_id desc ;
select * from activity_searches where id in (1977, 1978, 1979);
select * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);
select * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277
select * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879
INSERT INTO `activity_search_filters`
(`activity_search_id`, `filter`, `value`) VALUES
(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')
;
select * from crm_configurations where id = 39;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from features;
SELECT * FROM activity_searches where id = 1982; # 1981
SELECT * FROM activity_search_filters WHERE activity_search_id = 1982;
SELECT * FROM automated_reports where id = 68;
SELECT * FROM automated_report_results where id = 275;
SELECT * FROM automated_reports order by id desc;
SELECT * FROM automated_report_results order by id desc;
select * from activity_searches where user_id = 143;
select * from ask_anything_prompts;
SELECT * FROM groups WHERE id = 1439;
SELECT * FROM users WHERE group_id = 1439;
select * from permissions; # 158
select * from roles;
select * from permission_role
select * from teams where id = 1;
select * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;
select * from groups where id = 28;
select * from playbooks where team_id = 1;
select * from playbooks where id = 179;
select * from playbook_categories where id = 1391;
select * from users where id = 143;
select * from crm_profiles where user_id = 143;
select * from activities where crm_configuration_id = 39 and type = 'conference'
and crm_provider_id IS NOT NULL ORDER by id desc;
select * from activities where id = 422003; # 00UO400000pB6fpMAC
SELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type
FROM automated_report_results ar
JOIN automated_reports a ON a.id = ar.report_id
WHERE a.type = 'ask_jiminny'
LIMIT 10;
select * from teams where id = 3143;
select * from crm_configurations where id = 500;
select * from users where name = 'Integration Account'; # 1695
SELECT * FROM social_accounts WHERE sociable_id = 1695;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
54502
|
NULL
|
0
|
2026-04-20T09:01:53.473051+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776675713473_m2.jpg...
|
PhpStorm
|
faVsco.js – RequestGenerateAskJiminnyReportJobTest faVsco.js – RequestGenerateAskJiminnyReportJobTest.php...
|
True
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
RequestGenerateAskJiminnyReportJobTest
Run 'RequestGenerateAskJiminnyReportJobTest'
Debug 'RequestGenerateAskJiminnyReportJobTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
14
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\AutomatedReports;
use Carbon\Carbon;
use Jiminny\Component\ProphetAi\Exceptions\ProphetException;
use Jiminny\Component\ProphetAi\ProphetClient;
use Jiminny\Jobs\AutomatedReports\RequestGenerateAskJiminnyReportJob;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AskJiminnyReportActivityService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
class RequestGenerateAskJiminnyReportJobTest extends TestCase
{
private AutomatedReportsService&MockObject $reportService;
private AskJiminnyReportActivityService&MockObject $activityService;
private ProphetClient&MockObject $prophetClient;
private LoggerInterface&MockObject $logger;
protected function setUp(): void
{
$this->reportService = $this->createMock(AutomatedReportsService::class);
$this->activityService = $this->createMock(AskJiminnyReportActivityService::class);
$this->prophetClient = $this->createMock(ProphetClient::class);
$this->logger = $this->createMock(LoggerInterface::class);
}
private function makeJob(string $uuid = 'report-uuid'): RequestGenerateAskJiminnyReportJob
{
return new RequestGenerateAskJiminnyReportJob($uuid);
}
private function makeActiveReport(
string $type = AutomatedReportsService::TYPE_ASK_JIMINNY,
bool $status = true,
string $teamStatus = Team::STATUS_ACTIVE,
): AutomatedReport&MockObject { // @phpstan-ignore-line
$team = $this->createMock(Team::class);
$team->method('getStatus')->willReturn($teamStatus);
$report = $this->createMock(AutomatedReport::class);
$report->method('getType')->willReturn($type);
$report->method('getStatus')->willReturn($status);
$report->method('getTeam')->willReturn($team);
return $report;
}
public function testUniqueIdReturnsReportUuid(): void
{
$job = $this->makeJob('my-unique-uuid');
$this->assertEquals('my-unique-uuid', $job->uniqueId());
}
public function testHandleSkipsWhenReportTypeIsNotAskJiminny(): void
{
$report = $this->makeActiveReport(type: 'exec_summary');
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->once())
->method('info')
->with($this->stringContains('Started'));
$this->logger->expects($this->once())
->method('warning')
->with($this->stringContains('not an ask_jiminny report'));
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSkipsWhenReportIsInactive(): void
{
$report = $this->makeActiveReport(status: false);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->exactly(2))
->method('info');
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSkipsWhenTeamIsInactive(): void
{
$report = $this->makeActiveReport(teamStatus: Team::STATUS_DEACTIVATED);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->exactly(2))
->method('info');
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSkipsWhenCreatorIsNull(): void
{
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn(null);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->once())
->method('warning')
->with($this->stringContains('report creator not found'));
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSkipsWhenSavedSearchIsNull(): void
{
$creator = $this->createMock(User::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn(null);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->once())
->method('warning')
->with($this->stringContains('saved search not found'));
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSkipsWhenPromptIsNull(): void
{
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn(null);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->once())
->method('warning')
->with($this->stringContains('ask anything prompt not found'));
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleFailsReportWhenNotEnoughActivities(): void
{
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$prompt = $this->createMock(\Jiminny\Models\AskAnything\AskAnythingPrompt::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn($prompt);
$reportResult = $this->createMock(AutomatedReportResult::class);
$reportResult->expects($this->once())
->method('update')
->with($this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_FAILED
&& $data['reason'] === AutomatedReportResult::REASON_NOT_ENOUGH_ACTIVITIES));
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->reportService->expects($this->once())
->method('getOrCreateReportResult')
->willReturn($reportResult);
$this->activityService->expects($this->once())
->method('getActivityIdsForSavedSearch')
->willReturn([]);
$this->logger->expects($this->exactly(3))
->method('info');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSuccessfullyRequestsReport(): void
{
Carbon::setTestNow(Carbon::parse('2026-04-07 10:00:00'));
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$prompt = $this->createMock(\Jiminny\Models\AskAnything\AskAnythingPrompt::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn($prompt);
$report->method('getUuid')->willReturn('report-uuid');
$reportResult = $this->createMock(AutomatedReportResult::class);
$reportResult->method('getUuid')->willReturn('result-uuid');
$reportResult->expects($this->once())
->method('update')
->with($this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_REQUESTED
&& isset($data['name'], $data['payload'], $data['requested_at'])));
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->reportService->expects($this->once())
->method('getOrCreateReportResult')
->willReturn($reportResult);
$this->reportService->expects($this->once())
->method('getAskJiminnyGenerateReportPayload')
->willReturn(['key' => 'value']);
$this->reportService->expects($this->once())
->method('getReportFileName')
->willReturn('My Report - 7 Apr 2026');
$this->activityService->expects($this->once())
->method('getActivityIdsForSavedSearch')
->willReturn(['act-1', 'act-2']);
$this->prophetClient->expects($this->once())
->method('sendRequest')
->willReturn(new \Jiminny\Component\ProphetAi\Dtos\ProphetResponseDto([]));
$this->logger->expects($this->exactly(4))
->method('info');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
Carbon::setTestNow();
}
public function testHandleCatchesGenericExceptionAndLogsError(): void
{
$this->reportService->expects($this->once())
->method('getReport')
->willThrowException(new \RuntimeException('DB error'));
$this->logger->expects($this->once())
->method('error')
->with($this->stringContains('Error'));
$job = $this->makeJob();
$reflection = new \ReflectionClass($job);
$triesProp = $reflection->getProperty('tries');
$triesProp->setAccessible(true);
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleCatchesProphetExceptionAndSetsCorrectReason(): void
{
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$prompt = $this->createMock(\Jiminny\Models\AskAnything\AskAnythingPrompt::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn($prompt);
$reportResult = $this->createMock(AutomatedReportResult::class);
$reportResult->method('getUuid')->willReturn('result-uuid');
$reportResult->expects($this->once())
->method('update')
->with($this->callback(fn ($data) => $data['reason'] === AutomatedReportResult::REASON_PROPHET_API_ERROR));
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->reportService->expects($this->once())
->method('getOrCreateReportResult')
->willReturn($reportResult);
$this->activityService->expects($this->once())
->method('getActivityIdsForSavedSearch')
->willThrowException(new ProphetException('Prophet failed'));
$this->logger->expects($this->once())
->method('error');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleCreatesReportResultBeforeActivityFetch(): void
{
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$prompt = $this->createMock(\Jiminny\Models\AskAnything\AskAnythingPrompt::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn($prompt);
$reportResult = $this->createMock(AutomatedReportResult::class);
$reportResult->method('getUuid')->willReturn('result-uuid');
$callOrder = [];
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->reportService->expects($this->once())
->method('getOrCreateReportResult')
->willReturnCallback(function () use ($reportResult, &$callOrder) {
$callOrder[] = 'getOrCreateReportResult';
return $reportResult;
});
$this->activityService->expects($this->once())
->method('getActivityIdsForSavedSearch')
->willReturnCallback(function () use (&$callOrder) {
$callOrder[] = 'getActivityIds';
return [];
});
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
$this->assertEquals(['getOrCreateReportResult', 'getActivityIds'], $callOrder);
}
public function testHandlePassesCorrectDataToCreateReportResult(): void
{
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$prompt = $this->createMock(\Jiminny\Models\AskAnything\AskAnythingPrompt::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn($prompt);
$reportResult = $this->createMock(AutomatedReportResult::class);
$reportResult->method('getUuid')->willReturn('result-uuid');
$reportResult->method('update')->willReturn(true);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->reportService->expects($this->once())
->method('getOrCreateReportResult')
->with(
automatedReport: $report,
data: $this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_DEFAULT
&& $data['media_type'] === AutomatedReportsService::MEDIA_TYPE_PDF)
)
->willReturn($reportResult);
$this->activityService->expects($this->once())
->method('getActivityIdsForSavedSearch')
->willReturn([]);
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
9
12
2
4
Previous Highlighted Error
Next Highlighted Error
SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o
JOIN activities a ON o.id = a.opportunity_id
WHERE a.crm_configuration_id = 39
AND a.actual_start_time > '2025-10-13'
AND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM activities
WHERE crm_configuration_id = 39 and user_id = 143
and actual_start_time >= '2025-10-13'
AND type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM opportunities WHERE account_id IN (178);
select * from activities where id IN (620137, 620187, 620188, 620189, 620230);
# HS
SELECT * FROM opportunities WHERE id IN (238);
select * from activities where id IN (477,2076);
select * from users;
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM activities;
SELECT COUNT(*) FROM opportunities;
UPDATE activities
SET
actual_start_time = '2025-12-19 09:00:00',
actual_end_time = '2025-12-19 10:30:00',
scheduled_start_time = '2025-12-19 09:00:00',
scheduled_end_time = '2025-12-19 10:30:00'
WHERE id IN (407509,407375);
select * from partners;
SELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id
FROM activities
WHERE user_id = 143
AND actual_start_time >= '2025-10-13 00:00:00'
AND actual_start_time <= '2026-01-13 23:59:59'
ORDER BY actual_start_time DESC;
SELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;
SELECT * FROM crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;
# lead_id
# account_id 177
# contact_id 3969
# opportunity_id
# stage_id 203
SELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;
SELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'
AND user_id = 143 and actual_start_time >= '2025-10-13';
SELECT * FROM activities a
# JOIN opportunities o ON a.opportunity_id = o.id
WHERE a.crm_configuration_id = 39 AND a.type = 'conference'
and status = 'completed' and recording_state = 'recorded'
and a.actual_start_time >= '2025-10-13'
AND a.user_id = 143
;
select * from leads
where crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310);
SELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198
SELECT * FROM activities WHERE id IN (356001, 356008); # contacts:
SELECT * FROM opportunities WHERE id IN (1707);
SELECT * FROM stages where id IN (204, 198);
SELECT * FROM opportunities WHERE account_id IN (178);
SELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';
SELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal
SELECT * FROM activities where crm_configuration_id = 39
AND opportunity_id IS NULL
AND is_internal = false
and status = 'completed' and recording_state = 'recorded'
AND actual_start_time >= '2025-10-13'
AND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)
# AND lead_id IN (112, 109)
;
SELECT * FROM crm_profiles WHERE user_id = 143;
select * from inboxes; # 212
select * from users where id = 143; # 143
select * from inbox_email_batches where inbox_id = 212
and updated_at >= '2026-01-28 00:00:00' order by id desc;
select * from inbox_emails where inbox_id = 212
and batch_id = 95885 order by id desc;
select * from email_messages where origin_user_id = 143;
select * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';
select * from participants where activity_id = 620247;
select * from crm_profiles where user_id = 143;
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001
select * from transcription where activity_id = 356001; # 6943
select * from ai_prompts where transcription_id = 6943;
SELECT * FROM activity_summary_logs where activity_id = 356001;
SELECT * FROM social_accounts WHERE sociable_id = 143;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;
# 422515 softphone tr. 8100
SELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;
# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS
select * from ai_prompts where transcription_id IN (8100, 7670);
select * from activity_summary_logs where activity_id = 407509;
select * from sidekick_settings;
select * from default_activity_types;
SELECT * FROM contacts WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM leads WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM activity_searches where user_id = 143;
SELECT * FROM groups where team_id = 1;
select * from teams where id = 1;
select * from groups where team_id = 1; # 1150 - 7e75f8025c22
select id, name, group_id, status, deleted_at, email
from users where team_id = 1 order by group_id desc ;
select * from activity_searches where id in (1977, 1978, 1979);
select * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);
select * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277
select * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879
INSERT INTO `activity_search_filters`
(`activity_search_id`, `filter`, `value`) VALUES
(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')
;
select * from crm_configurations where id = 39;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from features;
SELECT * FROM activity_searches where id = 1982; # 1981
SELECT * FROM activity_search_filters WHERE activity_search_id = 1982;
SELECT * FROM automated_reports where id = 68;
SELECT * FROM automated_report_results where id = 275;
SELECT * FROM automated_reports order by id desc;
SELECT * FROM automated_report_results order by id desc;
select * from activity_searches where user_id = 143;
select * from ask_anything_prompts;
SELECT * FROM groups WHERE id = 1439;
SELECT * FROM users WHERE group_id = 1439;
select * from permissions; # 158
select * from roles;
select * from permission_role
select * from teams where id = 1;
select * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;
select * from groups where id = 28;
select * from playbooks where team_id = 1;
select * from playbooks where id = 179;
select * from playbook_categories where id = 1391;
select * from users where id = 143;
select * from crm_profiles where user_id = 143;
select * from activities where crm_configuration_id = 39 and type = 'conference'
and crm_provider_id IS NOT NULL ORDER by id desc;
select * from activities where id = 422003; # 00UO400000pB6fpMAC
SELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type
FROM automated_report_results ar
JOIN automated_reports a ON a.id = ar.report_id
WHERE a.type = 'ask_jiminny'
LIMIT 10;
select * from teams where id = 3143;
select * from crm_configurations where id = 500;
select * from users where name = 'Integration Account'; # 1695
SELECT * FROM social_accounts WHERE sociable_id = 1695;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.025930852,"top":0.019952115,"width":0.03856383,"height":0.025538707},"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"#11894 on JY-18909-automated-reports-ask-jiminny, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.12134308,"height":0.025538707},"help_text":"Pull request #11894 exists for current branch JY-18909-automated-reports-ask-jiminny","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.7972075,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"RequestGenerateAskJiminnyReportJobTest","depth":6,"bounds":{"left":0.8125,"top":0.019952115,"width":0.10305851,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'RequestGenerateAskJiminnyReportJobTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'RequestGenerateAskJiminnyReportJobTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"bounds":{"left":0.9381649,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"bounds":{"left":0.96609044,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"bounds":{"left":0.9773936,"top":0.019952115,"width":0.011303191,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"bounds":{"left":0.9886968,"top":0.019952115,"width":0.011303186,"height":0.025538707},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.3587101,"top":0.273743,"width":0.00731383,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"14","depth":4,"bounds":{"left":0.36801863,"top":0.273743,"width":0.009640957,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"bounds":{"left":0.37965426,"top":0.273743,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.38929522,"top":0.27214685,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.39660904,"top":0.27214685,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Jobs\\AutomatedReports;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\ProphetAi\\Exceptions\\ProphetException;\nuse Jiminny\\Component\\ProphetAi\\ProphetClient;\nuse Jiminny\\Jobs\\AutomatedReports\\RequestGenerateAskJiminnyReportJob;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AskJiminnyReportActivityService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\n\nclass RequestGenerateAskJiminnyReportJobTest extends TestCase\n{\n private AutomatedReportsService&MockObject $reportService;\n private AskJiminnyReportActivityService&MockObject $activityService;\n private ProphetClient&MockObject $prophetClient;\n private LoggerInterface&MockObject $logger;\n\n protected function setUp(): void\n {\n $this->reportService = $this->createMock(AutomatedReportsService::class);\n $this->activityService = $this->createMock(AskJiminnyReportActivityService::class);\n $this->prophetClient = $this->createMock(ProphetClient::class);\n $this->logger = $this->createMock(LoggerInterface::class);\n }\n\n private function makeJob(string $uuid = 'report-uuid'): RequestGenerateAskJiminnyReportJob\n {\n return new RequestGenerateAskJiminnyReportJob($uuid);\n }\n\n private function makeActiveReport(\n string $type = AutomatedReportsService::TYPE_ASK_JIMINNY,\n bool $status = true,\n string $teamStatus = Team::STATUS_ACTIVE,\n ): AutomatedReport&MockObject { // @phpstan-ignore-line\n $team = $this->createMock(Team::class);\n $team->method('getStatus')->willReturn($teamStatus);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getType')->willReturn($type);\n $report->method('getStatus')->willReturn($status);\n $report->method('getTeam')->willReturn($team);\n\n return $report;\n }\n\n public function testUniqueIdReturnsReportUuid(): void\n {\n $job = $this->makeJob('my-unique-uuid');\n\n $this->assertEquals('my-unique-uuid', $job->uniqueId());\n }\n\n public function testHandleSkipsWhenReportTypeIsNotAskJiminny(): void\n {\n $report = $this->makeActiveReport(type: 'exec_summary');\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with($this->stringContains('Started'));\n\n $this->logger->expects($this->once())\n ->method('warning')\n ->with($this->stringContains('not an ask_jiminny report'));\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSkipsWhenReportIsInactive(): void\n {\n $report = $this->makeActiveReport(status: false);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->exactly(2))\n ->method('info');\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSkipsWhenTeamIsInactive(): void\n {\n $report = $this->makeActiveReport(teamStatus: Team::STATUS_DEACTIVATED);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->exactly(2))\n ->method('info');\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSkipsWhenCreatorIsNull(): void\n {\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn(null);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->once())\n ->method('warning')\n ->with($this->stringContains('report creator not found'));\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSkipsWhenSavedSearchIsNull(): void\n {\n $creator = $this->createMock(User::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn(null);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->once())\n ->method('warning')\n ->with($this->stringContains('saved search not found'));\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSkipsWhenPromptIsNull(): void\n {\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn(null);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->once())\n ->method('warning')\n ->with($this->stringContains('ask anything prompt not found'));\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleFailsReportWhenNotEnoughActivities(): void\n {\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n $prompt = $this->createMock(\\Jiminny\\Models\\AskAnything\\AskAnythingPrompt::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn($prompt);\n\n $reportResult = $this->createMock(AutomatedReportResult::class);\n $reportResult->expects($this->once())\n ->method('update')\n ->with($this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_FAILED\n && $data['reason'] === AutomatedReportResult::REASON_NOT_ENOUGH_ACTIVITIES));\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->reportService->expects($this->once())\n ->method('getOrCreateReportResult')\n ->willReturn($reportResult);\n\n $this->activityService->expects($this->once())\n ->method('getActivityIdsForSavedSearch')\n ->willReturn([]);\n\n $this->logger->expects($this->exactly(3))\n ->method('info');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSuccessfullyRequestsReport(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-04-07 10:00:00'));\n\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n $prompt = $this->createMock(\\Jiminny\\Models\\AskAnything\\AskAnythingPrompt::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn($prompt);\n $report->method('getUuid')->willReturn('report-uuid');\n\n $reportResult = $this->createMock(AutomatedReportResult::class);\n $reportResult->method('getUuid')->willReturn('result-uuid');\n $reportResult->expects($this->once())\n ->method('update')\n ->with($this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_REQUESTED\n && isset($data['name'], $data['payload'], $data['requested_at'])));\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->reportService->expects($this->once())\n ->method('getOrCreateReportResult')\n ->willReturn($reportResult);\n\n $this->reportService->expects($this->once())\n ->method('getAskJiminnyGenerateReportPayload')\n ->willReturn(['key' => 'value']);\n\n $this->reportService->expects($this->once())\n ->method('getReportFileName')\n ->willReturn('My Report - 7 Apr 2026');\n\n $this->activityService->expects($this->once())\n ->method('getActivityIdsForSavedSearch')\n ->willReturn(['act-1', 'act-2']);\n\n $this->prophetClient->expects($this->once())\n ->method('sendRequest')\n ->willReturn(new \\Jiminny\\Component\\ProphetAi\\Dtos\\ProphetResponseDto([]));\n\n $this->logger->expects($this->exactly(4))\n ->method('info');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n\n Carbon::setTestNow();\n }\n\n public function testHandleCatchesGenericExceptionAndLogsError(): void\n {\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willThrowException(new \\RuntimeException('DB error'));\n\n $this->logger->expects($this->once())\n ->method('error')\n ->with($this->stringContains('Error'));\n\n $job = $this->makeJob();\n\n $reflection = new \\ReflectionClass($job);\n $triesProp = $reflection->getProperty('tries');\n $triesProp->setAccessible(true);\n\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleCatchesProphetExceptionAndSetsCorrectReason(): void\n {\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n $prompt = $this->createMock(\\Jiminny\\Models\\AskAnything\\AskAnythingPrompt::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn($prompt);\n\n $reportResult = $this->createMock(AutomatedReportResult::class);\n $reportResult->method('getUuid')->willReturn('result-uuid');\n $reportResult->expects($this->once())\n ->method('update')\n ->with($this->callback(fn ($data) => $data['reason'] === AutomatedReportResult::REASON_PROPHET_API_ERROR));\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->reportService->expects($this->once())\n ->method('getOrCreateReportResult')\n ->willReturn($reportResult);\n\n $this->activityService->expects($this->once())\n ->method('getActivityIdsForSavedSearch')\n ->willThrowException(new ProphetException('Prophet failed'));\n\n $this->logger->expects($this->once())\n ->method('error');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleCreatesReportResultBeforeActivityFetch(): void\n {\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n $prompt = $this->createMock(\\Jiminny\\Models\\AskAnything\\AskAnythingPrompt::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn($prompt);\n\n $reportResult = $this->createMock(AutomatedReportResult::class);\n $reportResult->method('getUuid')->willReturn('result-uuid');\n\n $callOrder = [];\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->reportService->expects($this->once())\n ->method('getOrCreateReportResult')\n ->willReturnCallback(function () use ($reportResult, &$callOrder) {\n $callOrder[] = 'getOrCreateReportResult';\n\n return $reportResult;\n });\n\n $this->activityService->expects($this->once())\n ->method('getActivityIdsForSavedSearch')\n ->willReturnCallback(function () use (&$callOrder) {\n $callOrder[] = 'getActivityIds';\n\n return [];\n });\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n\n $this->assertEquals(['getOrCreateReportResult', 'getActivityIds'], $callOrder);\n }\n\n public function testHandlePassesCorrectDataToCreateReportResult(): void\n {\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n $prompt = $this->createMock(\\Jiminny\\Models\\AskAnything\\AskAnythingPrompt::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn($prompt);\n\n $reportResult = $this->createMock(AutomatedReportResult::class);\n $reportResult->method('getUuid')->willReturn('result-uuid');\n $reportResult->method('update')->willReturn(true);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->reportService->expects($this->once())\n ->method('getOrCreateReportResult')\n ->with(\n automatedReport: $report,\n data: $this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_DEFAULT\n && $data['media_type'] === AutomatedReportsService::MEDIA_TYPE_PDF)\n )\n ->willReturn($reportResult);\n\n $this->activityService->expects($this->once())\n ->method('getActivityIdsForSavedSearch')\n ->willReturn([]);\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n}","depth":4,"bounds":{"left":0.13863032,"top":0.27055067,"width":0.28158244,"height":0.72944933},"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Jobs\\AutomatedReports;\n\nuse Carbon\\Carbon;\nuse Jiminny\\Component\\ProphetAi\\Exceptions\\ProphetException;\nuse Jiminny\\Component\\ProphetAi\\ProphetClient;\nuse Jiminny\\Jobs\\AutomatedReports\\RequestGenerateAskJiminnyReportJob;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AskJiminnyReportActivityService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse PHPUnit\\Framework\\TestCase;\nuse Psr\\Log\\LoggerInterface;\n\nclass RequestGenerateAskJiminnyReportJobTest extends TestCase\n{\n private AutomatedReportsService&MockObject $reportService;\n private AskJiminnyReportActivityService&MockObject $activityService;\n private ProphetClient&MockObject $prophetClient;\n private LoggerInterface&MockObject $logger;\n\n protected function setUp(): void\n {\n $this->reportService = $this->createMock(AutomatedReportsService::class);\n $this->activityService = $this->createMock(AskJiminnyReportActivityService::class);\n $this->prophetClient = $this->createMock(ProphetClient::class);\n $this->logger = $this->createMock(LoggerInterface::class);\n }\n\n private function makeJob(string $uuid = 'report-uuid'): RequestGenerateAskJiminnyReportJob\n {\n return new RequestGenerateAskJiminnyReportJob($uuid);\n }\n\n private function makeActiveReport(\n string $type = AutomatedReportsService::TYPE_ASK_JIMINNY,\n bool $status = true,\n string $teamStatus = Team::STATUS_ACTIVE,\n ): AutomatedReport&MockObject { // @phpstan-ignore-line\n $team = $this->createMock(Team::class);\n $team->method('getStatus')->willReturn($teamStatus);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getType')->willReturn($type);\n $report->method('getStatus')->willReturn($status);\n $report->method('getTeam')->willReturn($team);\n\n return $report;\n }\n\n public function testUniqueIdReturnsReportUuid(): void\n {\n $job = $this->makeJob('my-unique-uuid');\n\n $this->assertEquals('my-unique-uuid', $job->uniqueId());\n }\n\n public function testHandleSkipsWhenReportTypeIsNotAskJiminny(): void\n {\n $report = $this->makeActiveReport(type: 'exec_summary');\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->once())\n ->method('info')\n ->with($this->stringContains('Started'));\n\n $this->logger->expects($this->once())\n ->method('warning')\n ->with($this->stringContains('not an ask_jiminny report'));\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSkipsWhenReportIsInactive(): void\n {\n $report = $this->makeActiveReport(status: false);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->exactly(2))\n ->method('info');\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSkipsWhenTeamIsInactive(): void\n {\n $report = $this->makeActiveReport(teamStatus: Team::STATUS_DEACTIVATED);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->exactly(2))\n ->method('info');\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSkipsWhenCreatorIsNull(): void\n {\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn(null);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->once())\n ->method('warning')\n ->with($this->stringContains('report creator not found'));\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSkipsWhenSavedSearchIsNull(): void\n {\n $creator = $this->createMock(User::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn(null);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->once())\n ->method('warning')\n ->with($this->stringContains('saved search not found'));\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSkipsWhenPromptIsNull(): void\n {\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn(null);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->logger->expects($this->once())\n ->method('warning')\n ->with($this->stringContains('ask anything prompt not found'));\n\n $this->reportService->expects($this->never())->method('getOrCreateReportResult');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleFailsReportWhenNotEnoughActivities(): void\n {\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n $prompt = $this->createMock(\\Jiminny\\Models\\AskAnything\\AskAnythingPrompt::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn($prompt);\n\n $reportResult = $this->createMock(AutomatedReportResult::class);\n $reportResult->expects($this->once())\n ->method('update')\n ->with($this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_FAILED\n && $data['reason'] === AutomatedReportResult::REASON_NOT_ENOUGH_ACTIVITIES));\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->reportService->expects($this->once())\n ->method('getOrCreateReportResult')\n ->willReturn($reportResult);\n\n $this->activityService->expects($this->once())\n ->method('getActivityIdsForSavedSearch')\n ->willReturn([]);\n\n $this->logger->expects($this->exactly(3))\n ->method('info');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleSuccessfullyRequestsReport(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-04-07 10:00:00'));\n\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n $prompt = $this->createMock(\\Jiminny\\Models\\AskAnything\\AskAnythingPrompt::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn($prompt);\n $report->method('getUuid')->willReturn('report-uuid');\n\n $reportResult = $this->createMock(AutomatedReportResult::class);\n $reportResult->method('getUuid')->willReturn('result-uuid');\n $reportResult->expects($this->once())\n ->method('update')\n ->with($this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_REQUESTED\n && isset($data['name'], $data['payload'], $data['requested_at'])));\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->reportService->expects($this->once())\n ->method('getOrCreateReportResult')\n ->willReturn($reportResult);\n\n $this->reportService->expects($this->once())\n ->method('getAskJiminnyGenerateReportPayload')\n ->willReturn(['key' => 'value']);\n\n $this->reportService->expects($this->once())\n ->method('getReportFileName')\n ->willReturn('My Report - 7 Apr 2026');\n\n $this->activityService->expects($this->once())\n ->method('getActivityIdsForSavedSearch')\n ->willReturn(['act-1', 'act-2']);\n\n $this->prophetClient->expects($this->once())\n ->method('sendRequest')\n ->willReturn(new \\Jiminny\\Component\\ProphetAi\\Dtos\\ProphetResponseDto([]));\n\n $this->logger->expects($this->exactly(4))\n ->method('info');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n\n Carbon::setTestNow();\n }\n\n public function testHandleCatchesGenericExceptionAndLogsError(): void\n {\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willThrowException(new \\RuntimeException('DB error'));\n\n $this->logger->expects($this->once())\n ->method('error')\n ->with($this->stringContains('Error'));\n\n $job = $this->makeJob();\n\n $reflection = new \\ReflectionClass($job);\n $triesProp = $reflection->getProperty('tries');\n $triesProp->setAccessible(true);\n\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleCatchesProphetExceptionAndSetsCorrectReason(): void\n {\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n $prompt = $this->createMock(\\Jiminny\\Models\\AskAnything\\AskAnythingPrompt::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn($prompt);\n\n $reportResult = $this->createMock(AutomatedReportResult::class);\n $reportResult->method('getUuid')->willReturn('result-uuid');\n $reportResult->expects($this->once())\n ->method('update')\n ->with($this->callback(fn ($data) => $data['reason'] === AutomatedReportResult::REASON_PROPHET_API_ERROR));\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->reportService->expects($this->once())\n ->method('getOrCreateReportResult')\n ->willReturn($reportResult);\n\n $this->activityService->expects($this->once())\n ->method('getActivityIdsForSavedSearch')\n ->willThrowException(new ProphetException('Prophet failed'));\n\n $this->logger->expects($this->once())\n ->method('error');\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n\n public function testHandleCreatesReportResultBeforeActivityFetch(): void\n {\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n $prompt = $this->createMock(\\Jiminny\\Models\\AskAnything\\AskAnythingPrompt::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn($prompt);\n\n $reportResult = $this->createMock(AutomatedReportResult::class);\n $reportResult->method('getUuid')->willReturn('result-uuid');\n\n $callOrder = [];\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->reportService->expects($this->once())\n ->method('getOrCreateReportResult')\n ->willReturnCallback(function () use ($reportResult, &$callOrder) {\n $callOrder[] = 'getOrCreateReportResult';\n\n return $reportResult;\n });\n\n $this->activityService->expects($this->once())\n ->method('getActivityIdsForSavedSearch')\n ->willReturnCallback(function () use (&$callOrder) {\n $callOrder[] = 'getActivityIds';\n\n return [];\n });\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n\n $this->assertEquals(['getOrCreateReportResult', 'getActivityIds'], $callOrder);\n }\n\n public function testHandlePassesCorrectDataToCreateReportResult(): void\n {\n $creator = $this->createMock(User::class);\n $savedSearch = $this->createMock(\\Jiminny\\Models\\Activity\\Search::class);\n $prompt = $this->createMock(\\Jiminny\\Models\\AskAnything\\AskAnythingPrompt::class);\n\n $report = $this->makeActiveReport();\n $report->method('getCreator')->willReturn($creator);\n $report->method('getSavedSearch')->willReturn($savedSearch);\n $report->method('getAskAnythingPrompt')->willReturn($prompt);\n\n $reportResult = $this->createMock(AutomatedReportResult::class);\n $reportResult->method('getUuid')->willReturn('result-uuid');\n $reportResult->method('update')->willReturn(true);\n\n $this->reportService->expects($this->once())\n ->method('getReport')\n ->willReturn($report);\n\n $this->reportService->expects($this->once())\n ->method('getOrCreateReportResult')\n ->with(\n automatedReport: $report,\n data: $this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_DEFAULT\n && $data['media_type'] === AutomatedReportsService::MEDIA_TYPE_PDF)\n )\n ->willReturn($reportResult);\n\n $this->activityService->expects($this->once())\n ->method('getActivityIdsForSavedSearch')\n ->willReturn([]);\n\n $job = $this->makeJob();\n $job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"bounds":{"left":0.40492022,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"bounds":{"left":0.41356382,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"bounds":{"left":0.4245346,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"bounds":{"left":0.4331782,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"bounds":{"left":0.4418218,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"bounds":{"left":0.45279256,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"bounds":{"left":0.4637633,"top":0.09896249,"width":0.024268618,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"bounds":{"left":0.49035904,"top":0.09896249,"width":0.008643617,"height":0.01915403},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"bounds":{"left":0.5013298,"top":0.09896249,"width":0.029587766,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"bounds":{"left":0.69913566,"top":0.09896249,"width":0.02825798,"height":0.01915403},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Code changed:","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.042220745,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Sync Changes","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide This Notification","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.6732048,"top":0.123703115,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"12","depth":4,"bounds":{"left":0.6831782,"top":0.123703115,"width":0.009640957,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.69481385,"top":0.123703115,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"bounds":{"left":0.70478725,"top":0.123703115,"width":0.007978723,"height":0.015163607},"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.7144282,"top":0.12210695,"width":0.00731383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"bounds":{"left":0.72174203,"top":0.12210695,"width":0.006981383,"height":0.018355945},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o\nJOIN activities a ON o.id = a.opportunity_id\nWHERE a.crm_configuration_id = 39\nAND a.actual_start_time > '2025-10-13'\nAND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 39 and user_id = 143\nand actual_start_time >= '2025-10-13'\nAND type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM opportunities WHERE account_id IN (178);\nselect * from activities where id IN (620137, 620187, 620188, 620189, 620230);\n\n# HS\nSELECT * FROM opportunities WHERE id IN (238);\nselect * from activities where id IN (477,2076);\n\nselect * from users;\n\nSELECT COUNT(*) FROM users;\nSELECT COUNT(*) FROM activities;\nSELECT COUNT(*) FROM opportunities;\n\nUPDATE activities\nSET\n actual_start_time = '2025-12-19 09:00:00',\n actual_end_time = '2025-12-19 10:30:00',\n scheduled_start_time = '2025-12-19 09:00:00',\n scheduled_end_time = '2025-12-19 10:30:00'\nWHERE id IN (407509,407375);\n\nselect * from partners;\n\nSELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id\nFROM activities\nWHERE user_id = 143\nAND actual_start_time >= '2025-10-13 00:00:00'\nAND actual_start_time <= '2026-01-13 23:59:59'\nORDER BY actual_start_time DESC;\n\nSELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;\nSELECT * FROM crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;\n# lead_id\n# account_id 177\n# contact_id 3969\n# opportunity_id\n# stage_id 203\n\nSELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;\n\nSELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'\nAND user_id = 143 and actual_start_time >= '2025-10-13';\n\nSELECT * FROM activities a\n# JOIN opportunities o ON a.opportunity_id = o.id\nWHERE a.crm_configuration_id = 39 AND a.type = 'conference'\nand status = 'completed' and recording_state = 'recorded'\nand a.actual_start_time >= '2025-10-13'\nAND a.user_id = 143\n;\n\nselect * from leads\nwhere crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707\n\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310);\nSELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198\nSELECT * FROM activities WHERE id IN (356001, 356008); # contacts:\n\nSELECT * FROM opportunities WHERE id IN (1707);\nSELECT * FROM stages where id IN (204, 198);\nSELECT * FROM opportunities WHERE account_id IN (178);\nSELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';\nSELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal\n\nSELECT * FROM activities where crm_configuration_id = 39\nAND opportunity_id IS NULL\nAND is_internal = false\nand status = 'completed' and recording_state = 'recorded'\nAND actual_start_time >= '2025-10-13'\nAND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)\n# AND lead_id IN (112, 109)\n;\n\nSELECT * FROM crm_profiles WHERE user_id = 143;\n\nselect * from inboxes; # 212\nselect * from users where id = 143; # 143\nselect * from inbox_email_batches where inbox_id = 212\nand updated_at >= '2026-01-28 00:00:00' order by id desc;\nselect * from inbox_emails where inbox_id = 212\nand batch_id = 95885 order by id desc;\nselect * from email_messages where origin_user_id = 143;\nselect * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';\nselect * from participants where activity_id = 620247;\n\nselect * from crm_profiles where user_id = 143;\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001\nselect * from transcription where activity_id = 356001; # 6943\nselect * from ai_prompts where transcription_id = 6943;\nSELECT * FROM activity_summary_logs where activity_id = 356001;\n\nSELECT * FROM social_accounts WHERE sociable_id = 143;\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;\n# 422515 softphone tr. 8100\n\nSELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;\n# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS\n\nselect * from ai_prompts where transcription_id IN (8100, 7670);\nselect * from activity_summary_logs where activity_id = 407509;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nSELECT * FROM contacts WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\nSELECT * FROM leads WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\n\nSELECT * FROM activity_searches where user_id = 143;\nSELECT * FROM groups where team_id = 1;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1; # 1150 - 7e75f8025c22\nselect id, name, group_id, status, deleted_at, email\nfrom users where team_id = 1 order by group_id desc ;\n\nselect * from activity_searches where id in (1977, 1978, 1979);\nselect * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);\nselect * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277\nselect * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879\n\nINSERT INTO `activity_search_filters`\n(`activity_search_id`, `filter`, `value`) VALUES\n(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')\n;\n\nselect * from crm_configurations where id = 39;\n\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\nselect * from features;\n\nSELECT * FROM activity_searches where id = 1982; # 1981\nSELECT * FROM activity_search_filters WHERE activity_search_id = 1982;\n\nSELECT * FROM automated_reports where id = 68;\nSELECT * FROM automated_report_results where id = 275;\n\nSELECT * FROM automated_reports order by id desc;\nSELECT * FROM automated_report_results order by id desc;\nselect * from activity_searches where user_id = 143;\nselect * from ask_anything_prompts;\n\nSELECT * FROM groups WHERE id = 1439;\nSELECT * FROM users WHERE group_id = 1439;\n\nselect * from permissions; # 158\nselect * from roles;\nselect * from permission_role\n\nselect * from teams where id = 1;\nselect * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;\nselect * from groups where id = 28;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 179;\nselect * from playbook_categories where id = 1391;\nselect * from users where id = 143;\nselect * from crm_profiles where user_id = 143;\nselect * from activities where crm_configuration_id = 39 and type = 'conference'\nand crm_provider_id IS NOT NULL ORDER by id desc;\nselect * from activities where id = 422003; # 00UO400000pB6fpMAC\n\nSELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type\nFROM automated_report_results ar\nJOIN automated_reports a ON a.id = ar.report_id\nWHERE a.type = 'ask_jiminny'\nLIMIT 10;\n\n\nselect * from teams where id = 3143;\nselect * from crm_configurations where id = 500;\nselect * from users where name = 'Integration Account'; # 1695\nSELECT * FROM social_accounts WHERE sociable_id = 1695;","depth":4,"value":"SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o\nJOIN activities a ON o.id = a.opportunity_id\nWHERE a.crm_configuration_id = 39\nAND a.actual_start_time > '2025-10-13'\nAND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM activities\nWHERE crm_configuration_id = 39 and user_id = 143\nand actual_start_time >= '2025-10-13'\nAND type IN ('conference', 'softphone-inbound', 'softphone-outbound')\n;\n\nSELECT * FROM opportunities WHERE account_id IN (178);\nselect * from activities where id IN (620137, 620187, 620188, 620189, 620230);\n\n# HS\nSELECT * FROM opportunities WHERE id IN (238);\nselect * from activities where id IN (477,2076);\n\nselect * from users;\n\nSELECT COUNT(*) FROM users;\nSELECT COUNT(*) FROM activities;\nSELECT COUNT(*) FROM opportunities;\n\nUPDATE activities\nSET\n actual_start_time = '2025-12-19 09:00:00',\n actual_end_time = '2025-12-19 10:30:00',\n scheduled_start_time = '2025-12-19 09:00:00',\n scheduled_end_time = '2025-12-19 10:30:00'\nWHERE id IN (407509,407375);\n\nselect * from partners;\n\nSELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id\nFROM activities\nWHERE user_id = 143\nAND actual_start_time >= '2025-10-13 00:00:00'\nAND actual_start_time <= '2026-01-13 23:59:59'\nORDER BY actual_start_time DESC;\n\nSELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;\nSELECT * FROM crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;\n# lead_id\n# account_id 177\n# contact_id 3969\n# opportunity_id\n# stage_id 203\n\nSELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;\n\nSELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'\nAND user_id = 143 and actual_start_time >= '2025-10-13';\n\nSELECT * FROM activities a\n# JOIN opportunities o ON a.opportunity_id = o.id\nWHERE a.crm_configuration_id = 39 AND a.type = 'conference'\nand status = 'completed' and recording_state = 'recorded'\nand a.actual_start_time >= '2025-10-13'\nAND a.user_id = 143\n;\n\nselect * from leads\nwhere crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707\n\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);\nSELECT * FROM activities WHERE id IN (356013,616188,616202,616310);\nSELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198\nSELECT * FROM activities WHERE id IN (356001, 356008); # contacts:\n\nSELECT * FROM opportunities WHERE id IN (1707);\nSELECT * FROM stages where id IN (204, 198);\nSELECT * FROM opportunities WHERE account_id IN (178);\nSELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';\nSELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal\n\nSELECT * FROM activities where crm_configuration_id = 39\nAND opportunity_id IS NULL\nAND is_internal = false\nand status = 'completed' and recording_state = 'recorded'\nAND actual_start_time >= '2025-10-13'\nAND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)\n# AND lead_id IN (112, 109)\n;\n\nSELECT * FROM crm_profiles WHERE user_id = 143;\n\nselect * from inboxes; # 212\nselect * from users where id = 143; # 143\nselect * from inbox_email_batches where inbox_id = 212\nand updated_at >= '2026-01-28 00:00:00' order by id desc;\nselect * from inbox_emails where inbox_id = 212\nand batch_id = 95885 order by id desc;\nselect * from email_messages where origin_user_id = 143;\nselect * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';\nselect * from participants where activity_id = 620247;\n\nselect * from crm_profiles where user_id = 143;\n\nSELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001\nselect * from transcription where activity_id = 356001; # 6943\nselect * from ai_prompts where transcription_id = 6943;\nSELECT * FROM activity_summary_logs where activity_id = 356001;\n\nSELECT * FROM social_accounts WHERE sociable_id = 143;\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;\n# 422515 softphone tr. 8100\n\nSELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;\n# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS\n\nselect * from ai_prompts where transcription_id IN (8100, 7670);\nselect * from activity_summary_logs where activity_id = 407509;\n\nselect * from sidekick_settings;\nselect * from default_activity_types;\n\nSELECT * FROM contacts WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\nSELECT * FROM leads WHERE crm_configuration_id = 39 and email = 'm.kogoj@gmx.at';\n\nSELECT * FROM activity_searches where user_id = 143;\nSELECT * FROM groups where team_id = 1;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1; # 1150 - 7e75f8025c22\nselect id, name, group_id, status, deleted_at, email\nfrom users where team_id = 1 order by group_id desc ;\n\nselect * from activity_searches where id in (1977, 1978, 1979);\nselect * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);\nselect * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277\nselect * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879\n\nINSERT INTO `activity_search_filters`\n(`activity_search_id`, `filter`, `value`) VALUES\n(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),\n(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')\n;\n\nselect * from crm_configurations where id = 39;\n\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\nselect * from features;\n\nSELECT * FROM activity_searches where id = 1982; # 1981\nSELECT * FROM activity_search_filters WHERE activity_search_id = 1982;\n\nSELECT * FROM automated_reports where id = 68;\nSELECT * FROM automated_report_results where id = 275;\n\nSELECT * FROM automated_reports order by id desc;\nSELECT * FROM automated_report_results order by id desc;\nselect * from activity_searches where user_id = 143;\nselect * from ask_anything_prompts;\n\nSELECT * FROM groups WHERE id = 1439;\nSELECT * FROM users WHERE group_id = 1439;\n\nselect * from permissions; # 158\nselect * from roles;\nselect * from permission_role\n\nselect * from teams where id = 1;\nselect * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;\nselect * from groups where id = 28;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 179;\nselect * from playbook_categories where id = 1391;\nselect * from users where id = 143;\nselect * from crm_profiles where user_id = 143;\nselect * from activities where crm_configuration_id = 39 and type = 'conference'\nand crm_provider_id IS NOT NULL ORDER by id desc;\nselect * from activities where id = 422003; # 00UO400000pB6fpMAC\n\nSELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type\nFROM automated_report_results ar\nJOIN automated_reports a ON a.id = ar.report_id\nWHERE a.type = 'ask_jiminny'\nLIMIT 10;\n\n\nselect * from teams where id = 3143;\nselect * from crm_configurations where id = 500;\nselect * from users where name = 'Integration Account'; # 1695\nSELECT * FROM social_accounts WHERE sociable_id = 1695;","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"New File or Directory…","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Expand Selected","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Collapse All","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Options","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Hide","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.008643617,"height":0.0},"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
467660169672458461
|
6397958702907200333
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#11894 on JY-18909-automa Project: faVsco.js, menu
#11894 on JY-18909-automated-reports-ask-jiminny, menu
Start Listening for PHP Debug Connections
RequestGenerateAskJiminnyReportJobTest
Run 'RequestGenerateAskJiminnyReportJobTest'
Debug 'RequestGenerateAskJiminnyReportJobTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
1
14
4
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Jobs\AutomatedReports;
use Carbon\Carbon;
use Jiminny\Component\ProphetAi\Exceptions\ProphetException;
use Jiminny\Component\ProphetAi\ProphetClient;
use Jiminny\Jobs\AutomatedReports\RequestGenerateAskJiminnyReportJob;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Services\Kiosk\AutomatedReports\AskJiminnyReportActivityService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use PHPUnit\Framework\MockObject\MockObject;
use PHPUnit\Framework\TestCase;
use Psr\Log\LoggerInterface;
class RequestGenerateAskJiminnyReportJobTest extends TestCase
{
private AutomatedReportsService&MockObject $reportService;
private AskJiminnyReportActivityService&MockObject $activityService;
private ProphetClient&MockObject $prophetClient;
private LoggerInterface&MockObject $logger;
protected function setUp(): void
{
$this->reportService = $this->createMock(AutomatedReportsService::class);
$this->activityService = $this->createMock(AskJiminnyReportActivityService::class);
$this->prophetClient = $this->createMock(ProphetClient::class);
$this->logger = $this->createMock(LoggerInterface::class);
}
private function makeJob(string $uuid = 'report-uuid'): RequestGenerateAskJiminnyReportJob
{
return new RequestGenerateAskJiminnyReportJob($uuid);
}
private function makeActiveReport(
string $type = AutomatedReportsService::TYPE_ASK_JIMINNY,
bool $status = true,
string $teamStatus = Team::STATUS_ACTIVE,
): AutomatedReport&MockObject { // @phpstan-ignore-line
$team = $this->createMock(Team::class);
$team->method('getStatus')->willReturn($teamStatus);
$report = $this->createMock(AutomatedReport::class);
$report->method('getType')->willReturn($type);
$report->method('getStatus')->willReturn($status);
$report->method('getTeam')->willReturn($team);
return $report;
}
public function testUniqueIdReturnsReportUuid(): void
{
$job = $this->makeJob('my-unique-uuid');
$this->assertEquals('my-unique-uuid', $job->uniqueId());
}
public function testHandleSkipsWhenReportTypeIsNotAskJiminny(): void
{
$report = $this->makeActiveReport(type: 'exec_summary');
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->once())
->method('info')
->with($this->stringContains('Started'));
$this->logger->expects($this->once())
->method('warning')
->with($this->stringContains('not an ask_jiminny report'));
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSkipsWhenReportIsInactive(): void
{
$report = $this->makeActiveReport(status: false);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->exactly(2))
->method('info');
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSkipsWhenTeamIsInactive(): void
{
$report = $this->makeActiveReport(teamStatus: Team::STATUS_DEACTIVATED);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->exactly(2))
->method('info');
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSkipsWhenCreatorIsNull(): void
{
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn(null);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->once())
->method('warning')
->with($this->stringContains('report creator not found'));
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSkipsWhenSavedSearchIsNull(): void
{
$creator = $this->createMock(User::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn(null);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->once())
->method('warning')
->with($this->stringContains('saved search not found'));
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSkipsWhenPromptIsNull(): void
{
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn(null);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->logger->expects($this->once())
->method('warning')
->with($this->stringContains('ask anything prompt not found'));
$this->reportService->expects($this->never())->method('getOrCreateReportResult');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleFailsReportWhenNotEnoughActivities(): void
{
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$prompt = $this->createMock(\Jiminny\Models\AskAnything\AskAnythingPrompt::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn($prompt);
$reportResult = $this->createMock(AutomatedReportResult::class);
$reportResult->expects($this->once())
->method('update')
->with($this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_FAILED
&& $data['reason'] === AutomatedReportResult::REASON_NOT_ENOUGH_ACTIVITIES));
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->reportService->expects($this->once())
->method('getOrCreateReportResult')
->willReturn($reportResult);
$this->activityService->expects($this->once())
->method('getActivityIdsForSavedSearch')
->willReturn([]);
$this->logger->expects($this->exactly(3))
->method('info');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleSuccessfullyRequestsReport(): void
{
Carbon::setTestNow(Carbon::parse('2026-04-07 10:00:00'));
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$prompt = $this->createMock(\Jiminny\Models\AskAnything\AskAnythingPrompt::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn($prompt);
$report->method('getUuid')->willReturn('report-uuid');
$reportResult = $this->createMock(AutomatedReportResult::class);
$reportResult->method('getUuid')->willReturn('result-uuid');
$reportResult->expects($this->once())
->method('update')
->with($this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_REQUESTED
&& isset($data['name'], $data['payload'], $data['requested_at'])));
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->reportService->expects($this->once())
->method('getOrCreateReportResult')
->willReturn($reportResult);
$this->reportService->expects($this->once())
->method('getAskJiminnyGenerateReportPayload')
->willReturn(['key' => 'value']);
$this->reportService->expects($this->once())
->method('getReportFileName')
->willReturn('My Report - 7 Apr 2026');
$this->activityService->expects($this->once())
->method('getActivityIdsForSavedSearch')
->willReturn(['act-1', 'act-2']);
$this->prophetClient->expects($this->once())
->method('sendRequest')
->willReturn(new \Jiminny\Component\ProphetAi\Dtos\ProphetResponseDto([]));
$this->logger->expects($this->exactly(4))
->method('info');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
Carbon::setTestNow();
}
public function testHandleCatchesGenericExceptionAndLogsError(): void
{
$this->reportService->expects($this->once())
->method('getReport')
->willThrowException(new \RuntimeException('DB error'));
$this->logger->expects($this->once())
->method('error')
->with($this->stringContains('Error'));
$job = $this->makeJob();
$reflection = new \ReflectionClass($job);
$triesProp = $reflection->getProperty('tries');
$triesProp->setAccessible(true);
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleCatchesProphetExceptionAndSetsCorrectReason(): void
{
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$prompt = $this->createMock(\Jiminny\Models\AskAnything\AskAnythingPrompt::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn($prompt);
$reportResult = $this->createMock(AutomatedReportResult::class);
$reportResult->method('getUuid')->willReturn('result-uuid');
$reportResult->expects($this->once())
->method('update')
->with($this->callback(fn ($data) => $data['reason'] === AutomatedReportResult::REASON_PROPHET_API_ERROR));
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->reportService->expects($this->once())
->method('getOrCreateReportResult')
->willReturn($reportResult);
$this->activityService->expects($this->once())
->method('getActivityIdsForSavedSearch')
->willThrowException(new ProphetException('Prophet failed'));
$this->logger->expects($this->once())
->method('error');
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
public function testHandleCreatesReportResultBeforeActivityFetch(): void
{
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$prompt = $this->createMock(\Jiminny\Models\AskAnything\AskAnythingPrompt::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn($prompt);
$reportResult = $this->createMock(AutomatedReportResult::class);
$reportResult->method('getUuid')->willReturn('result-uuid');
$callOrder = [];
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->reportService->expects($this->once())
->method('getOrCreateReportResult')
->willReturnCallback(function () use ($reportResult, &$callOrder) {
$callOrder[] = 'getOrCreateReportResult';
return $reportResult;
});
$this->activityService->expects($this->once())
->method('getActivityIdsForSavedSearch')
->willReturnCallback(function () use (&$callOrder) {
$callOrder[] = 'getActivityIds';
return [];
});
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
$this->assertEquals(['getOrCreateReportResult', 'getActivityIds'], $callOrder);
}
public function testHandlePassesCorrectDataToCreateReportResult(): void
{
$creator = $this->createMock(User::class);
$savedSearch = $this->createMock(\Jiminny\Models\Activity\Search::class);
$prompt = $this->createMock(\Jiminny\Models\AskAnything\AskAnythingPrompt::class);
$report = $this->makeActiveReport();
$report->method('getCreator')->willReturn($creator);
$report->method('getSavedSearch')->willReturn($savedSearch);
$report->method('getAskAnythingPrompt')->willReturn($prompt);
$reportResult = $this->createMock(AutomatedReportResult::class);
$reportResult->method('getUuid')->willReturn('result-uuid');
$reportResult->method('update')->willReturn(true);
$this->reportService->expects($this->once())
->method('getReport')
->willReturn($report);
$this->reportService->expects($this->once())
->method('getOrCreateReportResult')
->with(
automatedReport: $report,
data: $this->callback(fn ($data) => $data['status'] === AutomatedReportResult::STATUS_DEFAULT
&& $data['media_type'] === AutomatedReportsService::MEDIA_TYPE_PDF)
)
->willReturn($reportResult);
$this->activityService->expects($this->once())
->method('getActivityIdsForSavedSearch')
->willReturn([]);
$job = $this->makeJob();
$job->handle($this->reportService, $this->activityService, $this->prophetClient, $this->logger);
}
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Code changed:
Hide
Sync Changes
Hide This Notification
9
12
2
4
Previous Highlighted Error
Next Highlighted Error
SELECT a.id, a.uuid, a.actual_start_time, o.id, o.uuid FROM opportunities o
JOIN activities a ON o.id = a.opportunity_id
WHERE a.crm_configuration_id = 39
AND a.actual_start_time > '2025-10-13'
AND a.type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM activities
WHERE crm_configuration_id = 39 and user_id = 143
and actual_start_time >= '2025-10-13'
AND type IN ('conference', 'softphone-inbound', 'softphone-outbound')
;
SELECT * FROM opportunities WHERE account_id IN (178);
select * from activities where id IN (620137, 620187, 620188, 620189, 620230);
# HS
SELECT * FROM opportunities WHERE id IN (238);
select * from activities where id IN (477,2076);
select * from users;
SELECT COUNT(*) FROM users;
SELECT COUNT(*) FROM activities;
SELECT COUNT(*) FROM opportunities;
UPDATE activities
SET
actual_start_time = '2025-12-19 09:00:00',
actual_end_time = '2025-12-19 10:30:00',
scheduled_start_time = '2025-12-19 09:00:00',
scheduled_end_time = '2025-12-19 10:30:00'
WHERE id IN (407509,407375);
select * from partners;
SELECT id, uuid, type, actual_start_time, user_id, crm_configuration_id
FROM activities
WHERE user_id = 143
AND actual_start_time >= '2025-10-13 00:00:00'
AND actual_start_time <= '2026-01-13 23:59:59'
ORDER BY actual_start_time DESC;
SELECT * FROM activities WHERE uuid_to_bin('78eda160-3086-435f-88a5-bb0c71b6008d') = uuid;
SELECT * FROM crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 282;
# lead_id
# account_id 177
# contact_id 3969
# opportunity_id
# stage_id 203
SELECT * FROM opportunities WHERE opportunities.crm_configuration_id = id = 282;
SELECT * FROM activities where crm_configuration_id = 39 AND type = 'conference'
AND user_id = 143 and actual_start_time >= '2025-10-13';
SELECT * FROM activities a
# JOIN opportunities o ON a.opportunity_id = o.id
WHERE a.crm_configuration_id = 39 AND a.type = 'conference'
and status = 'completed' and recording_state = 'recorded'
and a.actual_start_time >= '2025-10-13'
AND a.user_id = 143
;
select * from leads
where crm_configuration_id = 39; # 112 -> ac. 178, 109 => op. 1707
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310,407509,407375,356001,356008);
SELECT * FROM activities WHERE id IN (356013,616188,616202,616310);
SELECT * FROM activities WHERE id IN (407509,407375); # leads: 112, 109 | status - 198
SELECT * FROM activities WHERE id IN (356001, 356008); # contacts:
SELECT * FROM opportunities WHERE id IN (1707);
SELECT * FROM stages where id IN (204, 198);
SELECT * FROM opportunities WHERE account_id IN (178);
SELECT * FROM opportunities WHERE crm_configuration_id = 39 AND created_at > '2025-01-01';
SELECT * FROM contacts WHERE account_id IN (178); # 4118 Musaibe, 4448 Ceco Personal
SELECT * FROM activities where crm_configuration_id = 39
AND opportunity_id IS NULL
AND is_internal = false
and status = 'completed' and recording_state = 'recorded'
AND actual_start_time >= '2025-10-13'
AND (lead_id IS NOT NULL OR contact_id IS NOT NULL OR account_id IS NOT NULL)
# AND lead_id IN (112, 109)
;
SELECT * FROM crm_profiles WHERE user_id = 143;
select * from inboxes; # 212
select * from users where id = 143; # 143
select * from inbox_email_batches where inbox_id = 212
and updated_at >= '2026-01-28 00:00:00' order by id desc;
select * from inbox_emails where inbox_id = 212
and batch_id = 95885 order by id desc;
select * from email_messages where origin_user_id = 143;
select * from activities where user_id = 143 and updated_at >= '2026-01-28 00:00:00';
select * from participants where activity_id = 620247;
select * from crm_profiles where user_id = 143;
SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid; # 356001
select * from transcription where activity_id = 356001; # 6943
select * from ai_prompts where transcription_id = 6943;
SELECT * FROM activity_summary_logs where activity_id = 356001;
SELECT * FROM social_accounts WHERE sociable_id = 143;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('0164a4fb-cb95-454e-9edd-4d804e4999bd') = uuid;
# 422515 softphone tr. 8100
SELECT * FROM activities WHERE uuid_to_bin('7520add8-8d87-41a5-98e5-fc4edf96f21e') = uuid;
# 407509 conference tr. 7670 crmId: 00UD1000002J9aTMAS
select * from ai_prompts where transcription_id IN (8100, 7670);
select * from activity_summary_logs where activity_id = 407509;
select * from sidekick_settings;
select * from default_activity_types;
SELECT * FROM contacts WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM leads WHERE crm_configuration_id = 39 and email = '[EMAIL]';
SELECT * FROM activity_searches where user_id = 143;
SELECT * FROM groups where team_id = 1;
select * from teams where id = 1;
select * from groups where team_id = 1; # 1150 - 7e75f8025c22
select id, name, group_id, status, deleted_at, email
from users where team_id = 1 order by group_id desc ;
select * from activity_searches where id in (1977, 1978, 1979);
select * from activity_search_filters where activity_search_id IN (1977, 1978, 1979);
select * from activity_search_filters where filter = 'group_id' and value = '443f26b8-8512-437e-a9f9-7e75f8025c22'; # 10268, 10272, 10277
select * from nudges where activity_search_id IN (1977, 1978, 1979); # 877, 878, 879
INSERT INTO `activity_search_filters`
(`activity_search_id`, `filter`, `value`) VALUES
(1977, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1978, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22'),
(1979, 'group_id', '443f26b8-8512-437e-a9f9-7e75f8025c22')
;
select * from crm_configurations where id = 39;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from features;
SELECT * FROM activity_searches where id = 1982; # 1981
SELECT * FROM activity_search_filters WHERE activity_search_id = 1982;
SELECT * FROM automated_reports where id = 68;
SELECT * FROM automated_report_results where id = 275;
SELECT * FROM automated_reports order by id desc;
SELECT * FROM automated_report_results order by id desc;
select * from activity_searches where user_id = 143;
select * from ask_anything_prompts;
SELECT * FROM groups WHERE id = 1439;
SELECT * FROM users WHERE group_id = 1439;
select * from permissions; # 158
select * from roles;
select * from permission_role
select * from teams where id = 1;
select * from groups g JOIN playbooks p on g.playbook_id = p.id where g.team_id = 1;
select * from groups where id = 28;
select * from playbooks where team_id = 1;
select * from playbooks where id = 179;
select * from playbook_categories where id = 1391;
select * from users where id = 143;
select * from crm_profiles where user_id = 143;
select * from activities where crm_configuration_id = 39 and type = 'conference'
and crm_provider_id IS NOT NULL ORDER by id desc;
select * from activities where id = 422003; # 00UO400000pB6fpMAC
SELECT ar.id, ar.uuid, ar.media_type, ar.status, a.type
FROM automated_report_results ar
JOIN automated_reports a ON a.id = ar.report_id
WHERE a.type = 'ask_jiminny'
LIMIT 10;
select * from teams where id = 3143;
select * from crm_configurations where id = 500;
select * from users where name = 'Integration Account'; # 1695
SELECT * FROM social_accounts WHERE sociable_id = 1695;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
|
54371
|
NULL
|
0
|
2026-04-20T08:56:45.659830+00:00
|
/Users/lukas/.screenpipe/data/data/2026-04-20/1776 /Users/lukas/.screenpipe/data/data/2026-04-20/1776675405659_m2.jpg...
|
Firefox
|
Jiminny — Work
|
True
|
app.jiminny.com/dashboard
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
[JY-20543] AJ Reports > Tracking - Jira
[JY-20543] AJ Reports > Tracking - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira
Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app
Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app
New Tab
New Tab
Product Growth Platform | Userpilot
Product Growth Platform | Userpilot
Userpilot | Logged-activity
Userpilot | Logged-activity
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Feed — jiminny — Sentry
Feed — jiminny — Sentry
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
1
1
My Recordings
My Recordings
Team Recordings
Team Recordings
Everyone's Recordings
Everyone's Recordings
Unknown Customer
Notetaker added on 05-15-23 @ 20:45
15 May, 2023, 8:47 PM
Schedule
Schedule
Invite Notetaker
This Week
This Week
My Schedule
My Schedule
No Meetings
Trending this month
Trending this month
Sort by Sort by: Most played
Sort by
Sort by:
Most played
Miles Weeks at Cloud Gateway
Miles Weeks and Zornitsa Dzhongova
Miles Weeks and Zornitsa Dzhongova
4
times played
Unknown Customer
Steve Lazarus and Greg Moser
Steve Lazarus and Greg Moser
4
times played
David Roberts at Sigma Labs
Jiminny Onboarding Workshop
Jiminny Onboarding Workshop
2
times played
Tony Lombardo at AutoLeap
Meeting with Oliver
Meeting with Oliver
2
times played
Graeme Hennessey at RealTime eClinical Solutions
Meet with Becky from Jiminny 🚀
Meet with Becky from Jiminny 🚀
2
times played
Tom Daniels at Worldover
Worldover Onboarding Workshop
Worldover Onboarding Workshop
2
times played
Will Pagden at Rosterfy
Rosterfy & Jiminny [Intro call]
Rosterfy & Jiminny [Intro call]
2
times played
Todd Upchurch at LeadVenture
Jiminny - sync (Lauren & Todd)
Jiminny - sync (Lauren & Todd)
2
times played
Alex Bogumil at Cognitive Credit
Alex & Gabby Jiminny Customisations Alignment
Alex & Gabby Jiminny Customisations Alignment
2
times played
Phil Hart at Oxford Medical Simulation
🚀 Meet with Oliver from Jiminny
🚀 Meet with Oliver from Jiminny
2
times played
Melanie Yu Yu at Unibuddy
Jiminny <> Unibuddy (weekly acceleration!)
Jiminny <> Unibuddy (weekly acceleration!)
2
times played
Jack Wilson at Akixi
Akixi & Jiminny Onboarding Workshop 🚀
Akixi & Jiminny Onboarding Workshop 🚀
1
times played
Kelly Atkins at BT Local Business Severnside
BT Coventry & Jiminny
BT Coventry & Jiminny
1
times played
Kerensa Martin at CreateFuture
Jiminny x CF - Connect to Jiminny :)
Jiminny x CF - Connect to Jiminny :)
1
times played
Philipp Kronsteiner at DocPlanner
Meeting with Oliver
Meeting with Oliver
1
times played
Rachel Hand at Storage King
🚀 Meet with Becky from Jiminny
🚀 Meet with Becky from Jiminny
1
times played
Zilch
🚀 Meet with Becky from Jiminny
🚀 Meet with Becky from Jiminny
1
times played
Johnathan Berryman at INSURITAS
Jiminny + VIU by HUB/Insuritas Touchbase-Monthly
Jiminny + VIU by HUB/Insuritas Touchbase-Monthly
1
times played
Adriana Voyce at Credentially
Meeting with Stoyan 🚀 (Adriana Voyce)
Meeting with Stoyan 🚀 (Adriana Voyce)
1
times played
Melissa Desousa at Lloyd's List Intelligence
Melissa De Sousa and Petko Kashinski
Melissa De Sousa and Petko Kashinski
1
times played
Oscar Linares at Storyclash GmbH
Oscar Linares and Petko Kashinski
Oscar Linares and Petko Kashinski
1
times played
Graeme Hennessey at RealTime eClinical Solutions
Jiminny - Commercials Review & Next Steps 🚀
Jiminny - Commercials Review & Next Steps 🚀
1
times played
Base.com
Jiminny x Base - Commercials & Next Steps
Jiminny x Base - Commercials & Next Steps
1
times played
Belen Conteri at Superside
Belen Conteri and Lauren Hudson
Belen Conteri and Lauren Hudson
1
times played
Thomas Baxter at John Galt Solutions
🚀 Meet with Becky from Jiminny
🚀 Meet with Becky from Jiminny
1
times played
Live Feed
Live Feed
Gabriela Dureva
listened to call
Today, 11:42 AM
Decision / Closing
with
Hakeem Oloritun
Held:
28 Jan, 6:00 PM
Duration:
27m
Value:
$34,877
Calum Scott
listened to call
17 Apr, 7:26 PM
Proposal / Next Steps
with
Holger Marggraf
Held:
20 Feb, 11:00 AM
Duration:
42m
Value:
€0
Becky Butler
listened to call
17 Apr, 3:41 PM
Web Demo
with
Scott Ferguson
Held:
20 Mar, 11:29 AM
Duration:
1h
Value:
$7,620
Oliver Harris
listened to call
17 Apr, 3:34 PM
Web Demo
with
Scott Ferguson
Held:
20 Mar, 11:29 AM
Duration:
1h
Value:
$7,620
Petko Kashinski
listened to call
17 Apr, 10:01 AM
cold call
with
unknown customer
Held:
16 Apr, 4:35 PM
Duration:
1m
Value:
$0
Petko Kashinski
listened to call
17 Apr, 9:43 AM
Refresher Session
with
Melanie Yu Yu
Held:
9 Apr, 5:58 PM
Duration:
30m
Value:
$0
Zornitsa Dzhongova
listened to call
16 Apr, 4:16 PM
Discovery Call (upsell)
with
Oscar Linares
Held:
15 Apr, 3:30 PM
Duration:
32m
Value:
$11,875
Mario Georgiev
listened to call
16 Apr, 2:59 PM
Support / Troubleshooting
with
Adriana Voyce
Held:
15 Apr, 7:28 PM...
|
[{"role":"AXRadioButton","text [{"role":"AXRadioButton","text":"Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira","depth":4,"bounds":{"left":0.0018284575,"top":0.0518755,"width":0.07596409,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXRadioButton","text":"JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.09497207,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.10614525,"width":0.15774602,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[SRD-6793] Les Mills activity types not pulling in - Jira","depth":4,"bounds":{"left":0.0,"top":0.12769353,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[SRD-6793] Les Mills activity types not pulling in - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.13886672,"width":0.09524601,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.16041501,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.17158818,"width":0.19963431,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.19313647,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.20430966,"width":0.15525267,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-20543] AJ Reports > Tracking - Jira","depth":4,"bounds":{"left":0.0,"top":0.22585794,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-20543] AJ Reports > Tracking - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.23703113,"width":0.06981383,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira","depth":4,"bounds":{"left":0.0,"top":0.2585794,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira","depth":5,"bounds":{"left":0.013297873,"top":0.2697526,"width":0.10688165,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.29130086,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.30247405,"width":0.12915559,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"New Tab","depth":4,"bounds":{"left":0.0,"top":0.32402235,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"New Tab","depth":5,"bounds":{"left":0.013297873,"top":0.33519554,"width":0.014960106,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Product Growth Platform | Userpilot","depth":4,"bounds":{"left":0.0,"top":0.3567438,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Product Growth Platform | Userpilot","depth":5,"bounds":{"left":0.013297873,"top":0.367917,"width":0.06200133,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Userpilot | Logged-activity","depth":4,"bounds":{"left":0.0,"top":0.38946527,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Userpilot | Logged-activity","depth":5,"bounds":{"left":0.013297873,"top":0.40063846,"width":0.04637633,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.42218676,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.43335995,"width":0.2052859,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Pipelines - jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.45490822,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Pipelines - jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.4660814,"width":0.039228722,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Feed — jiminny — Sentry","depth":4,"bounds":{"left":0.0,"top":0.48762968,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Feed — jiminny — Sentry","depth":5,"bounds":{"left":0.013297873,"top":0.49880287,"width":0.042719416,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app","depth":4,"bounds":{"left":0.0,"top":0.5203512,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app","depth":5,"bounds":{"left":0.013297873,"top":0.53152436,"width":0.2052859,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.55307263,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.5642458,"width":0.013131649,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.5857941,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.5969673,"width":0.013131649,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Jiminny","depth":4,"bounds":{"left":0.0,"top":0.61851555,"width":0.07962101,"height":0.032721467},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"Jiminny","depth":5,"bounds":{"left":0.013297873,"top":0.62968874,"width":0.013131649,"height":0.010774142},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Close tab","depth":5,"bounds":{"left":0.06732048,"top":0.6256983,"width":0.007978723,"height":0.01915403},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"New Tab","depth":4,"bounds":{"left":0.0028257978,"top":0.6528332,"width":0.07413564,"height":0.025538707},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Customize sidebar","depth":6,"bounds":{"left":0.0028257978,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open Google Gemini (⌃X)","depth":6,"bounds":{"left":0.013796543,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Tabs from other devices","depth":6,"bounds":{"left":0.024933511,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open history (⇧⌘H)","depth":6,"bounds":{"left":0.036070477,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXCheckBox","text":"Open bookmarks (⌘B)","depth":6,"bounds":{"left":0.04720745,"top":0.97007185,"width":0.010638298,"height":0.025538707},"help_text":"","role_description":"toggle button","subrole":"AXToggle","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXButton","text":"1","depth":12,"bounds":{"left":0.08228058,"top":0.91380686,"width":0.015957447,"height":0.035115723},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"1","depth":14,"bounds":{"left":0.091755316,"top":0.9173983,"width":0.0023271276,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"My Recordings","depth":14,"bounds":{"left":0.15209441,"top":0.07182761,"width":0.061170213,"height":0.052673582},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":true},{"role":"AXStaticText","text":"My Recordings","depth":15,"bounds":{"left":0.1653923,"top":0.0905826,"width":0.034574468,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Team Recordings","depth":14,"bounds":{"left":0.21326463,"top":0.07182761,"width":0.065990694,"height":0.052673582},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Team Recordings","depth":15,"bounds":{"left":0.2265625,"top":0.0905826,"width":0.03939495,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXRadioButton","text":"Everyone's Recordings","depth":14,"bounds":{"left":0.27925533,"top":0.07182761,"width":0.07895612,"height":0.052673582},"help_text":"","role_description":"tab","subrole":"AXTabButton","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Everyone's Recordings","depth":15,"bounds":{"left":0.2925532,"top":0.0905826,"width":0.05236037,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":17,"bounds":{"left":0.14079122,"top":0.14604948,"width":0.04155585,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Notetaker added on 05-15-23 @ 20:45","depth":18,"bounds":{"left":0.14079122,"top":0.16679968,"width":0.079953454,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"15 May, 2023, 8:47 PM","depth":17,"bounds":{"left":0.14079122,"top":0.18754987,"width":0.047706116,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Schedule","depth":13,"bounds":{"left":0.40608376,"top":0.27214685,"width":0.029421542,"height":0.025538707},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Schedule","depth":14,"bounds":{"left":0.40608376,"top":0.27414206,"width":0.029421542,"height":0.021548284},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXButton","text":"Invite Notetaker","depth":14,"bounds":{"left":0.65026593,"top":0.2697526,"width":0.044215426,"height":0.028731046},"help_text":"","role_description":"button","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXComboBox","text":"This Week","depth":14,"bounds":{"left":0.41107047,"top":0.31763768,"width":0.13763298,"height":0.02952913},"value":"This Week","help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"This Week","depth":17,"bounds":{"left":0.4147274,"top":0.3256185,"width":0.021775266,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXComboBox","text":"My Schedule","depth":14,"bounds":{"left":0.55202794,"top":0.31763768,"width":0.13746676,"height":0.02952913},"value":"My Schedule","help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"My Schedule","depth":17,"bounds":{"left":0.55568486,"top":0.3256185,"width":0.02642952,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"No Meetings","depth":16,"bounds":{"left":0.53706783,"top":0.69193935,"width":0.02642952,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Trending this month","depth":13,"bounds":{"left":0.41107047,"top":0.08858739,"width":0.046210106,"height":0.01915403},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Trending this month","depth":14,"bounds":{"left":0.41107047,"top":0.0905826,"width":0.046210106,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXComboBox","text":"Sort by Sort by: Most played","depth":13,"bounds":{"left":0.62101066,"top":0.08339984,"width":0.068484046,"height":0.02952913},"value":"Sort by Sort by: Most played","help_text":"","role_description":"combo box","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"Sort by","depth":14,"help_text":"","role_description":"text field","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Sort by:","depth":15,"bounds":{"left":0.6246675,"top":0.091380686,"width":0.016954787,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Most played","depth":15,"bounds":{"left":0.64162236,"top":0.091380686,"width":0.025930852,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Miles Weeks at Cloud Gateway","depth":16,"bounds":{"left":0.51363033,"top":0.18036711,"width":0.06665558,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Miles Weeks and Zornitsa Dzhongova","depth":15,"bounds":{"left":0.50681514,"top":0.1991221,"width":0.08693484,"height":0.011971269},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Miles Weeks and Zornitsa Dzhongova","depth":16,"bounds":{"left":0.51678854,"top":0.1991221,"width":0.06698803,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4","depth":16,"bounds":{"left":0.5511968,"top":0.2150838,"width":0.005319149,"height":0.019553073},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"bounds":{"left":0.54105717,"top":0.23144454,"width":0.01861702,"height":0.009976057},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Unknown Customer","depth":16,"bounds":{"left":0.813996,"top":0.18036711,"width":0.043218084,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Steve Lazarus and Greg Moser","depth":15,"bounds":{"left":0.8018617,"top":0.1991221,"width":0.07396942,"height":0.011971269},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Steve Lazarus and Greg Moser","depth":16,"bounds":{"left":0.8118351,"top":0.1991221,"width":0.054022606,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"4","depth":16,"bounds":{"left":0.83976066,"top":0.2150838,"width":0.005319149,"height":0.019553073},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"bounds":{"left":0.829621,"top":0.23144454,"width":0.01861702,"height":0.009976057},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"David Roberts at Sigma Labs","depth":16,"bounds":{"left":1.0,"top":0.18036711,"width":-0.09375,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny Onboarding Workshop","depth":15,"bounds":{"left":1.0,"top":0.1991221,"width":-0.08976066,"height":0.011971269},"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny Onboarding Workshop","depth":16,"bounds":{"left":1.0,"top":0.1991221,"width":-0.09973407,"height":0.011971269},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tony Lombardo at AutoLeap","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Meeting with Oliver","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Meeting with Oliver","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Graeme Hennessey at RealTime eClinical Solutions","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Meet with Becky from Jiminny 🚀","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Meet with Becky from Jiminny 🚀","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Tom Daniels at Worldover","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Worldover Onboarding Workshop","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Worldover Onboarding Workshop","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Will Pagden at Rosterfy","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Rosterfy & Jiminny [Intro call]","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Rosterfy & Jiminny [Intro call]","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Todd Upchurch at LeadVenture","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny - sync (Lauren & Todd)","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny - sync (Lauren & Todd)","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Alex Bogumil at Cognitive Credit","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Alex & Gabby Jiminny Customisations Alignment","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Alex & Gabby Jiminny Customisations Alignment","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Phil Hart at Oxford Medical Simulation","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"🚀 Meet with Oliver from Jiminny","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"🚀 Meet with Oliver from Jiminny","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Melanie Yu Yu at Unibuddy","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny <> Unibuddy (weekly acceleration!)","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny <> Unibuddy (weekly acceleration!)","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"2","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Jack Wilson at Akixi","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Akixi & Jiminny Onboarding Workshop 🚀","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Akixi & Jiminny Onboarding Workshop 🚀","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Kelly Atkins at BT Local Business Severnside","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"BT Coventry & Jiminny","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"BT Coventry & Jiminny","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Kerensa Martin at CreateFuture","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny x CF - Connect to Jiminny :)","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny x CF - Connect to Jiminny :)","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Philipp Kronsteiner at DocPlanner","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Meeting with Oliver","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Meeting with Oliver","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Rachel Hand at Storage King","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"🚀 Meet with Becky from Jiminny","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"🚀 Meet with Becky from Jiminny","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Zilch","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"🚀 Meet with Becky from Jiminny","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"🚀 Meet with Becky from Jiminny","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Johnathan Berryman at INSURITAS","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny + VIU by HUB/Insuritas Touchbase-Monthly","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny + VIU by HUB/Insuritas Touchbase-Monthly","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Adriana Voyce at Credentially","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Meeting with Stoyan 🚀 (Adriana Voyce)","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Meeting with Stoyan 🚀 (Adriana Voyce)","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Melissa Desousa at Lloyd's List Intelligence","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Melissa De Sousa and Petko Kashinski","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Melissa De Sousa and Petko Kashinski","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Oscar Linares at Storyclash GmbH","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Oscar Linares and Petko Kashinski","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Oscar Linares and Petko Kashinski","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Graeme Hennessey at RealTime eClinical Solutions","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny - Commercials Review & Next Steps 🚀","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny - Commercials Review & Next Steps 🚀","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Base.com","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Jiminny x Base - Commercials & Next Steps","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Jiminny x Base - Commercials & Next Steps","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Belen Conteri at Superside","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"Belen Conteri and Lauren Hudson","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"Belen Conteri and Lauren Hudson","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Thomas Baxter at John Galt Solutions","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXLink","text":"🚀 Meet with Becky from Jiminny","depth":15,"help_text":"","role_description":"link","subrole":"AXUnknown","is_enabled":true,"is_focused":false,"is_selected":false},{"role":"AXStaticText","text":"🚀 Meet with Becky from Jiminny","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1","depth":16,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"times played","depth":17,"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXHeading","text":"Live Feed","depth":13,"bounds":{"left":0.70611703,"top":0.08858739,"width":0.021941489,"height":0.01915403},"help_text":"","role_description":"heading","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Live Feed","depth":14,"bounds":{"left":0.70611703,"top":0.0905826,"width":0.021941489,"height":0.01556265},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Gabriela Dureva","depth":18,"bounds":{"left":0.72772604,"top":0.14086193,"width":0.034075797,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"listened to call","depth":18,"bounds":{"left":0.7634641,"top":0.14086193,"width":0.02925532,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Today, 11:42 AM","depth":18,"bounds":{"left":0.9489694,"top":0.14046289,"width":0.034075797,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Decision / Closing","depth":18,"bounds":{"left":0.72772604,"top":0.17158818,"width":0.03706782,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":18,"bounds":{"left":0.76579124,"top":0.17158818,"width":0.008976064,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Hakeem Oloritun","depth":18,"bounds":{"left":0.77576464,"top":0.17158818,"width":0.036070477,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Held:","depth":18,"bounds":{"left":0.73537236,"top":0.20909816,"width":0.010472074,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"28 Jan, 6:00 PM","depth":18,"bounds":{"left":0.7465093,"top":0.20909816,"width":0.030086435,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Duration:","depth":18,"bounds":{"left":0.8490692,"top":0.20909816,"width":0.01861702,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"27m","depth":18,"bounds":{"left":0.86835104,"top":0.20909816,"width":0.008477394,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Value:","depth":18,"bounds":{"left":0.94930184,"top":0.20909816,"width":0.012134309,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$34,877","depth":18,"bounds":{"left":0.96210104,"top":0.20909816,"width":0.015957447,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Calum Scott","depth":18,"bounds":{"left":0.72772604,"top":0.25418994,"width":0.025265958,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"listened to call","depth":18,"bounds":{"left":0.7546542,"top":0.25418994,"width":0.02925532,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17 Apr, 7:26 PM","depth":18,"bounds":{"left":0.9502992,"top":0.25379092,"width":0.03274601,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Proposal / Next Steps","depth":18,"bounds":{"left":0.72772604,"top":0.2849162,"width":0.044714097,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":18,"bounds":{"left":0.77327126,"top":0.2849162,"width":0.009142287,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Holger Marggraf","depth":18,"bounds":{"left":0.78324467,"top":0.2849162,"width":0.034574468,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Held:","depth":18,"bounds":{"left":0.73537236,"top":0.32242617,"width":0.010472074,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20 Feb, 11:00 AM","depth":18,"bounds":{"left":0.7465093,"top":0.32242617,"width":0.033410903,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Duration:","depth":18,"bounds":{"left":0.8562167,"top":0.32242617,"width":0.018450798,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"42m","depth":18,"bounds":{"left":0.8753325,"top":0.32242617,"width":0.008643617,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Value:","depth":18,"bounds":{"left":0.9602726,"top":0.32242617,"width":0.012134309,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"€0","depth":18,"bounds":{"left":0.9730718,"top":0.32242617,"width":0.004986702,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Becky Butler","depth":18,"bounds":{"left":0.72772604,"top":0.36751795,"width":0.026928192,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"listened to call","depth":18,"bounds":{"left":0.7563165,"top":0.36751795,"width":0.02925532,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17 Apr, 3:41 PM","depth":18,"bounds":{"left":0.9502992,"top":0.36711892,"width":0.03274601,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Web Demo","depth":18,"bounds":{"left":0.72772604,"top":0.3982442,"width":0.0234375,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":18,"bounds":{"left":0.75199467,"top":0.3982442,"width":0.009142287,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Scott Ferguson","depth":18,"bounds":{"left":0.7619681,"top":0.3982442,"width":0.031083776,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Held:","depth":18,"bounds":{"left":0.73537236,"top":0.43575418,"width":0.010472074,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20 Mar, 11:29 AM","depth":18,"bounds":{"left":0.7465093,"top":0.43575418,"width":0.034075797,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Duration:","depth":18,"bounds":{"left":0.8540558,"top":0.43575418,"width":0.01861702,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1h","depth":18,"bounds":{"left":0.87333775,"top":0.43575418,"width":0.0048204786,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Value:","depth":18,"bounds":{"left":0.9517952,"top":0.43575418,"width":0.012134309,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$7,620","depth":18,"bounds":{"left":0.9645944,"top":0.43575418,"width":0.013464096,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Oliver Harris","depth":18,"bounds":{"left":0.72772604,"top":0.48084596,"width":0.027094414,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"listened to call","depth":18,"bounds":{"left":0.7564827,"top":0.48084596,"width":0.02925532,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17 Apr, 3:34 PM","depth":18,"bounds":{"left":0.9502992,"top":0.48044693,"width":0.03274601,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Web Demo","depth":18,"bounds":{"left":0.72772604,"top":0.51157224,"width":0.0234375,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":18,"bounds":{"left":0.75199467,"top":0.51157224,"width":0.009142287,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Scott Ferguson","depth":18,"bounds":{"left":0.7619681,"top":0.51157224,"width":0.031083776,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Held:","depth":18,"bounds":{"left":0.73537236,"top":0.5490822,"width":0.010472074,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"20 Mar, 11:29 AM","depth":18,"bounds":{"left":0.7465093,"top":0.5490822,"width":0.034075797,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Duration:","depth":18,"bounds":{"left":0.8540558,"top":0.5490822,"width":0.01861702,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1h","depth":18,"bounds":{"left":0.87333775,"top":0.5490822,"width":0.0048204786,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Value:","depth":18,"bounds":{"left":0.9517952,"top":0.5490822,"width":0.012134309,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$7,620","depth":18,"bounds":{"left":0.9645944,"top":0.5490822,"width":0.013464096,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Petko Kashinski","depth":18,"bounds":{"left":0.72772604,"top":0.59417397,"width":0.03324468,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"listened to call","depth":18,"bounds":{"left":0.76263297,"top":0.59417397,"width":0.02925532,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17 Apr, 10:01 AM","depth":18,"bounds":{"left":0.94730717,"top":0.5937749,"width":0.035738032,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"cold call","depth":18,"bounds":{"left":0.72772604,"top":0.6249002,"width":0.016954787,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":18,"bounds":{"left":0.74551195,"top":0.6249002,"width":0.009142287,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"unknown customer","depth":18,"bounds":{"left":0.75548536,"top":0.6249002,"width":0.040059842,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Held:","depth":18,"bounds":{"left":0.73537236,"top":0.6624102,"width":0.010472074,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"16 Apr, 4:35 PM","depth":18,"bounds":{"left":0.7465093,"top":0.6624102,"width":0.030418882,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Duration:","depth":18,"bounds":{"left":0.8558843,"top":0.6624102,"width":0.01861702,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"1m","depth":18,"bounds":{"left":0.87516624,"top":0.6624102,"width":0.005984043,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Value:","depth":18,"bounds":{"left":0.9602726,"top":0.6624102,"width":0.012134309,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$0","depth":18,"bounds":{"left":0.9730718,"top":0.6624102,"width":0.004986702,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Petko Kashinski","depth":18,"bounds":{"left":0.72772604,"top":0.707502,"width":0.03324468,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"listened to call","depth":18,"bounds":{"left":0.76263297,"top":0.707502,"width":0.02925532,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"17 Apr, 9:43 AM","depth":18,"bounds":{"left":0.9499667,"top":0.70710295,"width":0.03307846,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Refresher Session","depth":18,"bounds":{"left":0.72772604,"top":0.73822826,"width":0.03723404,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":18,"bounds":{"left":0.76579124,"top":0.73822826,"width":0.009142287,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Melanie Yu Yu","depth":18,"bounds":{"left":0.77576464,"top":0.73822826,"width":0.029587766,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Held:","depth":18,"bounds":{"left":0.73537236,"top":0.77573824,"width":0.010472074,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"9 Apr, 5:58 PM","depth":18,"bounds":{"left":0.7465093,"top":0.77573824,"width":0.027925532,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Duration:","depth":18,"bounds":{"left":0.85339093,"top":0.77573824,"width":0.01861702,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"30m","depth":18,"bounds":{"left":0.87267286,"top":0.77573824,"width":0.008477394,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Value:","depth":18,"bounds":{"left":0.9602726,"top":0.77573824,"width":0.012134309,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$0","depth":18,"bounds":{"left":0.9730718,"top":0.77573824,"width":0.004986702,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Zornitsa Dzhongova","depth":18,"bounds":{"left":0.72772604,"top":0.82083,"width":0.042054523,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"listened to call","depth":18,"bounds":{"left":0.77144283,"top":0.82083,"width":0.02925532,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"16 Apr, 4:16 PM","depth":18,"bounds":{"left":0.9502992,"top":0.820431,"width":0.03274601,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Discovery Call (upsell)","depth":18,"bounds":{"left":0.72772604,"top":0.85155624,"width":0.045877658,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":18,"bounds":{"left":0.77460104,"top":0.85155624,"width":0.008976064,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Oscar Linares","depth":18,"bounds":{"left":0.78457445,"top":0.85155624,"width":0.02825798,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Held:","depth":18,"bounds":{"left":0.73537236,"top":0.8890662,"width":0.010472074,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"15 Apr, 3:30 PM","depth":18,"bounds":{"left":0.7465093,"top":0.8890662,"width":0.030418882,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Duration:","depth":18,"bounds":{"left":0.84923536,"top":0.8890662,"width":0.018450798,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"32m","depth":18,"bounds":{"left":0.86835104,"top":0.8890662,"width":0.008643617,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Value:","depth":18,"bounds":{"left":0.94930184,"top":0.8890662,"width":0.012134309,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"$11,875","depth":18,"bounds":{"left":0.96210104,"top":0.8890662,"width":0.015957447,"height":0.012769354},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Mario Georgiev","depth":18,"bounds":{"left":0.72772604,"top":0.934158,"width":0.032579787,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"listened to call","depth":18,"bounds":{"left":0.7619681,"top":0.934158,"width":0.029089095,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"16 Apr, 2:59 PM","depth":18,"bounds":{"left":0.9502992,"top":0.933759,"width":0.03274601,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Support / Troubleshooting","depth":18,"bounds":{"left":0.72772604,"top":0.9648843,"width":0.054521278,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"with","depth":18,"bounds":{"left":0.78307843,"top":0.9648843,"width":0.009142287,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Adriana Voyce","depth":18,"bounds":{"left":0.79305184,"top":0.9648843,"width":0.03025266,"height":0.013567438},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"Held:","depth":18,"bounds":{"left":0.73537236,"top":1.0,"width":0.010472074,"height":-0.0023941994},"help_text":"","role_description":"text","subrole":"AXUnknown"},{"role":"AXStaticText","text":"15 Apr, 7:28 PM","depth":18,"bounds":{"left":0.7465093,"top":1.0,"width":0.030418882,"height":-0.0023941994},"help_text":"","role_description":"text","subrole":"AXUnknown"}]...
|
-4143135670630223683
|
-674061312079434720
|
click
|
accessibility
|
NULL
|
Platform Sprint 2 Q2 - Platform Team - Scrum Board Platform Sprint 2 Q2 - Platform Team - Scrum Board - Jira
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
JY-20553 | Improve crm-sync delays by yalokin-jiminny · Pull Request #11976 · jiminny/app
[SRD-6793] Les Mills activity types not pulling in - Jira
[SRD-6793] Les Mills activity types not pulling in - Jira
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20698 handle failed field sync on playbook import activity types by LakyLak · Pull Request #11988 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
JY-20692 change confirmation parameter by LakyLak · Pull Request #11986 · jiminny/app
[JY-20543] AJ Reports > Tracking - Jira
[JY-20543] AJ Reports > Tracking - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira
[JY-18909] [Part2] Automated reports with Ask Jiminny - Jira
Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app
Ask Jiminny Reports by nikolay-yankov · Pull Request #11894 · jiminny/app
New Tab
New Tab
Product Growth Platform | Userpilot
Product Growth Platform | Userpilot
Userpilot | Logged-activity
Userpilot | Logged-activity
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
Pipelines - jiminny/app
Pipelines - jiminny/app
Feed — jiminny — Sentry
Feed — jiminny — Sentry
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
fix(security): composer dependency updates – 2026-04-15 by github-actions[bot] · Pull Request #11970 · jiminny/app
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Jiminny
Close tab
New Tab
Customize sidebar
Open Google Gemini (⌃X)
Tabs from other devices
Open history (⇧⌘H)
Open bookmarks (⌘B)
1
1
My Recordings
My Recordings
Team Recordings
Team Recordings
Everyone's Recordings
Everyone's Recordings
Unknown Customer
Notetaker added on 05-15-23 @ 20:45
15 May, 2023, 8:47 PM
Schedule
Schedule
Invite Notetaker
This Week
This Week
My Schedule
My Schedule
No Meetings
Trending this month
Trending this month
Sort by Sort by: Most played
Sort by
Sort by:
Most played
Miles Weeks at Cloud Gateway
Miles Weeks and Zornitsa Dzhongova
Miles Weeks and Zornitsa Dzhongova
4
times played
Unknown Customer
Steve Lazarus and Greg Moser
Steve Lazarus and Greg Moser
4
times played
David Roberts at Sigma Labs
Jiminny Onboarding Workshop
Jiminny Onboarding Workshop
2
times played
Tony Lombardo at AutoLeap
Meeting with Oliver
Meeting with Oliver
2
times played
Graeme Hennessey at RealTime eClinical Solutions
Meet with Becky from Jiminny 🚀
Meet with Becky from Jiminny 🚀
2
times played
Tom Daniels at Worldover
Worldover Onboarding Workshop
Worldover Onboarding Workshop
2
times played
Will Pagden at Rosterfy
Rosterfy & Jiminny [Intro call]
Rosterfy & Jiminny [Intro call]
2
times played
Todd Upchurch at LeadVenture
Jiminny - sync (Lauren & Todd)
Jiminny - sync (Lauren & Todd)
2
times played
Alex Bogumil at Cognitive Credit
Alex & Gabby Jiminny Customisations Alignment
Alex & Gabby Jiminny Customisations Alignment
2
times played
Phil Hart at Oxford Medical Simulation
🚀 Meet with Oliver from Jiminny
🚀 Meet with Oliver from Jiminny
2
times played
Melanie Yu Yu at Unibuddy
Jiminny <> Unibuddy (weekly acceleration!)
Jiminny <> Unibuddy (weekly acceleration!)
2
times played
Jack Wilson at Akixi
Akixi & Jiminny Onboarding Workshop 🚀
Akixi & Jiminny Onboarding Workshop 🚀
1
times played
Kelly Atkins at BT Local Business Severnside
BT Coventry & Jiminny
BT Coventry & Jiminny
1
times played
Kerensa Martin at CreateFuture
Jiminny x CF - Connect to Jiminny :)
Jiminny x CF - Connect to Jiminny :)
1
times played
Philipp Kronsteiner at DocPlanner
Meeting with Oliver
Meeting with Oliver
1
times played
Rachel Hand at Storage King
🚀 Meet with Becky from Jiminny
🚀 Meet with Becky from Jiminny
1
times played
Zilch
🚀 Meet with Becky from Jiminny
🚀 Meet with Becky from Jiminny
1
times played
Johnathan Berryman at INSURITAS
Jiminny + VIU by HUB/Insuritas Touchbase-Monthly
Jiminny + VIU by HUB/Insuritas Touchbase-Monthly
1
times played
Adriana Voyce at Credentially
Meeting with Stoyan 🚀 (Adriana Voyce)
Meeting with Stoyan 🚀 (Adriana Voyce)
1
times played
Melissa Desousa at Lloyd's List Intelligence
Melissa De Sousa and Petko Kashinski
Melissa De Sousa and Petko Kashinski
1
times played
Oscar Linares at Storyclash GmbH
Oscar Linares and Petko Kashinski
Oscar Linares and Petko Kashinski
1
times played
Graeme Hennessey at RealTime eClinical Solutions
Jiminny - Commercials Review & Next Steps 🚀
Jiminny - Commercials Review & Next Steps 🚀
1
times played
Base.com
Jiminny x Base - Commercials & Next Steps
Jiminny x Base - Commercials & Next Steps
1
times played
Belen Conteri at Superside
Belen Conteri and Lauren Hudson
Belen Conteri and Lauren Hudson
1
times played
Thomas Baxter at John Galt Solutions
🚀 Meet with Becky from Jiminny
🚀 Meet with Becky from Jiminny
1
times played
Live Feed
Live Feed
Gabriela Dureva
listened to call
Today, 11:42 AM
Decision / Closing
with
Hakeem Oloritun
Held:
28 Jan, 6:00 PM
Duration:
27m
Value:
$34,877
Calum Scott
listened to call
17 Apr, 7:26 PM
Proposal / Next Steps
with
Holger Marggraf
Held:
20 Feb, 11:00 AM
Duration:
42m
Value:
€0
Becky Butler
listened to call
17 Apr, 3:41 PM
Web Demo
with
Scott Ferguson
Held:
20 Mar, 11:29 AM
Duration:
1h
Value:
$7,620
Oliver Harris
listened to call
17 Apr, 3:34 PM
Web Demo
with
Scott Ferguson
Held:
20 Mar, 11:29 AM
Duration:
1h
Value:
$7,620
Petko Kashinski
listened to call
17 Apr, 10:01 AM
cold call
with
unknown customer
Held:
16 Apr, 4:35 PM
Duration:
1m
Value:
$0
Petko Kashinski
listened to call
17 Apr, 9:43 AM
Refresher Session
with
Melanie Yu Yu
Held:
9 Apr, 5:58 PM
Duration:
30m
Value:
$0
Zornitsa Dzhongova
listened to call
16 Apr, 4:16 PM
Discovery Call (upsell)
with
Oscar Linares
Held:
15 Apr, 3:30 PM
Duration:
32m
Value:
$11,875
Mario Georgiev
listened to call
16 Apr, 2:59 PM
Support / Troubleshooting
with
Adriana Voyce
Held:
15 Apr, 7:28 PM...
|
NULL
|