|
57915
|
2037
|
37
|
2026-05-19T11:15:27.795172+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189327795_m2.jpg...
|
PhpStorm
|
faVsco.js – AskAnythingPrompt.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu...
|
[{"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},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.098071806,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1961873295031593158
|
-1483003541378331465
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
PhostormVIewINavicarecodeKeractorWindowFV faVsco.js?9 JY-20676-delete-report-related-objectsProiectC ActivityController.ong© AskAnythingController.php© AskAnythingPromptService.php© AutomatedReportsServiceTest.php• @ AskAnything© AskAnythingPrompt.php© AskAnythingPromptDto.phpe AsKAnytningPromptlarget.onp© AskJiminnyReportsController.php© Automa©) AskAnythingPromptServiceTest.php© Search.phpUseraskanythingPrompt.onpclass AskAnythingPrompt extendsu calendaD Connectionoublic tunction cetownero: zuser...?w contracts0 Crmno usadesc) BusinessProcess.ohppublic function userPrompts(): Relations\HasManyt...$c) contiquration.phpc) ContactRole.ohp4 usagesc) Fieldonopublic function automatedReports: Relations \HasManyt...}© FieldData.phpC) FieldValue.ohoC) Lavout ohopublic function getUuid: stringf...}C) LavoutEntitv.ohopublic function getIdO: inti...}© Log.phpc) Profile nhn© RecordType.php© SyncBatch.php1M GlasticSearchpublic function get0wnerId: ?inti...hpublic function getTarget: AskAnythingPromptTargetf...}D Feature_ UpporunityD ParticipantD PlaybackThemeD Playlist* Prompt 1s considered derault when 1t has no owner* @return bool0 Webhookc) Account.pho© Activity.php© Address.phpnuouic tunction 1steraultPromoto: 000L...}public function cetiitleo: strino.....(c) AlPrompt.php(c) AutomatedReportResult.onopublic function getContent: stringt...,Susadesnublic function aetHasRenortso: hooll© CoachingFeedback.php(C) CoachinaFeedbackVisiollitv.oho(C) CoachinaSection.oho104if (array_key_exists( key: 'automated_reports_count', $this->getAttributes())) Accept Rejectneturn(Gint) Sthis->aetAttrihuted kev.lautomated_renonts count!) >0.(C) CoachingSectioncriterion.ohv@ CoachinaSectionGriterionFeedback.ohn(C) CoachinaSectionFeedback nhn© CommentAbstract.php1Commentinterface.nhn@ Contact nhn.return $this->automatedReports()->exists();109110© Device.php© EmailMessage.php© GenericAiPrompt.php@ Group.php© Inbox.phpAccept File &X Reject File 4%€+ 3 of 6 files →=custom.log= laravel.log4 SF jiminny@localhost] x4 HS_local [jiminny@localhost]A console [STAGING]C) CoachinaFeedhackCoachl.Icerin.nhn188 0192196200-202203205294207299.209213215219223Tx: AutovPlavaroundselect * fron activities where id = 422003• # 00U04000000B6foMAClSELECT ar.id, ar.uuid, ar.media type, ar.status, a.typeSp0M automated nenont neculte anJOIN automated_reports a ON a.id = ar.report idWHERE a.type = 'ask jiminny'LIMIT 10:SELECT * FROM automated_reports where id = 71:SELECT * FROM automated report results where report id = 71:UPDATE automated reports set playbook categories = NULL where id = 68:SELECT * FROM automated report_ results where id = 275SELECT * FROM automated reports order by id desc›SELECT * FROMautomated_reportresults order by 1d desc:select * from activity searches where user id = 143:SELECTautomated renort results' * FROM 'automated renort resultsiINNER JOIN 'automated renortsiautomated renort results' "renort id' = 'automated renorts' 'idiautomated renort results' 'aenerated at' IS NOT NuLIautomated renort results' sent at' IS NOT NULIAND ISON CONTATNS('automated nenonte' "neciniente'. 147 Id lucengll)SELECT * EPOM automated nenonte whene id = 47-SELECT * FROM automated_reports where id = 42;SELECT * FROM users WHERE id = 143; # group 28select * from crm_confiqurations where id = 500:select * from users where name = 'Integration Account': # 1695SELECT * FROMsocial accounts WHERE sociable_ id = 1695:select * from activities where crm_ configuration_ id = 39and recording state = 'recorded' and duration > 60and status = 'completed' and actual start time >= 12025-12-01'•SELECT * FROM activities WHERE uuid to bin(•458cf915-6914-4000-b083-568763262956') = uuidiselect * from leads:SELECT * FROM activities WHERE uuid to bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid: # 422003SFLECT + EPOM activitiec WHEPE id TN (16. 422003).Socket fail to connect to host:address=(host=localhost) (port=3306)(tvpe=primarv). Connection refusedhell"suppont Dally • In 40m100% 5• Tue 19 May 14:15:27AskAnythingPromptServiceTest v& console [PROD]# console [euyCascadeAsk Jiminny Report M+0 ..So jiminny vThouaht for 1sm 021 A1 A18 V2 Y6 ^• AutomatedReportsServiceTest.php+13 -17Review Items Addrassedcnucal - Nti cuerles (Tixea)Saved searches - ActivityController.ohp: 1100 now eager-loads via ->withcount('automatedReports'), and Searchtnanstormer.php: 48 reads trom aucomated_reports_count.Promots — moved loadCount('autonatedReports') into AskAnvthinaRepositorv.oho:94-100 (sinale batched countquery for the whole list). The AskAnythingPrompt::getHasReports() accessor now prefers automated reports countwhen oresent and talls back to exists() otherwise (oreserves correctness in other calli sites and tests).Moderate - Business logic moved to serviceAutomatedReportsService.php:1240-1252 now contains the quard and throws InvalidArgumentException . The controller(AskJiminnyReportsController.php:126-160) is back to a thin try/catch with an added InvalidArgumentException → 422nandler (matches the pattern already used in createAsk) iminnvReport and updateAski iminnvReport).Moderate — Tests addediAutomatedReportsservicelest.php:•testUpdateAskJiminnyReportStatusThrowsWhenEnablingWithMissingReferences - verifies the new validationthrows and uodated is never called.•testUpdateAskJiminnyReportStatusDoesNotValidateWhenDisabling - verifies disabling bypasses the validationentire v and oroceeds to undate.(I did not add controller tests per your "no unit tests for controllers" rule; the service-level coverage exercises the sameoaic.Minor - create() returns has_reports: falseAskAnythingPromptService.php:106 now passes false explicitly. Updated testCreateAskAnythingPromptWithTwoUsers to matchMinor - onBeforeDelete only on on demandNot changed in this round — tlagaed for contirmation. currentlv onlv on demand promots can be wired to Ask Jiminnyreports (tne getaskJiminnykeportritters service explicity Tetches ASKAnythingPromptlarget::on demand), so theView allltests/Unit/Component/AskAnvthing/B AskAnythingPromptServiceTest.php +25-2app/Component/AskAnything/@ AskAnythingPromptService.php +7 -2app/Repositories/ D AskAnythingRepository.php +7 -1ann/Httn/Trancformore/M SoarchTrancformor.nhnt1lers/API/ ActivityController.php +1/m AskAnvthinaPromot.oho +4Accent allExaplin<> Code Claude Qnus 4.7 MediumW Windsurf Toamo100•6/274 charc 7 line hreake)io 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57914
|
2036
|
29
|
2026-05-19T11:15:26.997233+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189326997_m1.jpg...
|
PhpStorm
|
faVsco.js – AskAnythingPrompt.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 45 m100% C7Tue 19 May 14:15:26ED→Describe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
1053847076388316236
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 45 m100% C7Tue 19 May 14:15:26ED→Describe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57913
|
2037
|
36
|
2026-05-19T11:15:22.856600+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189322856_m2.jpg...
|
PhpStorm
|
faVsco.js – AskAnythingPrompt.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormViewINavicarecodeKeractorWindowFV faVsco.j PhostormViewINavicarecodeKeractorWindowFV faVsco.js?9 JY-20676-delete-report-related-objectsroledeyC ActivityController.ong© AskAnythingController.php© UserAskAnythingPrompt.php© AskAnythingPromptService.php© AutomatedReportsServiceTest.php_ Calendar© AskAnythingPromptDto.phpa ConnectionContracts© AskJiminnyReportsController.php© Automat©) AskAnythingPromptServiceTest.php© Search.phpv hermclass AskAnythingPrompt extends© BusinessProcess.php© Configuration.php© ContactRole.phpo rielo.onp© FieldData.phpOrielavalue.onp© Layout.php© LayoutEntity.php© Log.php© Profile.phpc) кecoralype.phpc) syncbatch.phpu clasticsearchu reatureOpponunitvM ParticipantPlavbackthemeD PlavlistD ScorecardWebhook(C) Account oho@ Activitv.oho.© Address.php(C) A Promot.oho© AutomatedReport.php(C) AutomatedRenortResult.oho© Calendar.php(c) Callimnort nhn© CoachingFeedback.php© CoachingFeedbackVisibility.php© CoachingSection.php© CoachingSectionCriterion.php© CoachingSectionCriterionFeedback.php© CoachingSectionFeedback.php© CommentAbstract.php• Commentinterface.php(c) Contact.php© Device.php© EmailMessage.php102(c) GenericAiPromot.pho© Group.php(c) nbox.oho© InboxEmail.phpC)[EMAIL]) oblo.ooublic tunction cetownero: zuser...?no usadespublic function userPrompts(): Relations\HasManyt...$4 usagespublic function automatedReports: Relations \HasManyt...}public function getUuid: stringf...}public function getIdO: inti...}public function get0wnerId: ?inti...hpublic function getTarget: AskAnythingPromptTargetf...}* Prompt 1s considered derault when 1t has no owner* @return boolnuouic tunction 1steraultPromoto: 000L...}public function cetiitleo: strino.....public function getContent(): stringf...}Susadespublic function getHasReports(): boolif (array_key_exists( key: 'automated_reports_count', $this->getAttributes())) AcceptReriectneturn (aint) Sthis->aetAttrihuted kev: "automated nenonts count!)) > 0.return $this->automatedReports()->exists();Accept File &+X Reject File 4%€+ 3 of 6 files →(C),lobTitle ohoPuched 1 commit to.oriain/IV.20676-delete-renort-rolated-ohiectc // View null reauect (57 minutes aao)=custom.log= laravel.log4 SF jiminny@localhost] x4 HS_local [jiminny@localhost]A console [STAGING]C) CoachinaFeedhackCoachl.Icerin.nhn188 0192196200201205294207299.209213215223Plavaroundselect * fron activities where id = 422003• # 00U04000000B6foMAClSELECT ar.id, ar.uuid, ar.media type, ar.status, a.typeSp0M automated nenont neculte anJOIN automated_reports a ON a.id = ar.report idWHERE a.type = 'ask jiminny'LIMIT 10:SELECT * FROM automated_reports where id = 71:SELECT * FROM automated report results where report id = 71:UPDATE automated_reports set playbook categories = NULL where id = 68:SELECT * FROM automated report_ results where id = 275SELECT * FROM automated reports order by id desc›SELECT * FROMautomated_reportresults order by 1d desc:select * from activity_searches where user_id = 143;SELECTautomated renort results' * FROM 'automated renort resultsiINNER JOIN 'automated renortsiautomated renort results' "renort id' = 'automated renorts' 'idiautomated renort results' 'aenerated at' IS NOT NuLIautomated renort results' sent at' IS NOT NULIAND ISON CONTATNS('automated nenonte' "neciniente'. 147 Id lucengll)SELECT * EPOM automated nenonte whene id = 47-SELECT * FROM automated_reports where id = 42;SELECT * FROM users WHERE id = 143; # group 28select * from crm_confiqurations where id = 500:select * from users where name = 'Integration Account': # 1695SELECT * FROMsocial accounts WHERE sociable_ id = 1695:select * from activities where crm_ configuration_ id = 39and recording state = 'recorded' and duration > 60and status = 'completed' and actual start time >= 12025-12-01'•SELECT * FROM activities WHERE uuid to bin('458cf915-6914-4000-b083-568763262956') = uuid:select * from leads:SELECT * FROM activities WHERE uuid to bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid: # 422003SFLECT + EPOM activitiec WHEPE id TN (16. 422003).Socket fail to connect to host:address=(host=localhost) (port=3306)(tvpe=primarv). Connection refusedhell"suppont Dally • In 40m100% 5• Tue 19 May 14:15:22AskAnythingPromptServiceTest v& console [PROD]# console [euyCascadeAsk Jiminny Report M+0 ..So jiminny vThouaht for 1sm 021 A1 A18 V2 Y6 ^• AutomatedReportsServiceTest.php+13 -17Review Items Addrassedcnucal - Nti cuerles (Tixea)Saved searches - ActivityController.ohp: 1100 now eager-loads via ->withcount('automatedReports'), and Searchtnanstormer.php: 48 reads trom aucomated_reports_count.Promots — moved loadCount('autonatedReports') into AskAnvthinaRepositorv.oho:94-100 (sinale batched countquery for the whole list). The AskAnythingPrompt::getHasReports() accessor now prefers automated reports countwhen oresent and talls back to exists() otherwise (oreserves correctness in other calli sites and tests).Moderate - Business logic moved to serviceAutomatedReportsService.php:1240-1252 now contains the quard and throws InvalidArgumentException . The controller(AskJiminnyReportsController.php:126-160) is back to a thin try/catch with an added InvalidArgumentException → 422nandler (matches the pattern already used in createAsk) iminnvReport and updateAski iminnvReport).Moderate — Tests addediAutomatedReportsservicelest.php:•testUpdateAskJiminnyReportStatusThrowsWhenEnablingWithMissingReferences - verifies the new validationthrows and uodated is never called.•testUpdateAskJiminnyReportStatusDoesNotValidateWhenDisabling- verifies disabling bypasses the validationentire v and oroceeds to undate.(I did not add controller tests per your "no unit tests for controllers" rule; the service-level coverage exercises the sameoaic.Minor - create() returns has_reports: falseAskAnythingPromptService.php:106 now passes false explicitly. Updated testCreateAskAnythingPromptWithTwoUsers to matchMinor - onBeforeDelete only on on demandNot changed in this round — tlagaed for contirmation. currentlv onlv on demand promots can be wired to Ask Jiminnyreports (tne getaskJiminnykeportritters service explicity Tetches ASKAnythingPromptlarget::on demand), so theView allltests/Unit/Component/AskAnvthing/B AskAnythingPromptServiceTest.php +25-2app/Component/AskAnything/@ AskAnythingPromptService.php +7 -2app/Repositories/ @ ASKAnythingRepository.php +7 -1ann/Httn/Trancformore/M SoarchTrancformor.nhnt1lers/API/ ActivityController.php +1a/MAskAnvthinaPromot.ohn +4Accent alliExaplin<> Code Claude Qnus 1.7 MediumW Windsurf Teamcio 4 spaces...
|
NULL
|
-6629622998043316361
|
NULL
|
click
|
ocr
|
NULL
|
PhostormViewINavicarecodeKeractorWindowFV faVsco.j PhostormViewINavicarecodeKeractorWindowFV faVsco.js?9 JY-20676-delete-report-related-objectsroledeyC ActivityController.ong© AskAnythingController.php© UserAskAnythingPrompt.php© AskAnythingPromptService.php© AutomatedReportsServiceTest.php_ Calendar© AskAnythingPromptDto.phpa ConnectionContracts© AskJiminnyReportsController.php© Automat©) AskAnythingPromptServiceTest.php© Search.phpv hermclass AskAnythingPrompt extends© BusinessProcess.php© Configuration.php© ContactRole.phpo rielo.onp© FieldData.phpOrielavalue.onp© Layout.php© LayoutEntity.php© Log.php© Profile.phpc) кecoralype.phpc) syncbatch.phpu clasticsearchu reatureOpponunitvM ParticipantPlavbackthemeD PlavlistD ScorecardWebhook(C) Account oho@ Activitv.oho.© Address.php(C) A Promot.oho© AutomatedReport.php(C) AutomatedRenortResult.oho© Calendar.php(c) Callimnort nhn© CoachingFeedback.php© CoachingFeedbackVisibility.php© CoachingSection.php© CoachingSectionCriterion.php© CoachingSectionCriterionFeedback.php© CoachingSectionFeedback.php© CommentAbstract.php• Commentinterface.php(c) Contact.php© Device.php© EmailMessage.php102(c) GenericAiPromot.pho© Group.php(c) nbox.oho© InboxEmail.phpC)[EMAIL]) oblo.ooublic tunction cetownero: zuser...?no usadespublic function userPrompts(): Relations\HasManyt...$4 usagespublic function automatedReports: Relations \HasManyt...}public function getUuid: stringf...}public function getIdO: inti...}public function get0wnerId: ?inti...hpublic function getTarget: AskAnythingPromptTargetf...}* Prompt 1s considered derault when 1t has no owner* @return boolnuouic tunction 1steraultPromoto: 000L...}public function cetiitleo: strino.....public function getContent(): stringf...}Susadespublic function getHasReports(): boolif (array_key_exists( key: 'automated_reports_count', $this->getAttributes())) AcceptReriectneturn (aint) Sthis->aetAttrihuted kev: "automated nenonts count!)) > 0.return $this->automatedReports()->exists();Accept File &+X Reject File 4%€+ 3 of 6 files →(C),lobTitle ohoPuched 1 commit to.oriain/IV.20676-delete-renort-rolated-ohiectc // View null reauect (57 minutes aao)=custom.log= laravel.log4 SF jiminny@localhost] x4 HS_local [jiminny@localhost]A console [STAGING]C) CoachinaFeedhackCoachl.Icerin.nhn188 0192196200201205294207299.209213215223Plavaroundselect * fron activities where id = 422003• # 00U04000000B6foMAClSELECT ar.id, ar.uuid, ar.media type, ar.status, a.typeSp0M automated nenont neculte anJOIN automated_reports a ON a.id = ar.report idWHERE a.type = 'ask jiminny'LIMIT 10:SELECT * FROM automated_reports where id = 71:SELECT * FROM automated report results where report id = 71:UPDATE automated_reports set playbook categories = NULL where id = 68:SELECT * FROM automated report_ results where id = 275SELECT * FROM automated reports order by id desc›SELECT * FROMautomated_reportresults order by 1d desc:select * from activity_searches where user_id = 143;SELECTautomated renort results' * FROM 'automated renort resultsiINNER JOIN 'automated renortsiautomated renort results' "renort id' = 'automated renorts' 'idiautomated renort results' 'aenerated at' IS NOT NuLIautomated renort results' sent at' IS NOT NULIAND ISON CONTATNS('automated nenonte' "neciniente'. 147 Id lucengll)SELECT * EPOM automated nenonte whene id = 47-SELECT * FROM automated_reports where id = 42;SELECT * FROM users WHERE id = 143; # group 28select * from crm_confiqurations where id = 500:select * from users where name = 'Integration Account': # 1695SELECT * FROMsocial accounts WHERE sociable_ id = 1695:select * from activities where crm_ configuration_ id = 39and recording state = 'recorded' and duration > 60and status = 'completed' and actual start time >= 12025-12-01'•SELECT * FROM activities WHERE uuid to bin('458cf915-6914-4000-b083-568763262956') = uuid:select * from leads:SELECT * FROM activities WHERE uuid to bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid: # 422003SFLECT + EPOM activitiec WHEPE id TN (16. 422003).Socket fail to connect to host:address=(host=localhost) (port=3306)(tvpe=primarv). Connection refusedhell"suppont Dally • In 40m100% 5• Tue 19 May 14:15:22AskAnythingPromptServiceTest v& console [PROD]# console [euyCascadeAsk Jiminny Report M+0 ..So jiminny vThouaht for 1sm 021 A1 A18 V2 Y6 ^• AutomatedReportsServiceTest.php+13 -17Review Items Addrassedcnucal - Nti cuerles (Tixea)Saved searches - ActivityController.ohp: 1100 now eager-loads via ->withcount('automatedReports'), and Searchtnanstormer.php: 48 reads trom aucomated_reports_count.Promots — moved loadCount('autonatedReports') into AskAnvthinaRepositorv.oho:94-100 (sinale batched countquery for the whole list). The AskAnythingPrompt::getHasReports() accessor now prefers automated reports countwhen oresent and talls back to exists() otherwise (oreserves correctness in other calli sites and tests).Moderate - Business logic moved to serviceAutomatedReportsService.php:1240-1252 now contains the quard and throws InvalidArgumentException . The controller(AskJiminnyReportsController.php:126-160) is back to a thin try/catch with an added InvalidArgumentException → 422nandler (matches the pattern already used in createAsk) iminnvReport and updateAski iminnvReport).Moderate — Tests addediAutomatedReportsservicelest.php:•testUpdateAskJiminnyReportStatusThrowsWhenEnablingWithMissingReferences - verifies the new validationthrows and uodated is never called.•testUpdateAskJiminnyReportStatusDoesNotValidateWhenDisabling- verifies disabling bypasses the validationentire v and oroceeds to undate.(I did not add controller tests per your "no unit tests for controllers" rule; the service-level coverage exercises the sameoaic.Minor - create() returns has_reports: falseAskAnythingPromptService.php:106 now passes false explicitly. Updated testCreateAskAnythingPromptWithTwoUsers to matchMinor - onBeforeDelete only on on demandNot changed in this round — tlagaed for contirmation. currentlv onlv on demand promots can be wired to Ask Jiminnyreports (tne getaskJiminnykeportritters service explicity Tetches ASKAnythingPromptlarget::on demand), so theView allltests/Unit/Component/AskAnvthing/B AskAnythingPromptServiceTest.php +25-2app/Component/AskAnything/@ AskAnythingPromptService.php +7 -2app/Repositories/ @ ASKAnythingRepository.php +7 -1ann/Httn/Trancformore/M SoarchTrancformor.nhnt1lers/API/ ActivityController.php +1a/MAskAnvthinaPromot.ohn +4Accent alliExaplin<> Code Claude Qnus 1.7 MediumW Windsurf Teamcio 4 spaces...
|
57910
|
NULL
|
NULL
|
NULL
|
|
57912
|
2036
|
28
|
2026-05-19T11:15:22.901661+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189322901_m1.jpg...
|
PhpStorm
|
faVsco.js – AskAnythingPrompt.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 45 m100% C7Tue 19 May 14:15:22ED→Describe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
-524321385975321627
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 45 m100% C7Tue 19 May 14:15:22ED→Describe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
57911
|
NULL
|
NULL
|
NULL
|
|
57911
|
2036
|
27
|
2026-05-19T11:15:17.839474+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189317839_m1.jpg...
|
PhpStorm
|
faVsco.js – AskAnythingPrompt.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 45 m100% C7Tue 19 May 14:15:17ED→Describe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
-6812012816791641999
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 45 m100% C7Tue 19 May 14:15:17ED→Describe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57910
|
2037
|
35
|
2026-05-19T11:15:17.476612+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189317476_m2.jpg...
|
PhpStorm
|
faVsco.js – AskAnythingPrompt.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Models\AskAnything;
use Illuminate\Database\Eloquent\Relations;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Model;
use Jiminny\Models\User;
use Jiminny\Traits\RequiresUUID;
class AskAnythingPrompt extends Model
{
use RequiresUUID;
protected $table = 'ask_anything_prompts';
protected $fillable = [
'title',
'content',
'target',
'owner_id',
];
protected $visible = [
'title',
'content',
'owner_id',
];
protected function casts(): array
{
return [
'title' => 'string',
'content' => 'string',
'target' => AskAnythingPromptTarget::class,
'owner_id' => 'integer',
];
}
public function owner(): Relations\BelongsTo
{
return $this->belongsTo(User::class);
}
public function getOwner(): ?User
{
return $this->getAttribute('owner');
}
public function userPrompts(): Relations\HasMany
{
return $this->hasMany(UserAskAnythingPrompt::class, 'prompt_id');
}
public function automatedReports(): Relations\HasMany
{
return $this->hasMany(AutomatedReport::class, 'ask_anything_prompt_id');
}
public function getUuid(): string
{
return $this->getAttribute('id_string');
}
public function getId(): int
{
return $this->getAttribute('id');
}
public function getOwnerId(): ?int
{
return $this->getAttribute('owner_id');
}
public function getTarget(): AskAnythingPromptTarget
{
return $this->getAttribute('target');
}
/**
* Prompt is considered default when it has no owner
*
* @return bool
*/
public function isDefaultPrompt(): bool
{
return $this->getOwnerId() === null;
}
public function getTitle(): string
{
return $this->getAttribute('title');
}
public function getContent(): string
{
return $this->getAttribute('content');
}
public function getHasReports(): bool
{
if (array_key_exists('automated_reports_count', $this->getAttributes())) {
return ((int) $this->getAttribute('automated_reports_count')) > 0;
}
return $this->automatedReports()->exists();
}
}
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
21
1
18
2
6
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 sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id
where u.team_id = 1;
SELECT * FROM social_accounts WHERE sociable_id = 1635;
SELECT * FROM users WHERE id = 1635;
select * from teams where id = 1;
select * from users where team_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 activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;
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 automated_reports where id = 71;
SELECT * FROM automated_report_results where report_id = 71;
UPDATE automated_reports set playbook_categories = NULL 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 `automated_report_results`.* FROM `automated_report_results`
INNER JOIN `automated_reports`
ON `automated_report_results`.`report_id` = `automated_reports`.`id`
WHERE 1=1
AND `automated_report_results`.`generated_at` IS NOT NULL
# AND `automated_report_results`.`sent_at` IS NOT NULL
AND `automated_reports`.`team_id` = 1
AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$."users"')
;
SELECT * FROM automated_reports where id = 67;
SELECT * FROM automated_reports where id = 42;
SELECT * FROM users WHERE id = 143; # group 28
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;
select * from leads;
SELECT * FROM activities WHERE uuid_to_bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid; # 422003
SELECT * FROM activities WHERE id IN (16,422003);
SELECT * FROM activities where status = 'failed';
SELECT * FROM tracks WHERE activity_id = 422003;
SELECT
a.*
FROM activities a
JOIN users u ON a.user_id = u.id
WHERE
a.status = 'completed'
AND uuid_to_bin('641f1acb-16b8-42d1-8726-df52979dad0e') = u.uuid
AND a.deleted_at IS NULL
AND EXISTS (
SELECT 1 FROM tracks t
WHERE t.activity_id = a.id
AND t.type IN ('audio', 'video')
)
ORDER BY a.actual_start_time DESC
LIMIT 25;
select * from teams where id = 19;
select * from crm_configurations where provider = 'pipedrive';
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 = 19 and sa.provider = 'pipedrive';
SELECT * FROM social_accounts WHERE id = 1116;
UPDATE social_accounts SET provider_user_token = 'v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA',
provider_refresh_token = '5034113:[TELEGRAM_TOKEN]b2bfc',
expires = 1779091997,
state = 'connected'
WHERE id = 1116;
"provider_user_token": "v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA",
"provider_refresh_token": "5034113:[TELEGRAM_TOKEN]b2bfc",
"expires": 1779091997,
Socket fail to connect to host:address=(host=localhost)(port=3306)(type=primary). Connection refused
Project
Project
New File or Directory…
Expand Selected...
|
[{"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},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.098071806,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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.8194814,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskAnythingPromptServiceTest","depth":6,"bounds":{"left":0.83477396,"top":0.019952115,"width":0.080784574,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"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},"on_screen":false,"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\\Models\\AskAnything;\n\nuse Illuminate\\Database\\Eloquent\\Relations;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Model;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Traits\\RequiresUUID;\n\nclass AskAnythingPrompt extends Model\n{\n use RequiresUUID;\n\n protected $table = 'ask_anything_prompts';\n\n protected $fillable = [\n 'title',\n 'content',\n 'target',\n 'owner_id',\n ];\n\n protected $visible = [\n 'title',\n 'content',\n 'owner_id',\n ];\n\n protected function casts(): array\n {\n return [\n 'title' => 'string',\n 'content' => 'string',\n 'target' => AskAnythingPromptTarget::class,\n 'owner_id' => 'integer',\n ];\n }\n\n public function owner(): Relations\\BelongsTo\n {\n return $this->belongsTo(User::class);\n }\n\n public function getOwner(): ?User\n {\n return $this->getAttribute('owner');\n }\n\n public function userPrompts(): Relations\\HasMany\n {\n return $this->hasMany(UserAskAnythingPrompt::class, 'prompt_id');\n }\n\n public function automatedReports(): Relations\\HasMany\n {\n return $this->hasMany(AutomatedReport::class, 'ask_anything_prompt_id');\n }\n\n public function getUuid(): string\n {\n return $this->getAttribute('id_string');\n }\n\n public function getId(): int\n {\n return $this->getAttribute('id');\n }\n\n public function getOwnerId(): ?int\n {\n return $this->getAttribute('owner_id');\n }\n\n public function getTarget(): AskAnythingPromptTarget\n {\n return $this->getAttribute('target');\n }\n\n /**\n * Prompt is considered default when it has no owner\n *\n * @return bool\n */\n public function isDefaultPrompt(): bool\n {\n return $this->getOwnerId() === null;\n }\n\n public function getTitle(): string\n {\n return $this->getAttribute('title');\n }\n\n public function getContent(): string\n {\n return $this->getAttribute('content');\n }\n\n public function getHasReports(): bool\n {\n if (array_key_exists('automated_reports_count', $this->getAttributes())) {\n return ((int) $this->getAttribute('automated_reports_count')) > 0;\n }\n\n return $this->automatedReports()->exists();\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Models\\AskAnything;\n\nuse Illuminate\\Database\\Eloquent\\Relations;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Model;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Traits\\RequiresUUID;\n\nclass AskAnythingPrompt extends Model\n{\n use RequiresUUID;\n\n protected $table = 'ask_anything_prompts';\n\n protected $fillable = [\n 'title',\n 'content',\n 'target',\n 'owner_id',\n ];\n\n protected $visible = [\n 'title',\n 'content',\n 'owner_id',\n ];\n\n protected function casts(): array\n {\n return [\n 'title' => 'string',\n 'content' => 'string',\n 'target' => AskAnythingPromptTarget::class,\n 'owner_id' => 'integer',\n ];\n }\n\n public function owner(): Relations\\BelongsTo\n {\n return $this->belongsTo(User::class);\n }\n\n public function getOwner(): ?User\n {\n return $this->getAttribute('owner');\n }\n\n public function userPrompts(): Relations\\HasMany\n {\n return $this->hasMany(UserAskAnythingPrompt::class, 'prompt_id');\n }\n\n public function automatedReports(): Relations\\HasMany\n {\n return $this->hasMany(AutomatedReport::class, 'ask_anything_prompt_id');\n }\n\n public function getUuid(): string\n {\n return $this->getAttribute('id_string');\n }\n\n public function getId(): int\n {\n return $this->getAttribute('id');\n }\n\n public function getOwnerId(): ?int\n {\n return $this->getAttribute('owner_id');\n }\n\n public function getTarget(): AskAnythingPromptTarget\n {\n return $this->getAttribute('target');\n }\n\n /**\n * Prompt is considered default when it has no owner\n *\n * @return bool\n */\n public function isDefaultPrompt(): bool\n {\n return $this->getOwnerId() === null;\n }\n\n public function getTitle(): string\n {\n return $this->getAttribute('title');\n }\n\n public function getContent(): string\n {\n return $this->getAttribute('content');\n }\n\n public function getHasReports(): bool\n {\n if (array_key_exists('automated_reports_count', $this->getAttributes())) {\n return ((int) $this->getAttribute('automated_reports_count')) > 0;\n }\n\n return $this->automatedReports()->exists();\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.42785904,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.43650267,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.4474734,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.45611703,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.46476063,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.47573137,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.4867021,"top":0.09896249,"width":0.024268618,"height":0.01915403},"on_screen":true,"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.51329786,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"bounds":{"left":0.5242686,"top":0.09896249,"width":0.029587766,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"bounds":{"left":0.70611703,"top":0.09896249,"width":0.02825798,"height":0.01915403},"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"21","depth":4,"bounds":{"left":0.66921544,"top":0.123703115,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.68085104,"top":0.123703115,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"18","depth":4,"bounds":{"left":0.69015956,"top":0.123703115,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.7017952,"top":0.123703115,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.7117686,"top":0.123703115,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.72140956,"top":0.12210695,"width":0.00731383,"height":0.018355945},"on_screen":true,"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.7287234,"top":0.12210695,"width":0.006981383,"height":0.018355945},"on_screen":true,"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\n\nselect sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id\nwhere u.team_id = 1;\nSELECT * FROM social_accounts WHERE sociable_id = 1635;\nSELECT * FROM users WHERE id = 1635;\n\nselect * from teams where id = 1;\nselect * from users where team_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 activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;\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\nSELECT * FROM automated_reports where id = 71;\nSELECT * FROM automated_report_results where report_id = 71;\nUPDATE automated_reports set playbook_categories = NULL 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 `automated_report_results`.* FROM `automated_report_results`\nINNER JOIN `automated_reports`\n ON `automated_report_results`.`report_id` = `automated_reports`.`id`\nWHERE 1=1\n AND `automated_report_results`.`generated_at` IS NOT NULL\n# AND `automated_report_results`.`sent_at` IS NOT NULL\n AND `automated_reports`.`team_id` = 1\n AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$.\"users\"')\n;\n\nSELECT * FROM automated_reports where id = 67;\nSELECT * FROM automated_reports where id = 42;\nSELECT * FROM users WHERE id = 143; # group 28\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;\n\nselect * from leads;\n\nSELECT * FROM activities WHERE uuid_to_bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid; # 422003\nSELECT * FROM activities WHERE id IN (16,422003);\nSELECT * FROM activities where status = 'failed';\n\nSELECT * FROM tracks WHERE activity_id = 422003;\n\nSELECT\n a.*\nFROM activities a\nJOIN users u ON a.user_id = u.id\nWHERE\n a.status = 'completed'\n AND uuid_to_bin('641f1acb-16b8-42d1-8726-df52979dad0e') = u.uuid\n AND a.deleted_at IS NULL\n AND EXISTS (\n SELECT 1 FROM tracks t\n WHERE t.activity_id = a.id\n AND t.type IN ('audio', 'video')\n )\nORDER BY a.actual_start_time DESC\nLIMIT 25;\n\nselect * from teams where id = 19;\nselect * from crm_configurations where provider = 'pipedrive';\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 = 19 and sa.provider = 'pipedrive';\n\nSELECT * FROM social_accounts WHERE id = 1116;\n\nUPDATE social_accounts SET provider_user_token = 'v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA',\nprovider_refresh_token = '5034113:19555731:87c14258f0c813d02767ee975f6044d46b6b2bfc',\nexpires = 1779091997,\nstate = 'connected'\nWHERE id = 1116;\n\n \"provider_user_token\": \"v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA\",\n \"provider_refresh_token\": \"5034113:19555731:87c14258f0c813d02767ee975f6044d46b6b2bfc\",\n \"expires\": 1779091997,","depth":4,"on_screen":true,"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\n\nselect sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id\nwhere u.team_id = 1;\nSELECT * FROM social_accounts WHERE sociable_id = 1635;\nSELECT * FROM users WHERE id = 1635;\n\nselect * from teams where id = 1;\nselect * from users where team_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 activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;\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\nSELECT * FROM automated_reports where id = 71;\nSELECT * FROM automated_report_results where report_id = 71;\nUPDATE automated_reports set playbook_categories = NULL 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 `automated_report_results`.* FROM `automated_report_results`\nINNER JOIN `automated_reports`\n ON `automated_report_results`.`report_id` = `automated_reports`.`id`\nWHERE 1=1\n AND `automated_report_results`.`generated_at` IS NOT NULL\n# AND `automated_report_results`.`sent_at` IS NOT NULL\n AND `automated_reports`.`team_id` = 1\n AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$.\"users\"')\n;\n\nSELECT * FROM automated_reports where id = 67;\nSELECT * FROM automated_reports where id = 42;\nSELECT * FROM users WHERE id = 143; # group 28\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;\n\nselect * from leads;\n\nSELECT * FROM activities WHERE uuid_to_bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid; # 422003\nSELECT * FROM activities WHERE id IN (16,422003);\nSELECT * FROM activities where status = 'failed';\n\nSELECT * FROM tracks WHERE activity_id = 422003;\n\nSELECT\n a.*\nFROM activities a\nJOIN users u ON a.user_id = u.id\nWHERE\n a.status = 'completed'\n AND uuid_to_bin('641f1acb-16b8-42d1-8726-df52979dad0e') = u.uuid\n AND a.deleted_at IS NULL\n AND EXISTS (\n SELECT 1 FROM tracks t\n WHERE t.activity_id = a.id\n AND t.type IN ('audio', 'video')\n )\nORDER BY a.actual_start_time DESC\nLIMIT 25;\n\nselect * from teams where id = 19;\nselect * from crm_configurations where provider = 'pipedrive';\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 = 19 and sa.provider = 'pipedrive';\n\nSELECT * FROM social_accounts WHERE id = 1116;\n\nUPDATE social_accounts SET provider_user_token = 'v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA',\nprovider_refresh_token = '5034113:19555731:87c14258f0c813d02767ee975f6044d46b6b2bfc',\nexpires = 1779091997,\nstate = 'connected'\nWHERE id = 1116;\n\n \"provider_user_token\": \"v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA\",\n \"provider_refresh_token\": \"5034113:19555731:87c14258f0c813d02767ee975f6044d46b6b2bfc\",\n \"expires\": 1779091997,","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"Socket fail to connect to host:address=(host=localhost)(port=3306)(type=primary). Connection refused","depth":3,"bounds":{"left":0.42652926,"top":0.9577015,"width":0.29321808,"height":0.013567438},"on_screen":true,"value":"Socket fail to connect to host:address=(host=localhost)(port=3306)(type=primary). Connection refused","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
8713043229250015872
|
6830303734474610253
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Models\AskAnything;
use Illuminate\Database\Eloquent\Relations;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Model;
use Jiminny\Models\User;
use Jiminny\Traits\RequiresUUID;
class AskAnythingPrompt extends Model
{
use RequiresUUID;
protected $table = 'ask_anything_prompts';
protected $fillable = [
'title',
'content',
'target',
'owner_id',
];
protected $visible = [
'title',
'content',
'owner_id',
];
protected function casts(): array
{
return [
'title' => 'string',
'content' => 'string',
'target' => AskAnythingPromptTarget::class,
'owner_id' => 'integer',
];
}
public function owner(): Relations\BelongsTo
{
return $this->belongsTo(User::class);
}
public function getOwner(): ?User
{
return $this->getAttribute('owner');
}
public function userPrompts(): Relations\HasMany
{
return $this->hasMany(UserAskAnythingPrompt::class, 'prompt_id');
}
public function automatedReports(): Relations\HasMany
{
return $this->hasMany(AutomatedReport::class, 'ask_anything_prompt_id');
}
public function getUuid(): string
{
return $this->getAttribute('id_string');
}
public function getId(): int
{
return $this->getAttribute('id');
}
public function getOwnerId(): ?int
{
return $this->getAttribute('owner_id');
}
public function getTarget(): AskAnythingPromptTarget
{
return $this->getAttribute('target');
}
/**
* Prompt is considered default when it has no owner
*
* @return bool
*/
public function isDefaultPrompt(): bool
{
return $this->getOwnerId() === null;
}
public function getTitle(): string
{
return $this->getAttribute('title');
}
public function getContent(): string
{
return $this->getAttribute('content');
}
public function getHasReports(): bool
{
if (array_key_exists('automated_reports_count', $this->getAttributes())) {
return ((int) $this->getAttribute('automated_reports_count')) > 0;
}
return $this->automatedReports()->exists();
}
}
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
21
1
18
2
6
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 sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id
where u.team_id = 1;
SELECT * FROM social_accounts WHERE sociable_id = 1635;
SELECT * FROM users WHERE id = 1635;
select * from teams where id = 1;
select * from users where team_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 activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;
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 automated_reports where id = 71;
SELECT * FROM automated_report_results where report_id = 71;
UPDATE automated_reports set playbook_categories = NULL 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 `automated_report_results`.* FROM `automated_report_results`
INNER JOIN `automated_reports`
ON `automated_report_results`.`report_id` = `automated_reports`.`id`
WHERE 1=1
AND `automated_report_results`.`generated_at` IS NOT NULL
# AND `automated_report_results`.`sent_at` IS NOT NULL
AND `automated_reports`.`team_id` = 1
AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$."users"')
;
SELECT * FROM automated_reports where id = 67;
SELECT * FROM automated_reports where id = 42;
SELECT * FROM users WHERE id = 143; # group 28
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;
select * from leads;
SELECT * FROM activities WHERE uuid_to_bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid; # 422003
SELECT * FROM activities WHERE id IN (16,422003);
SELECT * FROM activities where status = 'failed';
SELECT * FROM tracks WHERE activity_id = 422003;
SELECT
a.*
FROM activities a
JOIN users u ON a.user_id = u.id
WHERE
a.status = 'completed'
AND uuid_to_bin('641f1acb-16b8-42d1-8726-df52979dad0e') = u.uuid
AND a.deleted_at IS NULL
AND EXISTS (
SELECT 1 FROM tracks t
WHERE t.activity_id = a.id
AND t.type IN ('audio', 'video')
)
ORDER BY a.actual_start_time DESC
LIMIT 25;
select * from teams where id = 19;
select * from crm_configurations where provider = 'pipedrive';
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 = 19 and sa.provider = 'pipedrive';
SELECT * FROM social_accounts WHERE id = 1116;
UPDATE social_accounts SET provider_user_token = 'v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA',
provider_refresh_token = '5034113:[TELEGRAM_TOKEN]b2bfc',
expires = 1779091997,
state = 'connected'
WHERE id = 1116;
"provider_user_token": "v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA",
"provider_refresh_token": "5034113:[TELEGRAM_TOKEN]b2bfc",
"expires": 1779091997,
Socket fail to connect to host:address=(host=localhost)(port=3306)(type=primary). Connection refused
Project
Project
New File or Directory…
Expand Selected...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57909
|
2037
|
34
|
2026-05-19T11:15:13.224828+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189313224_m2.jpg...
|
PhpStorm
|
faVsco.js – AutomatedReportsServiceTest.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormVIewINavicarecodeFV faVsco.js?9 JY-20676-d PhostormVIewINavicarecodeFV faVsco.js?9 JY-20676-delete-report-related-objectsProiect v© AskAnythingController.php> • OpportunitySyncStrategy• • ProspectSearchStrategy• M ServiceTraits© AskAnythingPromptService.php© AutomatedReportsServiceTest.php X© AskAnythingPromptDto.php© Automateakeport.php© ClientTest.phpC) DecorateActivitylest.pnpC DeleteObjectsTraitTest.php© FieldDefinitionsTest.phpC GetActivityFieldNameTest.phpPayloadBuilderTest.php@ QueryBuilderTest.phpC) QueryHandlerTest.php© QuerylteratorTest.php© QuervResultsTests.php© AskJiminnyReportsController.phg© Autonclass AutomatedReportsservicelest extends Testcase240 0 )(c) service lest.onoC SvncBatchRedisServiceTest.php©) BaseServiceTest.oho341 %©) CachedcrmServiceDecoratorTest.ohg©) CrmActivitvServicelest.onoc) crmobiectsResolveriiest.onoc DefaultProsnectSearchStrateavTest.cc EmailHelperTest.oho© FieldValueConverterTest.phpc LavoutManaderTest.oho© MigrateProviderServiceTest.php© OpportunityActivityMatcherTest.php© OpportunitySyncStrategyResolverTes© ProspectCacheTest.php© ProspectSearchStrategyFactoryTest.r© ProviderRegistryTest.php© RecordSelectorTest.phpaDocolwoCamnanyNamoRySmailTroitt423 ₽©) TimePeriodlteratorTest.php© UpdateCrmDataResolverTest.php> C Internalv @ Kioskv @ AutomatedReports© ActivitvTvpeServiceTest.php© AskJiminnyReportActivitvServiceT© AskJiminnyReportServiceTest.php@ AutomatedReportsCallbackServiceC AutomatedReportsServiceActivitieC) AutomatedRenortsServiceExtende@ AutomatedReportsServiceFieldDat(C) AutomatedRenortsServiceFormatti@ AutomatedReportsServiceGetActivC) AutomatedRenortsServiceGetPlavt( AutomatedRenortcServiceRenortGch AutomatedRenortsServiceValidateCh AutomatedRenortsServiceValidatio193—194public function testTransformReportResultsStructure: void{...}—195public function testTransformReportResultsWithMultipleResults: void{...}188 0#DataProvider('1sUserRec1p1ent0fReportDataProv1der'lpublic function testIsllserRecinient0fPeportGint fusentd, arnav Srecioients, bool Sexnected): voiff189#[DataProvider('isUserRecipient0fAskJiminnyReportDataProvider')]oublic function testIslserRecinient0fAskJiminnvReportViaGroun^int $userid,?int $groupld,array Srecipients,array SreportGroups,bool $expected,): void {...}=193=194195)=196=1971981200=201E202public static function isUserRecipient0fAskJiminnyReportDataProvider: array{...}—204public function testIsUserRecipient0fReportWithEmptyRecipients: void{...}public function testIsUserRecipient0fReportWithNoUsersKey(: void{...}l•201— 209public static function isUserRecipient0fReportDataProvider: array{...}private function createMockReportResult(strina Suuid = 'test-uuid', strina SreportTvpe = 'exec sun#DataProvider(aetUsersUuidsDataProviden']ublic function testGetlserslluids(arrav Srecipients, apray Snocklisers, array SexpectedUuids): voñd 216public function testGetUsersUuidsWithEmptyRecipients(): void{...}=219public function testGetUsersUuidsWithNoUsersKey(): void{...}nublie function testGetlisenslluidsWithNonEyictentllsenc()• voidf. .. }public static function getUsersUvidsDataProvider(): arrayf...}#[DataProvider('qetCurrentDealStagesUuidsDataProvider')]= custom.log= laravel.log4 SF jiminny@localhost] X& console [PROD]# console [euySo jiminny vm 021 A1 A18 V2 Y6 ^JOIN automated_reports a ON a.id = ar.report idWHERE a.type = 'ask jiminny'ITMTT 10.SELECT * FROM automated reports where id = 71;SELECT * FROM automated_report_ results where id = 275:SELECT * FROM automated reports order by id desc›select * fromSELECT'automated renort results' * FROM 'automated renort resultsiautomated renort results' "renort id' = 'automated renorts' 'idiautomated renort results' 'sent at' IS NOT NULIautomated nenonts' "toam id' = 1SELECT * FROM automated_reports where id = 42;SELECT * FROM users WHERE id = 143; # group 28colort + fnom tonme wbono id - 71/7.hell"suppont Dally • In 40m100% 5• Tue 19 May 14:15:12AskAnythingPromptServiceTest vCascadeAsk Jiminny Report M+0 ..Thouaht for 1s• AutomatedReportsServiceTest.php+13 -17Review Items Addrassedcnucal - Nti cuerles (Tixea)Saved searches - ActivityController.ohp: 1100 now eager-loads via ->withcount('automatedReports'), and Searchtranstormer.php: 48 reads trom aucomated_reports_count.Promots — moved loadCount('autonatedReports') into AskAnvthinaRepositorv.oho:94-100 (sinale batched countquery for the whole list). The AskAnythingPrompt::getHasReports() accessor now prefers automated reports countwhen oresent and talls back to exists() otherwise (oreserves correctness in other calli sites and tests).Moderate - Business logic moved to serviceAutomatedReportsService.php:1240-1252 now contains the quard and throws InvalidArgumentException . The controller(AskJiminnyReportsController.php:126-160) is back to a thin try/catch with an added InvalidArgumentException → 422nandler (matches the pattern already used in createAsk) iminnvReport and updateAski iminnvReport).Moderate — Tests addediAutomatedReportsservicelest.php:•testUpdateAskJiminnyReportStatusThrowsWhenEnablingWithMissingReferences - verifies the new validationthrows and uodated is never called.•testUpdateAskJiminnyReportStatusDoesNotValidateWhenDisabling - verifies disabling bypasses the validationentire v and oroceeds to undate.(I did not add controller tests per your "no unit tests for controllers" rule; the service-level coverage exercises the sameoaic.Minor - create() returns has_reports: falseAskAnythingPromptService.php:106 now passes false explicitly. Updated testCreateAskAnythingPromptWithTwoUsers to matchMinor - onBeforeDelete only on on demandNot changed in this round — tlagaed for contirmation. currentlv onlv on demand promots can be wired to Ask Jiminnyreports (tne getaskJiminnykeportritters service explicity Tetches ASKAnythingPromptlarget::on demand), so theand recording state = 'recorded' and duration > 60and status = 'completed' and actual stant time >= 12025-12-01':SELECT * FROM activities WHERE uuid to bin(•458cf915-6914-4000-b083-568763262956') = uuid:select * from leads:SELECT * FROM activities WHERE uuid to bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid: # 422003SFLECT + EPOM activitiec WHEPE id TN (16. 422003).Socket fail to connect to host:address=(host=localhost) (port=3306)(tvpe=primarv). Connection refusedna/B AskAnythingPromptServiceTest.php +25-2app/Component/AskAnything/@ AskAnythingPromptService.php +7 -2app/Repositories/ @ ASKAnythingRepository.php +7 -1ann/Httn/Trancformore/M SoarchTrancformor.nhnt1lers/API/ ActivityController.php +1 -1/M AskAnvthinaPromot.ohn +4Ask anvthina (884-L)<> Code Claude Qnus 4.7 MediumView alllAccent alliWN Windsurf Teams 242-22UTE.8io 4 spaces...
|
NULL
|
7340097739037964081
|
NULL
|
click
|
ocr
|
NULL
|
PhostormVIewINavicarecodeFV faVsco.js?9 JY-20676-d PhostormVIewINavicarecodeFV faVsco.js?9 JY-20676-delete-report-related-objectsProiect v© AskAnythingController.php> • OpportunitySyncStrategy• • ProspectSearchStrategy• M ServiceTraits© AskAnythingPromptService.php© AutomatedReportsServiceTest.php X© AskAnythingPromptDto.php© Automateakeport.php© ClientTest.phpC) DecorateActivitylest.pnpC DeleteObjectsTraitTest.php© FieldDefinitionsTest.phpC GetActivityFieldNameTest.phpPayloadBuilderTest.php@ QueryBuilderTest.phpC) QueryHandlerTest.php© QuerylteratorTest.php© QuervResultsTests.php© AskJiminnyReportsController.phg© Autonclass AutomatedReportsservicelest extends Testcase240 0 )(c) service lest.onoC SvncBatchRedisServiceTest.php©) BaseServiceTest.oho341 %©) CachedcrmServiceDecoratorTest.ohg©) CrmActivitvServicelest.onoc) crmobiectsResolveriiest.onoc DefaultProsnectSearchStrateavTest.cc EmailHelperTest.oho© FieldValueConverterTest.phpc LavoutManaderTest.oho© MigrateProviderServiceTest.php© OpportunityActivityMatcherTest.php© OpportunitySyncStrategyResolverTes© ProspectCacheTest.php© ProspectSearchStrategyFactoryTest.r© ProviderRegistryTest.php© RecordSelectorTest.phpaDocolwoCamnanyNamoRySmailTroitt423 ₽©) TimePeriodlteratorTest.php© UpdateCrmDataResolverTest.php> C Internalv @ Kioskv @ AutomatedReports© ActivitvTvpeServiceTest.php© AskJiminnyReportActivitvServiceT© AskJiminnyReportServiceTest.php@ AutomatedReportsCallbackServiceC AutomatedReportsServiceActivitieC) AutomatedRenortsServiceExtende@ AutomatedReportsServiceFieldDat(C) AutomatedRenortsServiceFormatti@ AutomatedReportsServiceGetActivC) AutomatedRenortsServiceGetPlavt( AutomatedRenortcServiceRenortGch AutomatedRenortsServiceValidateCh AutomatedRenortsServiceValidatio193—194public function testTransformReportResultsStructure: void{...}—195public function testTransformReportResultsWithMultipleResults: void{...}188 0#DataProvider('1sUserRec1p1ent0fReportDataProv1der'lpublic function testIsllserRecinient0fPeportGint fusentd, arnav Srecioients, bool Sexnected): voiff189#[DataProvider('isUserRecipient0fAskJiminnyReportDataProvider')]oublic function testIslserRecinient0fAskJiminnvReportViaGroun^int $userid,?int $groupld,array Srecipients,array SreportGroups,bool $expected,): void {...}=193=194195)=196=1971981200=201E202public static function isUserRecipient0fAskJiminnyReportDataProvider: array{...}—204public function testIsUserRecipient0fReportWithEmptyRecipients: void{...}public function testIsUserRecipient0fReportWithNoUsersKey(: void{...}l•201— 209public static function isUserRecipient0fReportDataProvider: array{...}private function createMockReportResult(strina Suuid = 'test-uuid', strina SreportTvpe = 'exec sun#DataProvider(aetUsersUuidsDataProviden']ublic function testGetlserslluids(arrav Srecipients, apray Snocklisers, array SexpectedUuids): voñd 216public function testGetUsersUuidsWithEmptyRecipients(): void{...}=219public function testGetUsersUuidsWithNoUsersKey(): void{...}nublie function testGetlisenslluidsWithNonEyictentllsenc()• voidf. .. }public static function getUsersUvidsDataProvider(): arrayf...}#[DataProvider('qetCurrentDealStagesUuidsDataProvider')]= custom.log= laravel.log4 SF jiminny@localhost] X& console [PROD]# console [euySo jiminny vm 021 A1 A18 V2 Y6 ^JOIN automated_reports a ON a.id = ar.report idWHERE a.type = 'ask jiminny'ITMTT 10.SELECT * FROM automated reports where id = 71;SELECT * FROM automated_report_ results where id = 275:SELECT * FROM automated reports order by id desc›select * fromSELECT'automated renort results' * FROM 'automated renort resultsiautomated renort results' "renort id' = 'automated renorts' 'idiautomated renort results' 'sent at' IS NOT NULIautomated nenonts' "toam id' = 1SELECT * FROM automated_reports where id = 42;SELECT * FROM users WHERE id = 143; # group 28colort + fnom tonme wbono id - 71/7.hell"suppont Dally • In 40m100% 5• Tue 19 May 14:15:12AskAnythingPromptServiceTest vCascadeAsk Jiminny Report M+0 ..Thouaht for 1s• AutomatedReportsServiceTest.php+13 -17Review Items Addrassedcnucal - Nti cuerles (Tixea)Saved searches - ActivityController.ohp: 1100 now eager-loads via ->withcount('automatedReports'), and Searchtranstormer.php: 48 reads trom aucomated_reports_count.Promots — moved loadCount('autonatedReports') into AskAnvthinaRepositorv.oho:94-100 (sinale batched countquery for the whole list). The AskAnythingPrompt::getHasReports() accessor now prefers automated reports countwhen oresent and talls back to exists() otherwise (oreserves correctness in other calli sites and tests).Moderate - Business logic moved to serviceAutomatedReportsService.php:1240-1252 now contains the quard and throws InvalidArgumentException . The controller(AskJiminnyReportsController.php:126-160) is back to a thin try/catch with an added InvalidArgumentException → 422nandler (matches the pattern already used in createAsk) iminnvReport and updateAski iminnvReport).Moderate — Tests addediAutomatedReportsservicelest.php:•testUpdateAskJiminnyReportStatusThrowsWhenEnablingWithMissingReferences - verifies the new validationthrows and uodated is never called.•testUpdateAskJiminnyReportStatusDoesNotValidateWhenDisabling - verifies disabling bypasses the validationentire v and oroceeds to undate.(I did not add controller tests per your "no unit tests for controllers" rule; the service-level coverage exercises the sameoaic.Minor - create() returns has_reports: falseAskAnythingPromptService.php:106 now passes false explicitly. Updated testCreateAskAnythingPromptWithTwoUsers to matchMinor - onBeforeDelete only on on demandNot changed in this round — tlagaed for contirmation. currentlv onlv on demand promots can be wired to Ask Jiminnyreports (tne getaskJiminnykeportritters service explicity Tetches ASKAnythingPromptlarget::on demand), so theand recording state = 'recorded' and duration > 60and status = 'completed' and actual stant time >= 12025-12-01':SELECT * FROM activities WHERE uuid to bin(•458cf915-6914-4000-b083-568763262956') = uuid:select * from leads:SELECT * FROM activities WHERE uuid to bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid: # 422003SFLECT + EPOM activitiec WHEPE id TN (16. 422003).Socket fail to connect to host:address=(host=localhost) (port=3306)(tvpe=primarv). Connection refusedna/B AskAnythingPromptServiceTest.php +25-2app/Component/AskAnything/@ AskAnythingPromptService.php +7 -2app/Repositories/ @ ASKAnythingRepository.php +7 -1ann/Httn/Trancformore/M SoarchTrancformor.nhnt1lers/API/ ActivityController.php +1 -1/M AskAnvthinaPromot.ohn +4Ask anvthina (884-L)<> Code Claude Qnus 4.7 MediumView alllAccent alliWN Windsurf Teams 242-22UTE.8io 4 spaces...
|
57907
|
NULL
|
NULL
|
NULL
|
|
57908
|
2036
|
26
|
2026-05-19T11:15:13.216804+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189313216_m1.jpg...
|
PhpStorm
|
faVsco.js – AutomatedReportsServiceTest.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 45 m100% C7Tue 19 May 14:15:13ED→Describe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
1249825932853792307
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 45 m100% C7Tue 19 May 14:15:13ED→Describe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
57906
|
NULL
|
NULL
|
NULL
|
|
57907
|
2037
|
33
|
2026-05-19T11:15:07.472532+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189307472_m2.jpg...
|
PhpStorm
|
faVsco.js – AutomatedReportsServiceTest.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormVIewINavicarecodeWindowFV faVsco.js°9 JY-2 PhostormVIewINavicarecodeWindowFV faVsco.js°9 JY-20676-delete-report-related-objectsroledey© AskAnythingController.php> • OpportunitySyncStrategy• • ProspectSearchStrategy> N ServiceTraits© ClientTest.phpC) DecorateActivitylest.pnpC DeleteObjectsTraitTest.php© FieldDefinitionsTest.phpC GetActivityFieldNameTest.phpPayloadBuilderTest.php@ QueryBuilderTest.phpC) QueryHandlerTest.php© QuerylteratorTest.php© QuervResultsTests.phpC ServiceTest.phpC SvncBatchRedisServiceTest.php© AskAnythingPromptService.php© AutomatedReportsServiceTest.php X© AskAnythingPromptDto.php© Automateakeport.php© AskJiminnyReportsController.phg© AutomatedReportsService.phpclass AutomatedReportsservicelest extends Testcase16351636 %1655 %1670 %1685 %1694 V1©) BaseServiceTest.oho©) CachedcrmServiceDecoratorTest.ohg1703 %©) CrmActivitvServicelest.ono1712 %c) crmobiectsResolveriiest.onoc DefaultProsnectSearchStrateavTest.c1921 Vc EmailHelperTest.ohoc FieldValueConverterTest.oho1730 V.lc LavoutManaderTest.oho© MigrateProviderServiceTest.phpci OnnortunitvActivitvMatcherTect nhn1738 V..© OpportunitySyncStrategyResolverTes© ProspectCacheTest.php© ProspectSearchStrategyFactoryTest.r1754 VC ProviderPeaistrvTect nhnl© RecordSelectorTest.php@PocalvaComnanuNamoRuEmallTraitt, 1762 %©) TimePeriodlteratorTest.php© UpdateCrmDataResolverTest.php> C Internalv @ Kioskv @ AutomatedReports© ActivitvTvpeServiceTest.php© AskJiminnyReportActivitvServiceTa© AskJiminnyReportServiceTest.php@ AutomatedReportsCallbackServiceC AutomatedReportsServiceActivitie.17701711778 %C) AutomatedRenortsServiceExtende@ AutomatedReportsServiceFieldDat(C) AutomatedRenortsServiceFormatti@ AutomatedReportsServiceGetActivC) AutomatedRenortsServiceGetPlavt( AutomatedRenortcServiceRenortGci AutomatedRenortsServiceTect nhnch AutomatedRenortsServiceValidateCh AutomatedRenortsServiceValidatio1985 V.public function testGetReportTypeFieldDataWithTeamHavingBothFeatures: void{...}public function testGetReportTypeFieldDataWithTeamHaving0nlyAutomatedReports: void{...}public function testGetReportTypeFieldDataWithTeamHaving0nlyAskJiminnyO: void{...}public function testGetReportTypeFieldDataWithNullTeamFallsBackToStandardTypes: void{...}public function testGetFrequencyFieldDataO: void{...}public function testGetPer1odFieldbata): voidi...*public function testbetcal durationFielddatao: void'...;public function testGetbealValueFielddata): voidi...public function testGetCustomReportNameFieldData(): void{...}public function testGetAdditionalPromptInputFieldData(): voidf...}public function testGetCallTypeFieldDataBoth0n: voidt...}public function testGetCallTypeFieldDataNone0n: void{...}public function testGetCallTypeFieldDataConference0nly: void{...=public function testGetCallTypeFieldDataDialerOnly: void{...}public function testTransformDurationToMinutesNullO: void{...}public function testTransformDurationToMinutesZero0: void{...}public function testTransformDurationToMinutes: void{...}public function testGetTeamo: voidf...}public function testGetTeamById(): voidf...}nublic function testGetGrounslluidsEmptv@: void!...?oublic function testGetGrouosUuidsWithGrounso: void....;nublie function +estGe+PlavhookCateaonieclluidcWithCateaonies(- voidf. ?biects // View null reauect (57 minutes aao)=custom.log193—194—195-189—190- 192=193=194=196—197200= 219|220= laravel.log4 SF jiminny@localhost] x4 HS_local [jiminny@localhost]& console [PROD]# console [euyCoachinaFeedhackCoachl.Icerin.nhnPlavaroundSo jiminny vm 021 A1 A18 V2 Y6 ^JOIN automated_ reports a ON a.id = ar.report idWHERE a.type = 'ask jiminny'ITMTT 10.SELECT * FROM automated reports where id = 71;SELECT * FROM automated report results where report id = 71;SELECT * FROM automated_report_ results where id = 275:SELECT * FROM automated reports order by id desc›select * from activity searches where user id = 143:select * fromSELECTautomated renort results' * FROM 'automated renort resultsiINNER JOIN 'automated renortsiautomated renort results' "renort id' = 'automated renorts' 'idiautomated renort results' 'aenerated at' IS NOT NULLautomated renort results' sent at' IS NOT NULIautomated nenonts' "toam id' = 1SELECT * FROM automated_reports where id = 67:SELECT * FROM automated_reports where id = 42;SELECT * FROM users WHERE id = 143; # group 28colost + fnom tonme whono id - 71/7.SELECT * FROM social accounts WHERE sociable_id = 1695:and recording state = 'recorded' and duration > 60and status = 'completed' and actual start time >= 12025-12-01'•SELECT * FROM activities WHERE uuid to bin('458cf915-6914-4000-b083-568763262956') = uuid:select * from leads:SELECT * FROM activities WHERE uuid to bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid: # 422003Socket fail to connect to host:address=(host=localhost) (port=3306)(tvpe=primarv). Connection refusedhell"suppont Dally • In 40m100% 5• Tue 19 May 14:15:06AskAnythingPromptServiceTest vCascadeAsk Jiminny Report M+0 •Thouaht for 1s• AutomatedReportsServiceTest.php÷13 -17Review Items Addrassedcnucal - Nti cuerles (Tixea)Saved searches - ActivityController.ohp: 1100 now eager-loads via ->withcount('automatedReports'), and Searchtranstormer.php: 48 reads trom aucomated_reports_count.Promots — moved loadCount('autonatedReports') into AskAnvthinaRepositorv.oho:94-100 (sinale batched countquery for the whole list). The AskAnythingPrompt::getHasReports() accessor now prefers automated reports countwhen oresent and talls back to exists() otherwise (oreserves correctness in other calli sites and tests).Moderate - Business logic moved to serviceAutomatedReportsService.php:1240-1252 now contains the quard and throws InvalidArgumentException . The controller(AskJiminnyReportsController.php:126-160) is back to a thin try/catch with an added InvalidArgumentException → 422nandler (matches the pattern already used in createAsk) iminnvReport and updateAski iminnvReport).Moderate — Tests addediAutomatedReportsservicelest.php:•testUpdateAskJiminnyReportStatusThrowsWhenEnablingWithMissingReferences - verifies the new validationthrows and uodated is never called.•testUpdateAskJiminnyReportStatusDoesNotValidateWhenDisabling - verifies disabling bypasses the validationentire v and oroceeds to undate.(I did not add controller tests per your "no unit tests for controllers" rule; the service-level coverage exercises the sameoaic.Minor - create() returns has_reports: falseAskAnythingPromptService.php:106 now passes false explicitly. Updated testCreateAskAnythingPromptWithTwoUsers to matchMinor - onBeforeDelete only on on demandNot changed in this round — tlagaed for contirmation. currentlv onlv on demand promots can be wired to Ask Jiminnyreports (tne getaskJiminnykeportritters service explicity Tetches ASKAnythingPromptlarget::on demand), so thetests/Unit/Component/AskAnvthing/B AskAnythingPromptServiceTest.php +25-2app/Component/AskAnything/@ AskAnythingPromptService.php +7 -2app/Repositories/ @ ASKAnythingRepository.php +7 -1ann/Httn/Trancformorc/MSoarchTrancformornhntlers/API/ ActivityController.php +1/m AskAnvthinaPromot.oho +4Ask anvthing 884-D)<> Code Claude Qnus 4.7 MediumView alllAccent allWN Windsurf Toams 1220-1UITF.8io 4 spaces...
|
NULL
|
2724556128589893551
|
NULL
|
click
|
ocr
|
NULL
|
PhostormVIewINavicarecodeWindowFV faVsco.js°9 JY-2 PhostormVIewINavicarecodeWindowFV faVsco.js°9 JY-20676-delete-report-related-objectsroledey© AskAnythingController.php> • OpportunitySyncStrategy• • ProspectSearchStrategy> N ServiceTraits© ClientTest.phpC) DecorateActivitylest.pnpC DeleteObjectsTraitTest.php© FieldDefinitionsTest.phpC GetActivityFieldNameTest.phpPayloadBuilderTest.php@ QueryBuilderTest.phpC) QueryHandlerTest.php© QuerylteratorTest.php© QuervResultsTests.phpC ServiceTest.phpC SvncBatchRedisServiceTest.php© AskAnythingPromptService.php© AutomatedReportsServiceTest.php X© AskAnythingPromptDto.php© Automateakeport.php© AskJiminnyReportsController.phg© AutomatedReportsService.phpclass AutomatedReportsservicelest extends Testcase16351636 %1655 %1670 %1685 %1694 V1©) BaseServiceTest.oho©) CachedcrmServiceDecoratorTest.ohg1703 %©) CrmActivitvServicelest.ono1712 %c) crmobiectsResolveriiest.onoc DefaultProsnectSearchStrateavTest.c1921 Vc EmailHelperTest.ohoc FieldValueConverterTest.oho1730 V.lc LavoutManaderTest.oho© MigrateProviderServiceTest.phpci OnnortunitvActivitvMatcherTect nhn1738 V..© OpportunitySyncStrategyResolverTes© ProspectCacheTest.php© ProspectSearchStrategyFactoryTest.r1754 VC ProviderPeaistrvTect nhnl© RecordSelectorTest.php@PocalvaComnanuNamoRuEmallTraitt, 1762 %©) TimePeriodlteratorTest.php© UpdateCrmDataResolverTest.php> C Internalv @ Kioskv @ AutomatedReports© ActivitvTvpeServiceTest.php© AskJiminnyReportActivitvServiceTa© AskJiminnyReportServiceTest.php@ AutomatedReportsCallbackServiceC AutomatedReportsServiceActivitie.17701711778 %C) AutomatedRenortsServiceExtende@ AutomatedReportsServiceFieldDat(C) AutomatedRenortsServiceFormatti@ AutomatedReportsServiceGetActivC) AutomatedRenortsServiceGetPlavt( AutomatedRenortcServiceRenortGci AutomatedRenortsServiceTect nhnch AutomatedRenortsServiceValidateCh AutomatedRenortsServiceValidatio1985 V.public function testGetReportTypeFieldDataWithTeamHavingBothFeatures: void{...}public function testGetReportTypeFieldDataWithTeamHaving0nlyAutomatedReports: void{...}public function testGetReportTypeFieldDataWithTeamHaving0nlyAskJiminnyO: void{...}public function testGetReportTypeFieldDataWithNullTeamFallsBackToStandardTypes: void{...}public function testGetFrequencyFieldDataO: void{...}public function testGetPer1odFieldbata): voidi...*public function testbetcal durationFielddatao: void'...;public function testGetbealValueFielddata): voidi...public function testGetCustomReportNameFieldData(): void{...}public function testGetAdditionalPromptInputFieldData(): voidf...}public function testGetCallTypeFieldDataBoth0n: voidt...}public function testGetCallTypeFieldDataNone0n: void{...}public function testGetCallTypeFieldDataConference0nly: void{...=public function testGetCallTypeFieldDataDialerOnly: void{...}public function testTransformDurationToMinutesNullO: void{...}public function testTransformDurationToMinutesZero0: void{...}public function testTransformDurationToMinutes: void{...}public function testGetTeamo: voidf...}public function testGetTeamById(): voidf...}nublic function testGetGrounslluidsEmptv@: void!...?oublic function testGetGrouosUuidsWithGrounso: void....;nublie function +estGe+PlavhookCateaonieclluidcWithCateaonies(- voidf. ?biects // View null reauect (57 minutes aao)=custom.log193—194—195-189—190- 192=193=194=196—197200= 219|220= laravel.log4 SF jiminny@localhost] x4 HS_local [jiminny@localhost]& console [PROD]# console [euyCoachinaFeedhackCoachl.Icerin.nhnPlavaroundSo jiminny vm 021 A1 A18 V2 Y6 ^JOIN automated_ reports a ON a.id = ar.report idWHERE a.type = 'ask jiminny'ITMTT 10.SELECT * FROM automated reports where id = 71;SELECT * FROM automated report results where report id = 71;SELECT * FROM automated_report_ results where id = 275:SELECT * FROM automated reports order by id desc›select * from activity searches where user id = 143:select * fromSELECTautomated renort results' * FROM 'automated renort resultsiINNER JOIN 'automated renortsiautomated renort results' "renort id' = 'automated renorts' 'idiautomated renort results' 'aenerated at' IS NOT NULLautomated renort results' sent at' IS NOT NULIautomated nenonts' "toam id' = 1SELECT * FROM automated_reports where id = 67:SELECT * FROM automated_reports where id = 42;SELECT * FROM users WHERE id = 143; # group 28colost + fnom tonme whono id - 71/7.SELECT * FROM social accounts WHERE sociable_id = 1695:and recording state = 'recorded' and duration > 60and status = 'completed' and actual start time >= 12025-12-01'•SELECT * FROM activities WHERE uuid to bin('458cf915-6914-4000-b083-568763262956') = uuid:select * from leads:SELECT * FROM activities WHERE uuid to bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid: # 422003Socket fail to connect to host:address=(host=localhost) (port=3306)(tvpe=primarv). Connection refusedhell"suppont Dally • In 40m100% 5• Tue 19 May 14:15:06AskAnythingPromptServiceTest vCascadeAsk Jiminny Report M+0 •Thouaht for 1s• AutomatedReportsServiceTest.php÷13 -17Review Items Addrassedcnucal - Nti cuerles (Tixea)Saved searches - ActivityController.ohp: 1100 now eager-loads via ->withcount('automatedReports'), and Searchtranstormer.php: 48 reads trom aucomated_reports_count.Promots — moved loadCount('autonatedReports') into AskAnvthinaRepositorv.oho:94-100 (sinale batched countquery for the whole list). The AskAnythingPrompt::getHasReports() accessor now prefers automated reports countwhen oresent and talls back to exists() otherwise (oreserves correctness in other calli sites and tests).Moderate - Business logic moved to serviceAutomatedReportsService.php:1240-1252 now contains the quard and throws InvalidArgumentException . The controller(AskJiminnyReportsController.php:126-160) is back to a thin try/catch with an added InvalidArgumentException → 422nandler (matches the pattern already used in createAsk) iminnvReport and updateAski iminnvReport).Moderate — Tests addediAutomatedReportsservicelest.php:•testUpdateAskJiminnyReportStatusThrowsWhenEnablingWithMissingReferences - verifies the new validationthrows and uodated is never called.•testUpdateAskJiminnyReportStatusDoesNotValidateWhenDisabling - verifies disabling bypasses the validationentire v and oroceeds to undate.(I did not add controller tests per your "no unit tests for controllers" rule; the service-level coverage exercises the sameoaic.Minor - create() returns has_reports: falseAskAnythingPromptService.php:106 now passes false explicitly. Updated testCreateAskAnythingPromptWithTwoUsers to matchMinor - onBeforeDelete only on on demandNot changed in this round — tlagaed for contirmation. currentlv onlv on demand promots can be wired to Ask Jiminnyreports (tne getaskJiminnykeportritters service explicity Tetches ASKAnythingPromptlarget::on demand), so thetests/Unit/Component/AskAnvthing/B AskAnythingPromptServiceTest.php +25-2app/Component/AskAnything/@ AskAnythingPromptService.php +7 -2app/Repositories/ @ ASKAnythingRepository.php +7 -1ann/Httn/Trancformorc/MSoarchTrancformornhntlers/API/ ActivityController.php +1/m AskAnvthinaPromot.oho +4Ask anvthing 884-D)<> Code Claude Qnus 4.7 MediumView alllAccent allWN Windsurf Toams 1220-1UITF.8io 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57906
|
2036
|
25
|
2026-05-19T11:15:11.225779+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189311225_m1.jpg...
|
PhpStorm
|
faVsco.js – AutomatedReportsServiceTest.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
16
104
73
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Services\Kiosk\AutomatedReports;
use Carbon\Carbon;
use Illuminate\Support\Carbon as IlluminateCarbon;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Jiminny\Component\AskAnything\AskAnythingPromptService;
use Jiminny\Component\AskAnything\Dtos\AskAnythingPromptDto;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Contracts\Repositories\PlaybookCategoryRepository;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Contracts\Repositories\UserRepository;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Exceptions\ModelNotFoundException;
use Illuminate\Support\Collection;
use Jiminny\Models\AskAnything\AskAnythingPrompt;
use Jiminny\Models\AskAnything\AskAnythingPromptTarget;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Group;
use Jiminny\Models\Partner;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Repositories\AskAnythingRepository;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Repositories\GroupRepository;
use Jiminny\Repositories\SearchRepository;
use Jiminny\Repositories\StageRepository;
use Jiminny\Services\Kiosk\AutomatedReports\ActivityTypeService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\DealStagesService;
use Jiminny\Services\Kiosk\AutomatedReports\RecipientsService;
use Mockery;
use PHPUnit\Framework\Attributes\DataProvider;
use Tests\TestCase;
class AutomatedReportsServiceTest extends TestCase
{
private AutomatedReportsService $service;
protected function setUp(): void
{
parent::setUp();
// Create a real instance of the service without calling the constructor
$reflection = new \ReflectionClass(AutomatedReportsService::class);
$this->service = $reflection->newInstanceWithoutConstructor();
// Manually set the dependencies using reflection
$dependencies = [
'teamRepository' => TeamRepository::class,
'groupRepository' => GroupRepository::class,
'userRepository' => UserRepository::class,
'stageRepository' => StageRepository::class,
'dealStagesService' => DealStagesService::class,
'recipientsService' => RecipientsService::class,
'automatedReportsRepository' => AutomatedReportsRepository::class,
'webhookService' => Webhook::class,
'dispatcher' => Dispatcher::class,
'activityTypeService' => ActivityTypeService::class,
'playbookCategoryRepository' => PlaybookCategoryRepository::class,
'askAnythingPromptService' => AskAnythingPromptService::class,
'activitySearchRepository' => SearchRepository::class,
'askAnythingRepository' => AskAnythingRepository::class,
];
foreach ($dependencies as $propertyName => $class) {
$property = $reflection->getProperty($propertyName);
$property->setAccessible(true);
$property->setValue($this->service, $this->createMock($class));
}
}
protected function tearDown(): void
{
parent::tearDown();
Mockery::close();
}
private function getService(
$mockUserRepository = null,
$mockStageRepository = null,
$mockTeamRepository = null,
): AutomatedReportsService {
return new AutomatedReportsService(
($mockTeamRepository ?? $this->createMock(TeamRepository::class)),
$this->createMock(GroupRepository::class),
($mockUserRepository ?? $this->createMock(UserRepository::class)),
($mockStageRepository ?? $this->createMock(StageRepository::class)),
$this->createMock(DealStagesService::class),
$this->createMock(RecipientsService::class),
$this->createMock(AutomatedReportsRepository::class),
$this->createMock(Webhook::class),
$this->createMock(Dispatcher::class),
$this->createMock(ActivityTypeService::class),
$this->createMock(PlaybookCategoryRepository::class),
$this->createMock(AskAnythingPromptService::class),
$this->createMock(SearchRepository::class),
$this->createMock(AskAnythingRepository::class),
);
}
#[DataProvider('transformMediaTypesDataProvider')]
public function testTransformMediaTypes(array $mediaTypes, array $expected): void
{
$report = new AutomatedReport(['media_types' => $mediaTypes]);
$reflection = new \ReflectionClass(AutomatedReportsService::class);
$method = $reflection->getMethod('transformMediaTypes');
$result = $method->invoke($this->service, $report);
$this->assertEquals($expected, $result);
}
public function testGetMediaTypeFieldDataWithoutReport(): void
{
$result = $this->service->getMediaTypeFieldData(null);
$this->assertIsArray($result);
$this->assertArrayHasKey('value', $result);
$this->assertEmpty($result['value']);
$this->assertEquals('media_types', $result['id']);
}
public function testGetMediaTypeFieldDataWithReport(): void
{
$mediaTypes = ['pdf', 'podcast'];
$report = new AutomatedReport(['media_types' => $mediaTypes]);
$result = $this->service->getMediaTypeFieldData($report);
$expectedValue = [
['id' => 'pdf', 'name' => 'PDF'],
['id' => 'podcast', 'name' => 'Podcast'],
];
$this->assertIsArray($result);
$this->assertArrayHasKey('value', $result);
$this->assertEquals($expectedValue, $result['value']);
}
public static function transformMediaTypesDataProvider(): array
{
return [
'empty array' => [
'mediaTypes' => [],
'expected' => [],
],
'pdf only' => [
'mediaTypes' => ['pdf'],
'expected' => [
['id' => 'pdf', 'name' => 'PDF'],
],
],
'podcast only' => [
'mediaTypes' => ['podcast'],
'expected' => [
['id' => 'podcast', 'name' => 'Podcast'],
],
],
'both pdf and podcast' => [
'mediaTypes' => ['pdf', 'podcast'],
'expected' => [
['id' => 'pdf', 'name' => 'PDF'],
['id' => 'podcast', 'name' => 'Podcast'],
],
],
'with invalid type' => [
'mediaTypes' => ['pdf', 'invalid', 'podcast'],
'expected' => [
['id' => 'pdf', 'name' => 'PDF'],
['id' => 'podcast', 'name' => 'Podcast'],
],
],
];
}
#[DataProvider('hasCallTypeConferenceDataProvider')]
public function testHasCallTypeConference(array $callTypes, bool $expected): void
{
$report = $this->createMock(AutomatedReport::class);
$report->method('getCallTypes')->willReturn($callTypes);
$result = $this->service->hasCallTypeConference($report);
$this->assertEquals($expected, $result);
}
#[DataProvider('hasCallTypeDialerDataProvider')]
public function testHasCallTypeDialer(array $callTypes, bool $expected): void
{
$report = $this->createMock(AutomatedReport::class);
$report->method('getCallTypes')->willReturn($callTypes);
$result = $this->service->hasCallTypeDialer($report);
$this->assertEquals($expected, $result);
}
public static function hasCallTypeConferenceDataProvider(): array
{
return [
'has conference' => [
'callTypes' => ['conference', 'dialer'],
'expected' => true,
],
'does not have conference' => [
'callTypes' => ['dialer', 'other'],
'expected' => false,
],
'empty call types' => [
'callTypes' => [],
'expected' => false,
],
];
}
public static function hasCallTypeDialerDataProvider(): array
{
return [
'has dialer' => [
'callTypes' => ['conference', 'dialer'],
'expected' => true,
],
'does not have dialer' => [
'callTypes' => ['conference', 'other'],
'expected' => false,
],
'empty call types' => [
'callTypes' => [],
'expected' => false,
],
];
}
public function testTransformReportResultsWithEmptyCollection(): void
{
$emptyCollection = new Collection([]);
$result = $this->service->transformReportResults($emptyCollection);
$this->assertIsArray($result);
$this->assertEmpty($result);
}
public function testTransformReportResultsStructure(): void
{
// Create a mock AutomatedReportResult with minimal setup to test structure
$mockReportResult = $this->createMockReportResult();
$collection = new Collection([$mockReportResult]);
$result = $this->service->transformReportResults($collection);
$this->assertIsArray($result);
$this->assertCount(1, $result);
$transformedResult = $result[0];
// Verify all expected keys are present
$expectedKeys = [
'id', 'name', 'frequency', 'recipients',
'report_type', 'media_type', 'downloadUrl', 'viewUrl', 'generated_at',
];
foreach ($expectedKeys as $key) {
$this->assertArrayHasKey($key, $transformedResult);
}
// Verify structure of nested arrays
$this->assertIsArray($transformedResult['frequency']);
$this->assertArrayHasKey('id', $transformedResult['frequency']);
$this->assertArrayHasKey('name', $transformedResult['frequency']);
$this->assertIsArray($transformedResult['report_type']);
$this->assertArrayHasKey('id', $transformedResult['report_type']);
$this->assertArrayHasKey('name', $transformedResult['report_type']);
$this->assertIsArray($transformedResult['recipients']);
// Verify TODO fields are null as expected
$this->assertEquals(AutomatedReportsService::MEDIA_TYPE_PODCAST, $transformedResult['media_type']);
$this->assertEquals(route('ai-reports.audio.download', ['uuid' => 'test-uuid']), $transformedResult['downloadUrl']);
$this->assertEquals(route('ai-reports.audio.view', ['uuid' => 'test-uuid']), $transformedResult['viewUrl']);
}
public function testTransformReportResultsWithMultipleResults(): void
{
$mockReportResult1 = $this->createMockReportResult('result-uuid-1', 'exec_summary');
$mockReportResult2 = $this->createMockReportResult('result-uuid-2', 'coaching_profiles');
$collection = new Collection([$mockReportResult1, $mockReportResult2]);
$result = $this->service->transformReportResults($collection);
$this->assertIsArray($result);
$this->assertCount(2, $result);
// Verify different UUIDs
$this->assertEquals('result-uuid-1', $result[0]['id']);
$this->assertEquals('result-uuid-2', $result[1]['id']);
// Verify both results have the expected structure
foreach ($result as $transformedResult) {
$this->assertArrayHasKey('id', $transformedResult);
$this->assertArrayHasKey('name', $transformedResult);
$this->assertArrayHasKey('frequency', $transformedResult);
$this->assertArrayHasKey('recipients', $transformedResult);
$this->assertArrayHasKey('report_type', $transformedResult);
}
}
#[DataProvider('isUserRecipientOfReportDataProvider')]
public function testIsUserRecipientOfReport(int $userId, array $recipients, bool $expected): void
{
// Create mock User
$mockUser = $this->createMock(\Jiminny\Models\User::class);
$mockUser->method('getId')->willReturn($userId);
$mockUser->method('getGroupId')->willReturn(null);
// Create mock AutomatedReport
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getRecipients')->willReturn($recipients);
$mockReport->method('isAskJiminnyReport')->willReturn(false);
$mockReport->method('getGroups')->willReturn([]);
$result = $this->service->isUserRecipientOfReport($mockUser, $mockReport);
$this->assertEquals($expected, $result);
}
#[DataProvider('isUserRecipientOfAskJiminnyReportDataProvider')]
public function testIsUserRecipientOfAskJiminnyReportViaGroup(
int $userId,
?int $groupId,
array $recipients,
array $reportGroups,
bool $expected,
): void {
$mockUser = $this->createMock(\Jiminny\Models\User::class);
$mockUser->method('getId')->willReturn($userId);
$mockUser->method('getGroupId')->willReturn($groupId);
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getRecipients')->willReturn($recipients);
$mockReport->method('isAskJiminnyReport')->willReturn(true);
$mockReport->method('getGroups')->willReturn($reportGroups);
$this->assertSame($expected, $this->service->isUserRecipientOfReport($mockUser, $mockReport));
}
public function testIsUserRecipientOfNonAskJiminnyReportIgnoresGroups(): void
{
$mockUser = $this->createMock(\Jiminny\Models\User::class);
$mockUser->method('getId')->willReturn(123);
$mockUser->method('getGroupId')->willReturn(5);
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getRecipients')->willReturn(['users' => []]);
$mockReport->method('isAskJiminnyReport')->willReturn(false);
$mockReport->method('getGroups')->willReturn([5]);
$this->assertFalse($this->service->isUserRecipientOfReport($mockUser, $mockReport));
}
public static function isUserRecipientOfAskJiminnyReportDataProvider(): array
{
return [
'group member - ask jiminny' => [
'userId' => 123,
'groupId' => 7,
'recipients' => ['users' => []],
'reportGroups' => [7],
'expected' => true,
],
'group mismatch - ask jiminny' => [
'userId' => 123,
'groupId' => 9,
'recipients' => ['users' => []],
'reportGroups' => [7, 8],
'expected' => false,
],
'user with no group - ask jiminny' => [
'userId' => 123,
'groupId' => null,
'recipients' => ['users' => []],
'reportGroups' => [7],
'expected' => false,
],
'recipient users take precedence over group' => [
'userId' => 123,
'groupId' => null,
'recipients' => ['users' => [123]],
'reportGroups' => [],
'expected' => true,
],
];
}
public function testIsUserRecipientOfReportWithEmptyRecipients(): void
{
// Create mock User
$mockUser = $this->createMock(\Jiminny\Models\User::class);
$mockUser->method('getId')->willReturn(123);
// Create mock AutomatedReport with no recipients
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getRecipients')->willReturn([]);
$result = $this->service->isUserRecipientOfReport($mockUser, $mockReport);
$this->assertFalse($result);
}
public function testIsUserRecipientOfReportWithNoUsersKey(): void
{
// Create mock User
$mockUser = $this->createMock(\Jiminny\Models\User::class);
$mockUser->method('getId')->willReturn(123);
// Create mock AutomatedReport with recipients but no 'users' key
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getRecipients')->willReturn(['other_key' => [456, 789]]);
$result = $this->service->isUserRecipientOfReport($mockUser, $mockReport);
$this->assertFalse($result);
}
public static function isUserRecipientOfReportDataProvider(): array
{
return [
'user is recipient - single user' => [
'userId' => 123,
'recipients' => ['users' => [123]],
'expected' => true,
],
'user is recipient - multiple users' => [
'userId' => 456,
'recipients' => ['users' => [123, 456, 789]],
'expected' => true,
],
'user is not recipient - single user' => [
'userId' => 999,
'recipients' => ['users' => [123]],
'expected' => false,
],
'user is not recipient - multiple users' => [
'userId' => 999,
'recipients' => ['users' => [123, 456, 789]],
'expected' => false,
],
'user is recipient - string IDs converted to int' => [
'userId' => 123,
'recipients' => ['users' => ['123', '456']],
'expected' => true,
],
'user is not recipient - string IDs converted to int' => [
'userId' => 999,
'recipients' => ['users' => ['123', '456']],
'expected' => false,
],
'empty users array' => [
'userId' => 123,
'recipients' => ['users' => []],
'expected' => false,
],
];
}
private function createMockReportResult(string $uuid = 'test-uuid', string $reportType = 'exec_summary'): AutomatedReportResult
{
// Create mock AutomatedReport
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getFrequency')->willReturn('weekly');
$mockReport->method('getRecipients')->willReturn(['users' => [1, 2]]);
$mockReport->method('getGroups')->willReturn([10, 20]);
$mockReport->method('getType')->willReturn($reportType);
// Create mock Team
$mockTeam = $this->createMock(\Jiminny\Models\Team::class);
// Create mock Group
$mockGroup = $this->createMock(\Jiminny\Models\Group::class);
$mockGroup->method('getUuid')->willReturn('group-uuid-10');
$mockGroup->method('getName')->willReturn('Test Team');
$mockQueryBuilder = Mockery::mock();
$mockQueryBuilder->shouldReceive('where')->andReturnSelf();
$mockQueryBuilder->shouldReceive('first')->andReturn($mockGroup);
$dataRelation = Mockery::mock(HasMany::class);
$dataRelation->shouldReceive('where')->andReturn($mockQueryBuilder);
$dataRelation->shouldReceive('get')->andReturn(
new \Illuminate\Database\Eloquent\Collection([$mockGroup])
);
$mockTeam->method('groups')->willReturn($dataRelation);
$mockReport->method('getTeam')->willReturn($mockTeam);
// Create mock AutomatedReportResult
$mockReportResult = $this->createMock(AutomatedReportResult::class);
$mockReportResult->method('getUuid')->willReturn($uuid);
$mockReportResult->method('getGeneratedAt')->willReturn(
\Illuminate\Support\Carbon::parse('2024-01-15T10:30:00Z')
);
$mockReportResult->method('getReport')->willReturn($mockReport);
// Mock methods used in getReportFileName
$mockReportResult->method('getReportType')->willReturn($reportType);
$mockReportResult->method('getFromDate')->willReturn(
\Illuminate\Support\Carbon::parse('2024-01-08')
);
$mockReportResult->method('getToDate')->willReturn(
\Illuminate\Support\Carbon::parse('2024-01-15')
);
$mockReportResult->method('getGroups')->willReturn([10]);
$mockReportResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PODCAST);
return $mockReportResult;
}
#[DataProvider('getUsersUuidsDataProvider')]
public function testGetUsersUuids(array $recipients, array $mockUsers, array $expectedUuids): void
{
// Create mock UserRepository
$mockUserRepository = $this->createMock(UserRepository::class);
// Configure the mock to return specific users for specific IDs using a callback
$mockUserRepository->method('find')
->willReturnCallback(function ($userId) use ($mockUsers) {
if (! isset($mockUsers[$userId])) {
return null;
}
$userUuid = $mockUsers[$userId]['uuid'] ?? null;
if ($userUuid === null) {
return null;
}
$mockUser = $this->createMock(\Jiminny\Models\User::class);
$mockUser->method('getUuid')->willReturn((string) $userUuid);
return $mockUser;
});
// Create service with mocked UserRepository
$automatedReportsService = $this->getService(mockUserRepository: $mockUserRepository);
// Create mock AutomatedReport
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getRecipients')->willReturn($recipients);
$result = $automatedReportsService->getUsersUuids($mockReport);
$this->assertEquals($expectedUuids, $result);
}
public function testGetUsersUuidsWithEmptyRecipients(): void
{
// Create mock AutomatedReport with empty recipients
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getRecipients')->willReturn([]);
$result = $this->service->getUsersUuids($mockReport);
$this->assertEquals([], $result);
}
public function testGetUsersUuidsWithNoUsersKey(): void
{
// Create mock AutomatedReport with recipients but no 'users' key
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getRecipients')->willReturn(['other_key' => [1, 2, 3]]);
$result = $this->service->getUsersUuids($mockReport);
$this->assertEquals([], $result);
}
public function testGetUsersUuidsWithNonExistentUsers(): void
{
// Create mock UserRepository that returns null for all users
$mockUserRepository = $this->createMock(UserRepository::class);
$mockUserRepository->method('find')->willReturn(null);
// Create service with mocked UserRepository
$automatedReportsService = $this->getService(mockUserRepository: $mockUserRepository);
// Create mock AutomatedReport
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getRecipients')->willReturn(['users' => [1, 2, 3]]);
$result = $automatedReportsService->getUsersUuids($mockReport);
// Should return array with null values for non-existent users
$this->assertEquals([], $result);
}
public static function getUsersUuidsDataProvider(): array
{
return [
'single user found' => [
'recipients' => ['users' => [123]],
'mockUsers' => [
123 => ['id' => 123, 'uuid' => 'user-uuid-123'],
],
'expectedUuids' => ['user-uuid-123'],
],
'multiple users found' => [
'recipients' => ['users' => [123, 456, 789]],
'mockUsers' => [
123 => ['id' => 123, 'uuid' => 'user-uuid-123'],
456 => ['id' => 456, 'uuid' => 'user-uuid-456'],
789 => ['id' => 789, 'uuid' => 'user-uuid-789'],
],
'expectedUuids' => ['user-uuid-123', 'user-uuid-456', 'user-uuid-789'],
],
'mixed found and not found users' => [
'recipients' => ['users' => [123, 456, 789]],
'mockUsers' => [
123 => ['id' => 123, 'uuid' => 'user-uuid-123'],
// 456 not found in DB
789 => ['id' => 789, 'uuid' => 'user-uuid-789'],
],
'expectedUuids' => ['user-uuid-123', 'user-uuid-789'], // Updated to reflect that nulls are filtered out
],
'empty users array' => [
'recipients' => ['users' => []],
'mockUsers' => [],
'expectedUuids' => [],
],
'all users not found' => [
'recipients' => ['users' => [123, 456]],
'mockUsers' => [], // No users found
'expectedUuids' => [], // Updated to reflect that nulls are filtered out
],
];
}
#[DataProvider('getCurrentDealStagesUuidsDataProvider')]
public function testGetCurrentDealStagesUuids(array $currentDealStages, array $mockStages, array $expectedUuids): void
{
// Create mock StageRepository
$mockStageRepository = $this->createMock(StageRepository::class);
// Configure the mock to return specific stages for specific IDs using a callback
$mockStageRepository->method('find')
->willReturnCallback(function ($stageId) use ($mockStages) {
if (! isset($mockStages[$stageId])) {
return null;
}
$stageUuid = $mockStages[$stageId]['uuid'] ?? null;
if ($stageUuid === null) {
return null;
}
$mockStage = $this->createMock(\Jiminny\Models\Stage::class);
$mockStage->method('getUuid')->willReturn((string) $stageUuid);
return $mockStage;
});
// Create service with mocked StageRepository
$automatedReportsService = $this->getService(mockStageRepository: $mockStageRepository);
// Create mock AutomatedReport
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getCurrentDealStages')->willReturn($currentDealStages);
$result = $automatedReportsService->getCurrentDealStagesUuids($mockReport);
$this->assertEquals($expectedUuids, $result);
}
public function testGetCurrentDealStagesUuidsWithEmptyStages(): void
{
// Create mock AutomatedReport with empty current deal stages
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getCurrentDealStages')->willReturn([]);
$result = $this->service->getCurrentDealStagesUuids($mockReport);
$this->assertEquals([], $result);
}
public function testGetCurrentDealStagesUuidsWithNonExistentStages(): void
{
// Create mock StageRepository that returns null for all stages
$mockStageRepository = $this->createMock(StageRepository::class);
$mockStageRepository->method('find')->willReturn(null);
// Create service with mocked StageRepository
$automatedReportsService = $this->getService(mockStageRepository: $mockStageRepository);
// Create mock AutomatedReport
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getCurrentDealStages')->willReturn([1, 2, 3]);
$result = $automatedReportsService->getCurrentDealStagesUuids($mockReport);
// Should return array with null values for non-existent stages
$this->assertEquals([], $result);
}
public static function getCurrentDealStagesUuidsDataProvider(): array
{
return [
'single stage found' => [
'currentDealStages' => [10],
'mockStages' => [
10 => ['id' => 10, 'uuid' => 'stage-uuid-10'],
],
'expectedUuids' => ['stage-uuid-10'],
],
'multiple stages found' => [
'currentDealStages' => [10, 20, 30],
'mockStages' => [
10 => ['id' => 10, 'uuid' => 'stage-uuid-10'],
20 => ['id' => 20, 'uuid' => 'stage-uuid-20'],
30 => ['id' => 30, 'uuid' => 'stage-uuid-30'],
],
'expectedUuids' => ['stage-uuid-10', 'stage-uuid-20', 'stage-uuid-30'],
],
'mixed found and not found stages' => [
'currentDealStages' => [10, 20, 30],
'mockStages' => [
10 => ['id' => 10, 'uuid' => 'stage-uuid-10'],
// 20 not found in DB
30 => ['id' => 30, 'uuid' => 'stage-uuid-30'],
],
'expectedUuids' => ['stage-uuid-10', 'stage-uuid-30'], // Updated to reflect that nulls are filtered out
],
'empty stages array' => [
'currentDealStages' => [],
'mockStages' => [],
'expectedUuids' => [],
],
'all stages not found' => [
'currentDealStages' => [10, 20],
'mockStages' => [], // No stages found
'expectedUuids' => [], // Updated to reflect that nulls are filtered out
],
];
}
#[DataProvider('getTeamGroupsDataProvider')]
public function testGetTeamGroups(string $teamUuid, ?array $mockTeamData, array $mockGroups, array $expectedResult): void
{
// Create mock TeamRepository
$mockTeamRepository = $this->createMock(TeamRepository::class);
if ($mockTeamData === null) {
// Team not found
$mockTeamRepository->method('idOrUuid')
->with($teamUuid)
->willReturn(null);
} else {
// Team found - create mock team with groups
$mockTeam = $this->createMock(\Jiminny\Models\Team::class);
// Create mock groups collection
$mockGroupsCollection = $this->createMock(\Illuminate\Database\Eloquent\Collection::class);
// Create mock Group objects
$groupObjects = [];
foreach ($mockGroups as $groupData) {
$mockGroup = $this->createMock(\Jiminny\Models\Group::class);
$mockGroup->method('getUuid')->willReturn($groupData['id']);
$mockGroup->method('getName')->willReturn($groupData['name']);
$groupObjects[] = $mockGroup;
}
// Mock the groups collection to return our mock groups
$mockGroupsCollection->method('getIterator')->willReturn(new \ArrayIterator($groupObjects));
// Mock the groups() relation
$mockGroupsRelation = $this->createMock(\Illuminate\Database\Eloquent\Relations\HasMany::class);
$mockGroupsRelation->method('get')->willReturn($mockGroupsCollection);
$mockTeam->method('groups')->willReturn($mockGroupsRelation);
$mockTeamRepository->method('idOrUuid')
->with($teamUuid)
->willReturn($mockTeam);
}
// Create service with mocked TeamRepository
$automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);
$result = $automatedReportsService->getTeamGroups($teamUuid);
$this->assertEquals($expectedResult, $result);
}
public function testGetTeamGroupsWithNonExistentTeam(): void
{
// Create mock TeamRepository that returns null (team not found)
$mockTeamRepository = $this->createMock(TeamRepository::class);
$mockTeamRepository->method('idOrUuid')->willReturn(null);
// Create service with mocked TeamRepository
$automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);
$result = $automatedReportsService->getTeamGroups('non-existent-team-uuid');
$this->assertEquals([], $result);
}
public function testGetTeamGroupsWithEmptyGroups(): void
{
// Create mock team with no groups
$mockTeam = $this->createMock(\Jiminny\Models\Team::class);
// Create empty groups collection
$mockGroupsCollection = $this->createMock(\Illuminate\Database\Eloquent\Collection::class);
$mockGroupsCollection->method('getIterator')->willReturn(new \ArrayIterator([]));
$mockGroupsRelation = $this->createMock(\Illuminate\Database\Eloquent\Relations\HasMany::class);
$mockGroupsRelation->method('get')->willReturn($mockGroupsCollection);
$mockTeam->method('groups')->willReturn($mockGroupsRelation);
// Create mock TeamRepository
$mockTeamRepository = $this->createMock(TeamRepository::class);
$mockTeamRepository->method('idOrUuid')->willReturn($mockTeam);
// Create service with mocked TeamRepository
$automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);
$result = $automatedReportsService->getTeamGroups('team-with-no-groups');
$this->assertEquals([], $result);
}
public static function getTeamGroupsDataProvider(): array
{
return [
'team with single group' => [
'teamUuid' => 'team-uuid-123',
'mockTeamData' => ['id' => 'team-uuid-123', 'name' => 'Test Team'],
'mockGroups' => [
['id' => 'group-uuid-1', 'name' => 'Sales Team'],
],
'expectedResult' => [
['id' => 'group-uuid-1', 'name' => 'Sales Team'],
],
],
'team with multiple groups' => [
'teamUuid' => 'team-uuid-456',
'mockTeamData' => ['id' => 'team-uuid-456', 'name' => 'Another Team'],
'mockGroups' => [
['id' => 'group-uuid-1', 'name' => 'Sales Team'],
['id' => 'group-uuid-2', 'name' => 'Marketing Team'],
['id' => 'group-uuid-3', 'name' => 'Support Team'],
],
'expectedResult' => [
['id' => 'group-uuid-1', 'name' => 'Sales Team'],
['id' => 'group-uuid-2', 'name' => 'Marketing Team'],
['id' => 'group-uuid-3', 'name' => 'Support Team'],
],
],
'team not found' => [
'teamUuid' => 'non-existent-uuid',
'mockTeamData' => null,
'mockGroups' => [],
'expectedResult' => [],
],
'team with no groups' => [
'teamUuid' => 'team-uuid-empty',
'mockTeamData' => ['id' => 'team-uuid-empty', 'name' => 'Empty Team'],
'mockGroups' => [],
'expectedResult' => [],
],
];
}
#[DataProvider('getTeamsDataProvider')]
public function testGetTeams(array $mockTeams, array $expectedResult): void
{
// Create mock TeamRepository
$mockTeamRepository = $this->createMock(TeamRepository::class);
// Create mock Team objects
$teamObjects = [];
foreach ($mockTeams as $teamData) {
$mockTeam = $this->createMock(\Jiminny\Models\Team::class);
$mockTeam->method('getUuid')->willReturn($teamData['id']);
$mockTeam->method('getName')->willReturn($teamData['name']);
$mockTeam->method('hasFeature')
->with(\Jiminny\Models\Feature\FeatureEnum::AUTOMATED_REPORTS)
->willReturn($teamData['hasAutomatedReports']);
$teamObjects[] = $mockTeam;
}
// Mock the repository to return a Collection (not array)
$mockTeamRepository->method('getTeamsForKiosk')
->with('active')
->willReturn(new Collection($teamObjects));
// Create service with mocked TeamRepository
$automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);
$result = $automatedReportsService->getTeams();
$this->assertEquals($expectedResult, $result);
}
public function testGetTeamsWithNoTeams(): void
{
// Create mock TeamRepository that returns empty Collection
$mockTeamRepository = $this->createMock(TeamRepository::class);
$mockTeamRepository->method('getTeamsForKiosk')->willReturn(new Collection([]));
// Create service with mocked TeamRepository
$automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);
$result = $automatedReportsService->getTeams();
$this->assertEquals([], $result);
}
public function testGetTeamsWithAllTeamsWithoutFeature(): void
{
// Create mock teams without AUTOMATED_REPORTS feature
$mockTeam1 = $this->createMock(\Jiminny\Models\Team::class);
$mockTeam1->method('hasFeature')
->with(\Jiminny\Models\Feature\FeatureEnum::AUTOMATED_REPORTS)
->willReturn(false);
$mockTeam2 = $this->createMock(\Jiminny\Models\Team::class);
$mockTeam2->method('hasFeature')
->with(\Jiminny\Models\Feature\FeatureEnum::AUTOMATED_REPORTS)
->willReturn(false);
// Create mock TeamRepository that returns Collection
$mockTeamRepository = $this->createMock(TeamRepository::class);
$mockTeamRepository->method('getTeamsForKiosk')->willReturn(new Collection([$mockTeam1, $mockTeam2]));
// Create service with mocked TeamRepository
$automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);
$result = $automatedReportsService->getTeams();
$this->assertEquals([], $result);
}
public function testGetTeamsForwardsPartnerToRepository(): void
{
$partner = $this->createMock(Partner::class);
$mockTeamRepository = $this->createMock(TeamRepository::class);
$mockTeamRepository->expects(self::once())
->method('getTeamsForKiosk')
->with(Team::STATUS_ACTIVE, $partner)
->willReturn(new Collection([]));
$service = $this->getService(mockTeamRepository: $mockTeamRepository);
$service->getTeams(partner: $partner);
}
public function testGetOrganizationFieldDataForwardsPartnerToRepository(): void
{
$partner = $this->createMock(Partner::class);
$mockTeamRepository = $this->createMock(TeamRepository::class);
$mockTeamRepository->expects(self::once())
->method('getTeamsForKiosk')
->with(Team::STATUS_ACTIVE, $partner)
->willReturn(new Collection([]));
$service = $this->getService(mockTeamRepository: $mockTeamRepository);
$service->getOrganizationFieldData(partner: $partner);
}
public function testGetTeamsGroupsOptionsForwardsPartnerToRepository(): void
{
$partner = $this->createMock(Partner::class);
$mockTeamRepository = $this->createMock(TeamRepository::class);
$mockTeamRepository->expects(self::once())
->method('getTeamsForKiosk')
->with(Team::STATUS_ACTIVE, $partner)
->willReturn(new Collection([]));
$service = $this->getService(mockTeamRepository: $mockTeamRepository);
$service->getTeamsGroupsOptions(partner: $partner);
}
public static function getTeamsDataProvider(): array
{
return [
'single team with feature' => [
'mockTeams' => [
[
'id' => 'team-uuid-1',
'name' => 'Sales Team',
'hasAutomatedReports' => true,
],
],
'expectedResult' => [
['id' => 'team-uuid-1', 'name' => 'Sales Team'],
],
],
'multiple teams with feature' => [
'mockTeams' => [
[
'id' => 'team-uuid-1',
'name' => 'Sales Team',
'hasAutomatedReports' => true,
],
[
'id' => 'team-uuid-2',
'name' => 'Marketing Team',
'hasAutomatedReports' => true,
],
[
'id' => 'team-uuid-3',
'name' => 'Support Team',
'hasAutomatedReports' => true,
],
],
'expectedResult' => [
['id' => 'team-uuid-1', 'name' => 'Sales Team'],
['id' => 'team-uuid-2', 'name' => 'Marketing Team'],
['id' => 'team-uuid-3', 'name' => 'Support Team'],
],
],
'mixed teams - some with feature, some without' => [
'mockTeams' => [
[
'id' => 'team-uuid-1',
'name' => 'Sales Team',
'hasAutomatedReports' => true,
],
[
'id' => 'team-uuid-2',
'name' => 'Marketing Team',
'hasAutomatedReports' => false,
],
[
'id' => 'team-uuid-3',
'name' => 'Support Team',
'hasAutomatedReports' => true,
],
],
'expectedResult' => [
['id' => 'team-uuid-1', 'name' => 'Sales Team'],
['id' => 'team-uuid-3', 'name' => 'Support Team'],
],
],
'all teams without feature' => [
'mockTeams' => [
[
'id' => 'team-uuid-1',
'name' => 'Sales Team',
'hasAutomatedReports' => false,
],
[
'id' => 'team-uuid-2',
'name' => 'Marketing Team',
'hasAutomatedReports' => false,
],
],
'expectedResult' => [],
],
'empty teams array' => [
'mockTeams' => [],
'expectedResult' => [],
],
];
}
#[DataProvider('deleteS3FilesDataProvider')]
public function testDeleteS3Files(
string $mediaType,
array $expectedFileExtensions,
array $existingFiles,
string $pathSuffix,
int $expectedDeletes
): void {
// Arrange
$teamUuid = 'team-uuid-123';
$reportUuid = 'report-uuid-456';
$basePath = sprintf('%s/reports/%s', $teamUuid, $reportUuid);
$team = Mockery::mock(Team::class);
$team->allows('getUuid')->andReturn($teamUuid);
$report = Mockery::mock(AutomatedReport::class);
$report->allows('getTeam')->andReturn($team);
$result = Mockery::mock(AutomatedReportResult::class);
$result->allows('getReport')->andReturn($report);
$result->allows('getUuid')->andReturn($reportUuid);
$result->allows('getMediaType')->andReturn($mediaType);
Storage::fake();
Log::shouldReceive('info')->times($expectedDeletes);
foreach ($existingFiles as $extension) {
$filePath = $basePath . $pathSuffix . '.' . $extension;
Storage::put($filePath, 'dummy content');
}
// Act
$this->service->deleteS3Files($result);
// Assert
foreach ($expectedFileExtensions as $extension) {
$filePath = $basePath . $pathSuffix . '.' . $extension;
if (in_array($extension, $existingFiles, true)) {
Storage::assertMissing($filePath);
} else {
// To be sure no unexpected files were created and deleted
Storage::assertMissing($filePath);
}
}
}
public static function deleteS3FilesDataProvider(): array
{
return [
'PDF report, all files exist' => [
'mediaType' => AutomatedReportsService::MEDIA_TYPE_PDF,
'expectedFileExtensions' => ['html', 'MD', 'pdf'],
'existingFiles' => ['html', 'MD', 'pdf'],
'pathSuffix' => '',
'expectedDeletes' => 3,
],
'PDF report, some files exist' => [
'mediaType' => AutomatedReportsService::MEDIA_TYPE_PDF,
'expectedFileExtensions' => ['html', 'MD', 'pdf'],
'existingFiles' => ['html', 'pdf'],
'pathSuffix' => '',
'expectedDeletes' => 2,
],
'PDF report, no files exist' => [
'mediaType' => AutomatedReportsService::MEDIA_TYPE_PDF,
'expectedFileExtensions' => ['html', 'MD', 'pdf'],
'existingFiles' => [],
'pathSuffix' => '',
'expectedDeletes' => 0,
],
'Podcast report, all files exist' => [
'mediaType' => AutomatedReportsService::MEDIA_TYPE_PODCAST,
'expectedFileExtensions' => ['json', 'mp3', 'ssml'],
'existingFiles' => ['json', 'mp3', 'ssml'],
'pathSuffix' => '_podcast',
'expectedDeletes' => 3,
],
'Podcast report, some files exist' => [
'mediaType' => AutomatedReportsService::MEDIA_TYPE_PODCAST,
'expectedFileExtensions' => ['json', 'mp3', 'ssml'],
'existingFiles' => ['mp3'],
'pathSuffix' => '_podcast',
'expectedDeletes' => 1,
],
'Podcast report, no files exist' => [
'mediaType' => AutomatedReportsService::MEDIA_TYPE_PODCAST,
'expectedFileExtensions' => ['json', 'mp3', 'ssml'],
'existingFiles' => [],
'pathSuffix' => '_podcast',
'expectedDeletes' => 0,
],
'Other media type, should do nothing' => [
'mediaType' => 'some_other_type',
'expectedFileExtensions' => [],
'existingFiles' => [],
'pathSuffix' => '',
'expectedDeletes' => 0,
],
];
}
public function testDeleteReportsResultsInRetentionPeriodWithLogging(): void
{
// Create mocks for the test
$automatedReportsService = Mockery::mock(AutomatedReportsService::class);
$team = Mockery::mock(Team::class);
$team->shouldReceive('getId')->andReturn(123);
$from = now()->subDays(30);
$to = now();
$source = 'test-source';
// Expect the method to be called with specific parameters
$automatedReportsService->shouldReceive('deleteReportsResultsInRetentionPeriodWithLogging')
->once()
->with(
$team,
Mockery::on(function ($arg) use ($from) {
return $arg->timestamp === $from->timestamp;
}),
Mockery::on(function ($arg) use ($to) {
return $arg->timestamp === $to->timestamp;
}),
$source
)
->andReturn(5);
// Call the method and verify the result
$result = $automatedReportsService->deleteReportsResultsInRetentionPeriodWithLogging(
$team,
$from,
$to,
$source
);
$this->assertEquals(5, $result);
}
#[DataProvider('sanitizeFileNameDataProvider')]
public function testSanitizeFileName(string $input, string $expected): void
{
$result = $this->service->sanitizeFileName($input);
$this->assertEquals($expected, $result);
}
public static function sanitizeFileNameDataProvider(): array
{
return [
'no special characters' => [
'input' => 'Exec Summary - Sep 2025 - Business Development Team',
'expected' => 'Exec Summary - Sep 2025 - Business Development Team',
],
'forward slash in team name' => [
'input' => 'Exec Summary - Sep 2025 - ND/IRV',
'expected' => 'Exec Summary - Sep 2025 - ND-IRV',
],
'backslash in team name' => [
'input' => 'Exec Summary - Sep 2025 - ND\IRV',
'expected' => 'Exec Summary - Sep 2025 - ND-IRV',
],
'multiple forward slashes' => [
'input' => 'Report - Team A/B/C',
'expected' => 'Report - Team A-B-C',
],
'multiple backslashes' => [
'input' => 'Report - Team A\B\C',
'expected...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskAnythingPromptServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskAnythingPromptServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskAnythingPromptServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"16","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"104","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"73","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"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\\Carbon;\nuse Illuminate\\Support\\Carbon as IlluminateCarbon;\nuse Illuminate\\Contracts\\Bus\\Dispatcher;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Illuminate\\Support\\Facades\\Log;\nuse Illuminate\\Support\\Facades\\Storage;\nuse Jiminny\\Component\\AskAnything\\AskAnythingPromptService;\nuse Jiminny\\Component\\AskAnything\\Dtos\\AskAnythingPromptDto;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Contracts\\Repositories\\PlaybookCategoryRepository;\nuse Jiminny\\Contracts\\Repositories\\TeamRepository;\nuse Jiminny\\Contracts\\Repositories\\UserRepository;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Exceptions\\ModelNotFoundException;\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPrompt;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPromptTarget;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Group;\nuse Jiminny\\Models\\Partner;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AskAnythingRepository;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Repositories\\GroupRepository;\nuse Jiminny\\Repositories\\SearchRepository;\nuse Jiminny\\Repositories\\StageRepository;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ActivityTypeService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\DealStagesService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\RecipientsService;\nuse Mockery;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse Tests\\TestCase;\n\nclass AutomatedReportsServiceTest extends TestCase\n{\n private AutomatedReportsService $service;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n // Create a real instance of the service without calling the constructor\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $this->service = $reflection->newInstanceWithoutConstructor();\n\n // Manually set the dependencies using reflection\n $dependencies = [\n 'teamRepository' => TeamRepository::class,\n 'groupRepository' => GroupRepository::class,\n 'userRepository' => UserRepository::class,\n 'stageRepository' => StageRepository::class,\n 'dealStagesService' => DealStagesService::class,\n 'recipientsService' => RecipientsService::class,\n 'automatedReportsRepository' => AutomatedReportsRepository::class,\n 'webhookService' => Webhook::class,\n 'dispatcher' => Dispatcher::class,\n 'activityTypeService' => ActivityTypeService::class,\n 'playbookCategoryRepository' => PlaybookCategoryRepository::class,\n 'askAnythingPromptService' => AskAnythingPromptService::class,\n 'activitySearchRepository' => SearchRepository::class,\n 'askAnythingRepository' => AskAnythingRepository::class,\n ];\n\n foreach ($dependencies as $propertyName => $class) {\n $property = $reflection->getProperty($propertyName);\n $property->setAccessible(true);\n $property->setValue($this->service, $this->createMock($class));\n }\n }\n\n protected function tearDown(): void\n {\n parent::tearDown();\n Mockery::close();\n }\n\n private function getService(\n $mockUserRepository = null,\n $mockStageRepository = null,\n $mockTeamRepository = null,\n ): AutomatedReportsService {\n return new AutomatedReportsService(\n ($mockTeamRepository ?? $this->createMock(TeamRepository::class)),\n $this->createMock(GroupRepository::class),\n ($mockUserRepository ?? $this->createMock(UserRepository::class)),\n ($mockStageRepository ?? $this->createMock(StageRepository::class)),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n }\n\n #[DataProvider('transformMediaTypesDataProvider')]\n public function testTransformMediaTypes(array $mediaTypes, array $expected): void\n {\n $report = new AutomatedReport(['media_types' => $mediaTypes]);\n\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $method = $reflection->getMethod('transformMediaTypes');\n\n $result = $method->invoke($this->service, $report);\n\n $this->assertEquals($expected, $result);\n }\n\n public function testGetMediaTypeFieldDataWithoutReport(): void\n {\n $result = $this->service->getMediaTypeFieldData(null);\n\n $this->assertIsArray($result);\n $this->assertArrayHasKey('value', $result);\n $this->assertEmpty($result['value']);\n $this->assertEquals('media_types', $result['id']);\n }\n\n public function testGetMediaTypeFieldDataWithReport(): void\n {\n $mediaTypes = ['pdf', 'podcast'];\n $report = new AutomatedReport(['media_types' => $mediaTypes]);\n\n $result = $this->service->getMediaTypeFieldData($report);\n\n $expectedValue = [\n ['id' => 'pdf', 'name' => 'PDF'],\n ['id' => 'podcast', 'name' => 'Podcast'],\n ];\n\n $this->assertIsArray($result);\n $this->assertArrayHasKey('value', $result);\n $this->assertEquals($expectedValue, $result['value']);\n }\n\n public static function transformMediaTypesDataProvider(): array\n {\n return [\n 'empty array' => [\n 'mediaTypes' => [],\n 'expected' => [],\n ],\n 'pdf only' => [\n 'mediaTypes' => ['pdf'],\n 'expected' => [\n ['id' => 'pdf', 'name' => 'PDF'],\n ],\n ],\n 'podcast only' => [\n 'mediaTypes' => ['podcast'],\n 'expected' => [\n ['id' => 'podcast', 'name' => 'Podcast'],\n ],\n ],\n 'both pdf and podcast' => [\n 'mediaTypes' => ['pdf', 'podcast'],\n 'expected' => [\n ['id' => 'pdf', 'name' => 'PDF'],\n ['id' => 'podcast', 'name' => 'Podcast'],\n ],\n ],\n 'with invalid type' => [\n 'mediaTypes' => ['pdf', 'invalid', 'podcast'],\n 'expected' => [\n ['id' => 'pdf', 'name' => 'PDF'],\n ['id' => 'podcast', 'name' => 'Podcast'],\n ],\n ],\n ];\n }\n\n #[DataProvider('hasCallTypeConferenceDataProvider')]\n public function testHasCallTypeConference(array $callTypes, bool $expected): void\n {\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getCallTypes')->willReturn($callTypes);\n\n $result = $this->service->hasCallTypeConference($report);\n\n $this->assertEquals($expected, $result);\n }\n\n #[DataProvider('hasCallTypeDialerDataProvider')]\n public function testHasCallTypeDialer(array $callTypes, bool $expected): void\n {\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getCallTypes')->willReturn($callTypes);\n\n $result = $this->service->hasCallTypeDialer($report);\n\n $this->assertEquals($expected, $result);\n }\n\n public static function hasCallTypeConferenceDataProvider(): array\n {\n return [\n 'has conference' => [\n 'callTypes' => ['conference', 'dialer'],\n 'expected' => true,\n ],\n 'does not have conference' => [\n 'callTypes' => ['dialer', 'other'],\n 'expected' => false,\n ],\n 'empty call types' => [\n 'callTypes' => [],\n 'expected' => false,\n ],\n ];\n }\n\n public static function hasCallTypeDialerDataProvider(): array\n {\n return [\n 'has dialer' => [\n 'callTypes' => ['conference', 'dialer'],\n 'expected' => true,\n ],\n 'does not have dialer' => [\n 'callTypes' => ['conference', 'other'],\n 'expected' => false,\n ],\n 'empty call types' => [\n 'callTypes' => [],\n 'expected' => false,\n ],\n ];\n }\n\n public function testTransformReportResultsWithEmptyCollection(): void\n {\n $emptyCollection = new Collection([]);\n\n $result = $this->service->transformReportResults($emptyCollection);\n\n $this->assertIsArray($result);\n $this->assertEmpty($result);\n }\n\n public function testTransformReportResultsStructure(): void\n {\n // Create a mock AutomatedReportResult with minimal setup to test structure\n $mockReportResult = $this->createMockReportResult();\n $collection = new Collection([$mockReportResult]);\n\n $result = $this->service->transformReportResults($collection);\n\n $this->assertIsArray($result);\n $this->assertCount(1, $result);\n\n $transformedResult = $result[0];\n\n // Verify all expected keys are present\n $expectedKeys = [\n 'id', 'name', 'frequency', 'recipients',\n 'report_type', 'media_type', 'downloadUrl', 'viewUrl', 'generated_at',\n ];\n\n foreach ($expectedKeys as $key) {\n $this->assertArrayHasKey($key, $transformedResult);\n }\n\n // Verify structure of nested arrays\n $this->assertIsArray($transformedResult['frequency']);\n $this->assertArrayHasKey('id', $transformedResult['frequency']);\n $this->assertArrayHasKey('name', $transformedResult['frequency']);\n\n $this->assertIsArray($transformedResult['report_type']);\n $this->assertArrayHasKey('id', $transformedResult['report_type']);\n $this->assertArrayHasKey('name', $transformedResult['report_type']);\n\n $this->assertIsArray($transformedResult['recipients']);\n\n // Verify TODO fields are null as expected\n $this->assertEquals(AutomatedReportsService::MEDIA_TYPE_PODCAST, $transformedResult['media_type']);\n $this->assertEquals(route('ai-reports.audio.download', ['uuid' => 'test-uuid']), $transformedResult['downloadUrl']);\n $this->assertEquals(route('ai-reports.audio.view', ['uuid' => 'test-uuid']), $transformedResult['viewUrl']);\n }\n\n public function testTransformReportResultsWithMultipleResults(): void\n {\n $mockReportResult1 = $this->createMockReportResult('result-uuid-1', 'exec_summary');\n $mockReportResult2 = $this->createMockReportResult('result-uuid-2', 'coaching_profiles');\n $collection = new Collection([$mockReportResult1, $mockReportResult2]);\n\n $result = $this->service->transformReportResults($collection);\n\n $this->assertIsArray($result);\n $this->assertCount(2, $result);\n\n // Verify different UUIDs\n $this->assertEquals('result-uuid-1', $result[0]['id']);\n $this->assertEquals('result-uuid-2', $result[1]['id']);\n\n // Verify both results have the expected structure\n foreach ($result as $transformedResult) {\n $this->assertArrayHasKey('id', $transformedResult);\n $this->assertArrayHasKey('name', $transformedResult);\n $this->assertArrayHasKey('frequency', $transformedResult);\n $this->assertArrayHasKey('recipients', $transformedResult);\n $this->assertArrayHasKey('report_type', $transformedResult);\n }\n }\n\n #[DataProvider('isUserRecipientOfReportDataProvider')]\n public function testIsUserRecipientOfReport(int $userId, array $recipients, bool $expected): void\n {\n // Create mock User\n $mockUser = $this->createMock(\\Jiminny\\Models\\User::class);\n $mockUser->method('getId')->willReturn($userId);\n $mockUser->method('getGroupId')->willReturn(null);\n\n // Create mock AutomatedReport\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getRecipients')->willReturn($recipients);\n $mockReport->method('isAskJiminnyReport')->willReturn(false);\n $mockReport->method('getGroups')->willReturn([]);\n\n $result = $this->service->isUserRecipientOfReport($mockUser, $mockReport);\n\n $this->assertEquals($expected, $result);\n }\n\n #[DataProvider('isUserRecipientOfAskJiminnyReportDataProvider')]\n public function testIsUserRecipientOfAskJiminnyReportViaGroup(\n int $userId,\n ?int $groupId,\n array $recipients,\n array $reportGroups,\n bool $expected,\n ): void {\n $mockUser = $this->createMock(\\Jiminny\\Models\\User::class);\n $mockUser->method('getId')->willReturn($userId);\n $mockUser->method('getGroupId')->willReturn($groupId);\n\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getRecipients')->willReturn($recipients);\n $mockReport->method('isAskJiminnyReport')->willReturn(true);\n $mockReport->method('getGroups')->willReturn($reportGroups);\n\n $this->assertSame($expected, $this->service->isUserRecipientOfReport($mockUser, $mockReport));\n }\n\n public function testIsUserRecipientOfNonAskJiminnyReportIgnoresGroups(): void\n {\n $mockUser = $this->createMock(\\Jiminny\\Models\\User::class);\n $mockUser->method('getId')->willReturn(123);\n $mockUser->method('getGroupId')->willReturn(5);\n\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getRecipients')->willReturn(['users' => []]);\n $mockReport->method('isAskJiminnyReport')->willReturn(false);\n $mockReport->method('getGroups')->willReturn([5]);\n\n $this->assertFalse($this->service->isUserRecipientOfReport($mockUser, $mockReport));\n }\n\n public static function isUserRecipientOfAskJiminnyReportDataProvider(): array\n {\n return [\n 'group member - ask jiminny' => [\n 'userId' => 123,\n 'groupId' => 7,\n 'recipients' => ['users' => []],\n 'reportGroups' => [7],\n 'expected' => true,\n ],\n 'group mismatch - ask jiminny' => [\n 'userId' => 123,\n 'groupId' => 9,\n 'recipients' => ['users' => []],\n 'reportGroups' => [7, 8],\n 'expected' => false,\n ],\n 'user with no group - ask jiminny' => [\n 'userId' => 123,\n 'groupId' => null,\n 'recipients' => ['users' => []],\n 'reportGroups' => [7],\n 'expected' => false,\n ],\n 'recipient users take precedence over group' => [\n 'userId' => 123,\n 'groupId' => null,\n 'recipients' => ['users' => [123]],\n 'reportGroups' => [],\n 'expected' => true,\n ],\n ];\n }\n\n public function testIsUserRecipientOfReportWithEmptyRecipients(): void\n {\n // Create mock User\n $mockUser = $this->createMock(\\Jiminny\\Models\\User::class);\n $mockUser->method('getId')->willReturn(123);\n\n // Create mock AutomatedReport with no recipients\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getRecipients')->willReturn([]);\n\n $result = $this->service->isUserRecipientOfReport($mockUser, $mockReport);\n\n $this->assertFalse($result);\n }\n\n public function testIsUserRecipientOfReportWithNoUsersKey(): void\n {\n // Create mock User\n $mockUser = $this->createMock(\\Jiminny\\Models\\User::class);\n $mockUser->method('getId')->willReturn(123);\n\n // Create mock AutomatedReport with recipients but no 'users' key\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getRecipients')->willReturn(['other_key' => [456, 789]]);\n\n $result = $this->service->isUserRecipientOfReport($mockUser, $mockReport);\n\n $this->assertFalse($result);\n }\n\n public static function isUserRecipientOfReportDataProvider(): array\n {\n return [\n 'user is recipient - single user' => [\n 'userId' => 123,\n 'recipients' => ['users' => [123]],\n 'expected' => true,\n ],\n 'user is recipient - multiple users' => [\n 'userId' => 456,\n 'recipients' => ['users' => [123, 456, 789]],\n 'expected' => true,\n ],\n 'user is not recipient - single user' => [\n 'userId' => 999,\n 'recipients' => ['users' => [123]],\n 'expected' => false,\n ],\n 'user is not recipient - multiple users' => [\n 'userId' => 999,\n 'recipients' => ['users' => [123, 456, 789]],\n 'expected' => false,\n ],\n 'user is recipient - string IDs converted to int' => [\n 'userId' => 123,\n 'recipients' => ['users' => ['123', '456']],\n 'expected' => true,\n ],\n 'user is not recipient - string IDs converted to int' => [\n 'userId' => 999,\n 'recipients' => ['users' => ['123', '456']],\n 'expected' => false,\n ],\n 'empty users array' => [\n 'userId' => 123,\n 'recipients' => ['users' => []],\n 'expected' => false,\n ],\n ];\n }\n\n private function createMockReportResult(string $uuid = 'test-uuid', string $reportType = 'exec_summary'): AutomatedReportResult\n {\n // Create mock AutomatedReport\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getFrequency')->willReturn('weekly');\n $mockReport->method('getRecipients')->willReturn(['users' => [1, 2]]);\n $mockReport->method('getGroups')->willReturn([10, 20]);\n $mockReport->method('getType')->willReturn($reportType);\n\n // Create mock Team\n $mockTeam = $this->createMock(\\Jiminny\\Models\\Team::class);\n\n // Create mock Group\n $mockGroup = $this->createMock(\\Jiminny\\Models\\Group::class);\n $mockGroup->method('getUuid')->willReturn('group-uuid-10');\n $mockGroup->method('getName')->willReturn('Test Team');\n\n $mockQueryBuilder = Mockery::mock();\n $mockQueryBuilder->shouldReceive('where')->andReturnSelf();\n $mockQueryBuilder->shouldReceive('first')->andReturn($mockGroup);\n\n $dataRelation = Mockery::mock(HasMany::class);\n $dataRelation->shouldReceive('where')->andReturn($mockQueryBuilder);\n $dataRelation->shouldReceive('get')->andReturn(\n new \\Illuminate\\Database\\Eloquent\\Collection([$mockGroup])\n );\n\n $mockTeam->method('groups')->willReturn($dataRelation);\n $mockReport->method('getTeam')->willReturn($mockTeam);\n\n // Create mock AutomatedReportResult\n $mockReportResult = $this->createMock(AutomatedReportResult::class);\n $mockReportResult->method('getUuid')->willReturn($uuid);\n $mockReportResult->method('getGeneratedAt')->willReturn(\n \\Illuminate\\Support\\Carbon::parse('2024-01-15T10:30:00Z')\n );\n\n $mockReportResult->method('getReport')->willReturn($mockReport);\n\n // Mock methods used in getReportFileName\n $mockReportResult->method('getReportType')->willReturn($reportType);\n $mockReportResult->method('getFromDate')->willReturn(\n \\Illuminate\\Support\\Carbon::parse('2024-01-08')\n );\n $mockReportResult->method('getToDate')->willReturn(\n \\Illuminate\\Support\\Carbon::parse('2024-01-15')\n );\n $mockReportResult->method('getGroups')->willReturn([10]);\n $mockReportResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PODCAST);\n\n return $mockReportResult;\n }\n\n #[DataProvider('getUsersUuidsDataProvider')]\n public function testGetUsersUuids(array $recipients, array $mockUsers, array $expectedUuids): void\n {\n // Create mock UserRepository\n $mockUserRepository = $this->createMock(UserRepository::class);\n\n // Configure the mock to return specific users for specific IDs using a callback\n $mockUserRepository->method('find')\n ->willReturnCallback(function ($userId) use ($mockUsers) {\n if (! isset($mockUsers[$userId])) {\n return null;\n }\n\n $userUuid = $mockUsers[$userId]['uuid'] ?? null;\n\n if ($userUuid === null) {\n return null;\n }\n\n $mockUser = $this->createMock(\\Jiminny\\Models\\User::class);\n $mockUser->method('getUuid')->willReturn((string) $userUuid);\n\n return $mockUser;\n });\n\n // Create service with mocked UserRepository\n $automatedReportsService = $this->getService(mockUserRepository: $mockUserRepository);\n\n // Create mock AutomatedReport\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getRecipients')->willReturn($recipients);\n\n $result = $automatedReportsService->getUsersUuids($mockReport);\n\n $this->assertEquals($expectedUuids, $result);\n }\n\n public function testGetUsersUuidsWithEmptyRecipients(): void\n {\n // Create mock AutomatedReport with empty recipients\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getRecipients')->willReturn([]);\n\n $result = $this->service->getUsersUuids($mockReport);\n\n $this->assertEquals([], $result);\n }\n\n public function testGetUsersUuidsWithNoUsersKey(): void\n {\n // Create mock AutomatedReport with recipients but no 'users' key\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getRecipients')->willReturn(['other_key' => [1, 2, 3]]);\n\n $result = $this->service->getUsersUuids($mockReport);\n\n $this->assertEquals([], $result);\n }\n\n public function testGetUsersUuidsWithNonExistentUsers(): void\n {\n // Create mock UserRepository that returns null for all users\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturn(null);\n\n // Create service with mocked UserRepository\n $automatedReportsService = $this->getService(mockUserRepository: $mockUserRepository);\n\n // Create mock AutomatedReport\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getRecipients')->willReturn(['users' => [1, 2, 3]]);\n\n $result = $automatedReportsService->getUsersUuids($mockReport);\n\n // Should return array with null values for non-existent users\n $this->assertEquals([], $result);\n }\n\n public static function getUsersUuidsDataProvider(): array\n {\n return [\n 'single user found' => [\n 'recipients' => ['users' => [123]],\n 'mockUsers' => [\n 123 => ['id' => 123, 'uuid' => 'user-uuid-123'],\n ],\n 'expectedUuids' => ['user-uuid-123'],\n ],\n 'multiple users found' => [\n 'recipients' => ['users' => [123, 456, 789]],\n 'mockUsers' => [\n 123 => ['id' => 123, 'uuid' => 'user-uuid-123'],\n 456 => ['id' => 456, 'uuid' => 'user-uuid-456'],\n 789 => ['id' => 789, 'uuid' => 'user-uuid-789'],\n ],\n 'expectedUuids' => ['user-uuid-123', 'user-uuid-456', 'user-uuid-789'],\n ],\n 'mixed found and not found users' => [\n 'recipients' => ['users' => [123, 456, 789]],\n 'mockUsers' => [\n 123 => ['id' => 123, 'uuid' => 'user-uuid-123'],\n // 456 not found in DB\n 789 => ['id' => 789, 'uuid' => 'user-uuid-789'],\n ],\n 'expectedUuids' => ['user-uuid-123', 'user-uuid-789'], // Updated to reflect that nulls are filtered out\n ],\n 'empty users array' => [\n 'recipients' => ['users' => []],\n 'mockUsers' => [],\n 'expectedUuids' => [],\n ],\n 'all users not found' => [\n 'recipients' => ['users' => [123, 456]],\n 'mockUsers' => [], // No users found\n 'expectedUuids' => [], // Updated to reflect that nulls are filtered out\n ],\n ];\n }\n\n #[DataProvider('getCurrentDealStagesUuidsDataProvider')]\n public function testGetCurrentDealStagesUuids(array $currentDealStages, array $mockStages, array $expectedUuids): void\n {\n // Create mock StageRepository\n $mockStageRepository = $this->createMock(StageRepository::class);\n\n // Configure the mock to return specific stages for specific IDs using a callback\n $mockStageRepository->method('find')\n ->willReturnCallback(function ($stageId) use ($mockStages) {\n if (! isset($mockStages[$stageId])) {\n return null;\n }\n\n $stageUuid = $mockStages[$stageId]['uuid'] ?? null;\n\n if ($stageUuid === null) {\n return null;\n }\n\n $mockStage = $this->createMock(\\Jiminny\\Models\\Stage::class);\n $mockStage->method('getUuid')->willReturn((string) $stageUuid);\n\n return $mockStage;\n });\n\n // Create service with mocked StageRepository\n $automatedReportsService = $this->getService(mockStageRepository: $mockStageRepository);\n\n // Create mock AutomatedReport\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getCurrentDealStages')->willReturn($currentDealStages);\n\n $result = $automatedReportsService->getCurrentDealStagesUuids($mockReport);\n\n $this->assertEquals($expectedUuids, $result);\n }\n\n public function testGetCurrentDealStagesUuidsWithEmptyStages(): void\n {\n // Create mock AutomatedReport with empty current deal stages\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getCurrentDealStages')->willReturn([]);\n\n $result = $this->service->getCurrentDealStagesUuids($mockReport);\n\n $this->assertEquals([], $result);\n }\n\n public function testGetCurrentDealStagesUuidsWithNonExistentStages(): void\n {\n // Create mock StageRepository that returns null for all stages\n $mockStageRepository = $this->createMock(StageRepository::class);\n $mockStageRepository->method('find')->willReturn(null);\n\n // Create service with mocked StageRepository\n $automatedReportsService = $this->getService(mockStageRepository: $mockStageRepository);\n\n // Create mock AutomatedReport\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getCurrentDealStages')->willReturn([1, 2, 3]);\n\n $result = $automatedReportsService->getCurrentDealStagesUuids($mockReport);\n\n // Should return array with null values for non-existent stages\n $this->assertEquals([], $result);\n }\n\n public static function getCurrentDealStagesUuidsDataProvider(): array\n {\n return [\n 'single stage found' => [\n 'currentDealStages' => [10],\n 'mockStages' => [\n 10 => ['id' => 10, 'uuid' => 'stage-uuid-10'],\n ],\n 'expectedUuids' => ['stage-uuid-10'],\n ],\n 'multiple stages found' => [\n 'currentDealStages' => [10, 20, 30],\n 'mockStages' => [\n 10 => ['id' => 10, 'uuid' => 'stage-uuid-10'],\n 20 => ['id' => 20, 'uuid' => 'stage-uuid-20'],\n 30 => ['id' => 30, 'uuid' => 'stage-uuid-30'],\n ],\n 'expectedUuids' => ['stage-uuid-10', 'stage-uuid-20', 'stage-uuid-30'],\n ],\n 'mixed found and not found stages' => [\n 'currentDealStages' => [10, 20, 30],\n 'mockStages' => [\n 10 => ['id' => 10, 'uuid' => 'stage-uuid-10'],\n // 20 not found in DB\n 30 => ['id' => 30, 'uuid' => 'stage-uuid-30'],\n ],\n 'expectedUuids' => ['stage-uuid-10', 'stage-uuid-30'], // Updated to reflect that nulls are filtered out\n ],\n 'empty stages array' => [\n 'currentDealStages' => [],\n 'mockStages' => [],\n 'expectedUuids' => [],\n ],\n 'all stages not found' => [\n 'currentDealStages' => [10, 20],\n 'mockStages' => [], // No stages found\n 'expectedUuids' => [], // Updated to reflect that nulls are filtered out\n ],\n ];\n }\n\n #[DataProvider('getTeamGroupsDataProvider')]\n public function testGetTeamGroups(string $teamUuid, ?array $mockTeamData, array $mockGroups, array $expectedResult): void\n {\n // Create mock TeamRepository\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n\n if ($mockTeamData === null) {\n // Team not found\n $mockTeamRepository->method('idOrUuid')\n ->with($teamUuid)\n ->willReturn(null);\n } else {\n // Team found - create mock team with groups\n $mockTeam = $this->createMock(\\Jiminny\\Models\\Team::class);\n\n // Create mock groups collection\n $mockGroupsCollection = $this->createMock(\\Illuminate\\Database\\Eloquent\\Collection::class);\n\n // Create mock Group objects\n $groupObjects = [];\n foreach ($mockGroups as $groupData) {\n $mockGroup = $this->createMock(\\Jiminny\\Models\\Group::class);\n $mockGroup->method('getUuid')->willReturn($groupData['id']);\n $mockGroup->method('getName')->willReturn($groupData['name']);\n $groupObjects[] = $mockGroup;\n }\n\n // Mock the groups collection to return our mock groups\n $mockGroupsCollection->method('getIterator')->willReturn(new \\ArrayIterator($groupObjects));\n\n // Mock the groups() relation\n $mockGroupsRelation = $this->createMock(\\Illuminate\\Database\\Eloquent\\Relations\\HasMany::class);\n $mockGroupsRelation->method('get')->willReturn($mockGroupsCollection);\n $mockTeam->method('groups')->willReturn($mockGroupsRelation);\n\n $mockTeamRepository->method('idOrUuid')\n ->with($teamUuid)\n ->willReturn($mockTeam);\n }\n\n // Create service with mocked TeamRepository\n $automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);\n\n $result = $automatedReportsService->getTeamGroups($teamUuid);\n\n $this->assertEquals($expectedResult, $result);\n }\n\n public function testGetTeamGroupsWithNonExistentTeam(): void\n {\n // Create mock TeamRepository that returns null (team not found)\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->method('idOrUuid')->willReturn(null);\n\n // Create service with mocked TeamRepository\n $automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);\n\n $result = $automatedReportsService->getTeamGroups('non-existent-team-uuid');\n\n $this->assertEquals([], $result);\n }\n\n public function testGetTeamGroupsWithEmptyGroups(): void\n {\n // Create mock team with no groups\n $mockTeam = $this->createMock(\\Jiminny\\Models\\Team::class);\n\n // Create empty groups collection\n $mockGroupsCollection = $this->createMock(\\Illuminate\\Database\\Eloquent\\Collection::class);\n $mockGroupsCollection->method('getIterator')->willReturn(new \\ArrayIterator([]));\n\n $mockGroupsRelation = $this->createMock(\\Illuminate\\Database\\Eloquent\\Relations\\HasMany::class);\n $mockGroupsRelation->method('get')->willReturn($mockGroupsCollection);\n $mockTeam->method('groups')->willReturn($mockGroupsRelation);\n\n // Create mock TeamRepository\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->method('idOrUuid')->willReturn($mockTeam);\n\n // Create service with mocked TeamRepository\n $automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);\n\n $result = $automatedReportsService->getTeamGroups('team-with-no-groups');\n\n $this->assertEquals([], $result);\n }\n\n public static function getTeamGroupsDataProvider(): array\n {\n return [\n 'team with single group' => [\n 'teamUuid' => 'team-uuid-123',\n 'mockTeamData' => ['id' => 'team-uuid-123', 'name' => 'Test Team'],\n 'mockGroups' => [\n ['id' => 'group-uuid-1', 'name' => 'Sales Team'],\n ],\n 'expectedResult' => [\n ['id' => 'group-uuid-1', 'name' => 'Sales Team'],\n ],\n ],\n 'team with multiple groups' => [\n 'teamUuid' => 'team-uuid-456',\n 'mockTeamData' => ['id' => 'team-uuid-456', 'name' => 'Another Team'],\n 'mockGroups' => [\n ['id' => 'group-uuid-1', 'name' => 'Sales Team'],\n ['id' => 'group-uuid-2', 'name' => 'Marketing Team'],\n ['id' => 'group-uuid-3', 'name' => 'Support Team'],\n ],\n 'expectedResult' => [\n ['id' => 'group-uuid-1', 'name' => 'Sales Team'],\n ['id' => 'group-uuid-2', 'name' => 'Marketing Team'],\n ['id' => 'group-uuid-3', 'name' => 'Support Team'],\n ],\n ],\n 'team not found' => [\n 'teamUuid' => 'non-existent-uuid',\n 'mockTeamData' => null,\n 'mockGroups' => [],\n 'expectedResult' => [],\n ],\n 'team with no groups' => [\n 'teamUuid' => 'team-uuid-empty',\n 'mockTeamData' => ['id' => 'team-uuid-empty', 'name' => 'Empty Team'],\n 'mockGroups' => [],\n 'expectedResult' => [],\n ],\n ];\n }\n\n #[DataProvider('getTeamsDataProvider')]\n public function testGetTeams(array $mockTeams, array $expectedResult): void\n {\n // Create mock TeamRepository\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n\n // Create mock Team objects\n $teamObjects = [];\n foreach ($mockTeams as $teamData) {\n $mockTeam = $this->createMock(\\Jiminny\\Models\\Team::class);\n $mockTeam->method('getUuid')->willReturn($teamData['id']);\n $mockTeam->method('getName')->willReturn($teamData['name']);\n $mockTeam->method('hasFeature')\n ->with(\\Jiminny\\Models\\Feature\\FeatureEnum::AUTOMATED_REPORTS)\n ->willReturn($teamData['hasAutomatedReports']);\n $teamObjects[] = $mockTeam;\n }\n\n // Mock the repository to return a Collection (not array)\n $mockTeamRepository->method('getTeamsForKiosk')\n ->with('active')\n ->willReturn(new Collection($teamObjects));\n\n // Create service with mocked TeamRepository\n $automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);\n\n $result = $automatedReportsService->getTeams();\n\n $this->assertEquals($expectedResult, $result);\n }\n\n public function testGetTeamsWithNoTeams(): void\n {\n // Create mock TeamRepository that returns empty Collection\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->method('getTeamsForKiosk')->willReturn(new Collection([]));\n\n // Create service with mocked TeamRepository\n $automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);\n\n $result = $automatedReportsService->getTeams();\n\n $this->assertEquals([], $result);\n }\n\n public function testGetTeamsWithAllTeamsWithoutFeature(): void\n {\n // Create mock teams without AUTOMATED_REPORTS feature\n $mockTeam1 = $this->createMock(\\Jiminny\\Models\\Team::class);\n $mockTeam1->method('hasFeature')\n ->with(\\Jiminny\\Models\\Feature\\FeatureEnum::AUTOMATED_REPORTS)\n ->willReturn(false);\n\n $mockTeam2 = $this->createMock(\\Jiminny\\Models\\Team::class);\n $mockTeam2->method('hasFeature')\n ->with(\\Jiminny\\Models\\Feature\\FeatureEnum::AUTOMATED_REPORTS)\n ->willReturn(false);\n\n // Create mock TeamRepository that returns Collection\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->method('getTeamsForKiosk')->willReturn(new Collection([$mockTeam1, $mockTeam2]));\n\n // Create service with mocked TeamRepository\n $automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);\n\n $result = $automatedReportsService->getTeams();\n\n $this->assertEquals([], $result);\n }\n\n public function testGetTeamsForwardsPartnerToRepository(): void\n {\n $partner = $this->createMock(Partner::class);\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->expects(self::once())\n ->method('getTeamsForKiosk')\n ->with(Team::STATUS_ACTIVE, $partner)\n ->willReturn(new Collection([]));\n\n $service = $this->getService(mockTeamRepository: $mockTeamRepository);\n $service->getTeams(partner: $partner);\n }\n\n public function testGetOrganizationFieldDataForwardsPartnerToRepository(): void\n {\n $partner = $this->createMock(Partner::class);\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->expects(self::once())\n ->method('getTeamsForKiosk')\n ->with(Team::STATUS_ACTIVE, $partner)\n ->willReturn(new Collection([]));\n\n $service = $this->getService(mockTeamRepository: $mockTeamRepository);\n $service->getOrganizationFieldData(partner: $partner);\n }\n\n public function testGetTeamsGroupsOptionsForwardsPartnerToRepository(): void\n {\n $partner = $this->createMock(Partner::class);\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->expects(self::once())\n ->method('getTeamsForKiosk')\n ->with(Team::STATUS_ACTIVE, $partner)\n ->willReturn(new Collection([]));\n\n $service = $this->getService(mockTeamRepository: $mockTeamRepository);\n $service->getTeamsGroupsOptions(partner: $partner);\n }\n\n public static function getTeamsDataProvider(): array\n {\n return [\n 'single team with feature' => [\n 'mockTeams' => [\n [\n 'id' => 'team-uuid-1',\n 'name' => 'Sales Team',\n 'hasAutomatedReports' => true,\n ],\n ],\n 'expectedResult' => [\n ['id' => 'team-uuid-1', 'name' => 'Sales Team'],\n ],\n ],\n 'multiple teams with feature' => [\n 'mockTeams' => [\n [\n 'id' => 'team-uuid-1',\n 'name' => 'Sales Team',\n 'hasAutomatedReports' => true,\n ],\n [\n 'id' => 'team-uuid-2',\n 'name' => 'Marketing Team',\n 'hasAutomatedReports' => true,\n ],\n [\n 'id' => 'team-uuid-3',\n 'name' => 'Support Team',\n 'hasAutomatedReports' => true,\n ],\n ],\n 'expectedResult' => [\n ['id' => 'team-uuid-1', 'name' => 'Sales Team'],\n ['id' => 'team-uuid-2', 'name' => 'Marketing Team'],\n ['id' => 'team-uuid-3', 'name' => 'Support Team'],\n ],\n ],\n 'mixed teams - some with feature, some without' => [\n 'mockTeams' => [\n [\n 'id' => 'team-uuid-1',\n 'name' => 'Sales Team',\n 'hasAutomatedReports' => true,\n ],\n [\n 'id' => 'team-uuid-2',\n 'name' => 'Marketing Team',\n 'hasAutomatedReports' => false,\n ],\n [\n 'id' => 'team-uuid-3',\n 'name' => 'Support Team',\n 'hasAutomatedReports' => true,\n ],\n ],\n 'expectedResult' => [\n ['id' => 'team-uuid-1', 'name' => 'Sales Team'],\n ['id' => 'team-uuid-3', 'name' => 'Support Team'],\n ],\n ],\n 'all teams without feature' => [\n 'mockTeams' => [\n [\n 'id' => 'team-uuid-1',\n 'name' => 'Sales Team',\n 'hasAutomatedReports' => false,\n ],\n [\n 'id' => 'team-uuid-2',\n 'name' => 'Marketing Team',\n 'hasAutomatedReports' => false,\n ],\n ],\n 'expectedResult' => [],\n ],\n 'empty teams array' => [\n 'mockTeams' => [],\n 'expectedResult' => [],\n ],\n ];\n }\n\n #[DataProvider('deleteS3FilesDataProvider')]\n public function testDeleteS3Files(\n string $mediaType,\n array $expectedFileExtensions,\n array $existingFiles,\n string $pathSuffix,\n int $expectedDeletes\n ): void {\n // Arrange\n $teamUuid = 'team-uuid-123';\n $reportUuid = 'report-uuid-456';\n $basePath = sprintf('%s/reports/%s', $teamUuid, $reportUuid);\n\n $team = Mockery::mock(Team::class);\n $team->allows('getUuid')->andReturn($teamUuid);\n\n $report = Mockery::mock(AutomatedReport::class);\n $report->allows('getTeam')->andReturn($team);\n\n $result = Mockery::mock(AutomatedReportResult::class);\n $result->allows('getReport')->andReturn($report);\n $result->allows('getUuid')->andReturn($reportUuid);\n $result->allows('getMediaType')->andReturn($mediaType);\n\n Storage::fake();\n Log::shouldReceive('info')->times($expectedDeletes);\n\n foreach ($existingFiles as $extension) {\n $filePath = $basePath . $pathSuffix . '.' . $extension;\n Storage::put($filePath, 'dummy content');\n }\n\n // Act\n $this->service->deleteS3Files($result);\n\n // Assert\n foreach ($expectedFileExtensions as $extension) {\n $filePath = $basePath . $pathSuffix . '.' . $extension;\n if (in_array($extension, $existingFiles, true)) {\n Storage::assertMissing($filePath);\n } else {\n // To be sure no unexpected files were created and deleted\n Storage::assertMissing($filePath);\n }\n }\n }\n\n public static function deleteS3FilesDataProvider(): array\n {\n return [\n 'PDF report, all files exist' => [\n 'mediaType' => AutomatedReportsService::MEDIA_TYPE_PDF,\n 'expectedFileExtensions' => ['html', 'MD', 'pdf'],\n 'existingFiles' => ['html', 'MD', 'pdf'],\n 'pathSuffix' => '',\n 'expectedDeletes' => 3,\n ],\n 'PDF report, some files exist' => [\n 'mediaType' => AutomatedReportsService::MEDIA_TYPE_PDF,\n 'expectedFileExtensions' => ['html', 'MD', 'pdf'],\n 'existingFiles' => ['html', 'pdf'],\n 'pathSuffix' => '',\n 'expectedDeletes' => 2,\n ],\n 'PDF report, no files exist' => [\n 'mediaType' => AutomatedReportsService::MEDIA_TYPE_PDF,\n 'expectedFileExtensions' => ['html', 'MD', 'pdf'],\n 'existingFiles' => [],\n 'pathSuffix' => '',\n 'expectedDeletes' => 0,\n ],\n 'Podcast report, all files exist' => [\n 'mediaType' => AutomatedReportsService::MEDIA_TYPE_PODCAST,\n 'expectedFileExtensions' => ['json', 'mp3', 'ssml'],\n 'existingFiles' => ['json', 'mp3', 'ssml'],\n 'pathSuffix' => '_podcast',\n 'expectedDeletes' => 3,\n ],\n 'Podcast report, some files exist' => [\n 'mediaType' => AutomatedReportsService::MEDIA_TYPE_PODCAST,\n 'expectedFileExtensions' => ['json', 'mp3', 'ssml'],\n 'existingFiles' => ['mp3'],\n 'pathSuffix' => '_podcast',\n 'expectedDeletes' => 1,\n ],\n 'Podcast report, no files exist' => [\n 'mediaType' => AutomatedReportsService::MEDIA_TYPE_PODCAST,\n 'expectedFileExtensions' => ['json', 'mp3', 'ssml'],\n 'existingFiles' => [],\n 'pathSuffix' => '_podcast',\n 'expectedDeletes' => 0,\n ],\n 'Other media type, should do nothing' => [\n 'mediaType' => 'some_other_type',\n 'expectedFileExtensions' => [],\n 'existingFiles' => [],\n 'pathSuffix' => '',\n 'expectedDeletes' => 0,\n ],\n ];\n }\n\n public function testDeleteReportsResultsInRetentionPeriodWithLogging(): void\n {\n // Create mocks for the test\n $automatedReportsService = Mockery::mock(AutomatedReportsService::class);\n\n $team = Mockery::mock(Team::class);\n $team->shouldReceive('getId')->andReturn(123);\n\n $from = now()->subDays(30);\n $to = now();\n $source = 'test-source';\n\n // Expect the method to be called with specific parameters\n $automatedReportsService->shouldReceive('deleteReportsResultsInRetentionPeriodWithLogging')\n ->once()\n ->with(\n $team,\n Mockery::on(function ($arg) use ($from) {\n return $arg->timestamp === $from->timestamp;\n }),\n Mockery::on(function ($arg) use ($to) {\n return $arg->timestamp === $to->timestamp;\n }),\n $source\n )\n ->andReturn(5);\n\n // Call the method and verify the result\n $result = $automatedReportsService->deleteReportsResultsInRetentionPeriodWithLogging(\n $team,\n $from,\n $to,\n $source\n );\n\n $this->assertEquals(5, $result);\n }\n\n #[DataProvider('sanitizeFileNameDataProvider')]\n public function testSanitizeFileName(string $input, string $expected): void\n {\n $result = $this->service->sanitizeFileName($input);\n\n $this->assertEquals($expected, $result);\n }\n\n public static function sanitizeFileNameDataProvider(): array\n {\n return [\n 'no special characters' => [\n 'input' => 'Exec Summary - Sep 2025 - Business Development Team',\n 'expected' => 'Exec Summary - Sep 2025 - Business Development Team',\n ],\n 'forward slash in team name' => [\n 'input' => 'Exec Summary - Sep 2025 - ND/IRV',\n 'expected' => 'Exec Summary - Sep 2025 - ND-IRV',\n ],\n 'backslash in team name' => [\n 'input' => 'Exec Summary - Sep 2025 - ND\\IRV',\n 'expected' => 'Exec Summary - Sep 2025 - ND-IRV',\n ],\n 'multiple forward slashes' => [\n 'input' => 'Report - Team A/B/C',\n 'expected' => 'Report - Team A-B-C',\n ],\n 'multiple backslashes' => [\n 'input' => 'Report - Team A\\B\\C',\n 'expected' => 'Report - Team A-B-C',\n ],\n 'mixed slashes and backslashes' => [\n 'input' => 'Report - Team A/B\\C',\n 'expected' => 'Report - Team A-B-C',\n ],\n 'complex team name with slashes' => [\n 'input' => 'Exec Summary - Sep 2025 - Business Development Team - ND/IRV, Net Driven - Acquisition (Sales)',\n 'expected' => 'Exec Summary - Sep 2025 - Business Development Team - ND-IRV, Net Driven - Acquisition (Sales)',\n ],\n 'only slashes' => [\n 'input' => '//\\\\\\\\',\n 'expected' => '----',\n ],\n 'empty string' => [\n 'input' => '',\n 'expected' => '',\n ],\n 'slash at start' => [\n 'input' => '/Report Name',\n 'expected' => '-Report Name',\n ],\n 'slash at end' => [\n 'input' => 'Report Name/',\n 'expected' => 'Report Name-',\n ],\n ];\n }\n\n public function testGetReportFileNameSanitizesOutput(): void\n {\n // Create mock GroupRepository\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n\n // Create mock Group with slash in name\n $mockGroup = $this->createMock(\\Jiminny\\Models\\Group::class);\n $mockGroup->method('getName')->willReturn('ND/IRV, Net Driven - Acquisition (Sales)');\n\n $mockGroupRepository->method('find')->willReturn($mockGroup);\n\n // Create service with mocked GroupRepository\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n // Create mock AutomatedReportResult\n $mockReportResult = $this->createMock(AutomatedReportResult::class);\n\n // Create mock AutomatedReport\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getType')->willReturn('exec_summary');\n $mockReport->method('getFrequency')->willReturn('monthly');\n\n $mockReportResult->method('getReport')->willReturn($mockReport);\n $mockReportResult->method('getFromDate')->willReturn(\n \\Illuminate\\Support\\Carbon::parse('2025-09-01')\n );\n $mockReportResult->method('getToDate')->willReturn(\n \\Illuminate\\Support\\Carbon::parse('2025-09-30')\n );\n $mockReportResult->method('getGroups')->willReturn([123]);\n $mockReportResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PDF);\n\n // Call getReportFileName\n $result = $service->getReportFileName($mockReportResult);\n\n // Verify the result does not contain slashes or backslashes\n $this->assertStringNotContainsString('/', $result);\n $this->assertStringNotContainsString('\\\\', $result);\n\n // Verify the slash was replaced with dash\n $this->assertStringContainsString('ND-IRV', $result);\n }\n\n public function testGetReportFileNameWithExtensionSanitizesOutput(): void\n {\n // Create mock GroupRepository\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n\n // Create mock Group with backslash in name\n $mockGroup = $this->createMock(\\Jiminny\\Models\\Group::class);\n $mockGroup->method('getName')->willReturn('Team\\Name');\n\n $mockGroupRepository->method('find')->willReturn($mockGroup);\n\n // Create service with mocked GroupRepository\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n // Create mock AutomatedReportResult\n $mockReportResult = $this->createMock(AutomatedReportResult::class);\n\n // Create mock AutomatedReport\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getType')->willReturn('exec_summary');\n $mockReport->method('getFrequency')->willReturn('monthly');\n\n $mockReportResult->method('getReport')->willReturn($mockReport);\n $mockReportResult->method('getFromDate')->willReturn(\n \\Illuminate\\Support\\Carbon::parse('2025-09-01')\n );\n $mockReportResult->method('getToDate')->willReturn(\n \\Illuminate\\Support\\Carbon::parse('2025-09-30')\n );\n $mockReportResult->method('getGroups')->willReturn([123]);\n $mockReportResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PDF);\n\n // Call getReportFileNameWithExtension\n $result = $service->getReportFileNameWithExtension($mockReportResult);\n\n // Verify the result does not contain backslashes\n $this->assertStringNotContainsString('\\\\', $result);\n $this->assertStringNotContainsString('/', $result);\n\n // Verify the backslash was replaced with dash\n $this->assertStringContainsString('Team-Name', $result);\n\n // Verify extension is added\n $this->assertStringEndsWith('.pdf', $result);\n }\n\n public function testHasPassedScheduledTimeWithNullGeneratedAt(): void\n {\n $result = $this->service->hasPassedScheduledTime(null, 'America/Chicago');\n\n $this->assertFalse($result);\n }\n\n public function testHasPassedScheduledTimeWhenScheduledTimePassed(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-02-24 10:00:00', 'America/Chicago'));\n\n $generatedAt = Carbon::parse('2026-02-24 01:00:00', 'America/Chicago');\n\n $result = $this->service->hasPassedScheduledTime($generatedAt, 'America/Chicago');\n\n $this->assertTrue($result);\n\n Carbon::setTestNow();\n }\n\n public function testHasPassedScheduledTimeWhenGeneratedAfterScheduledTime(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-02-24 10:00:00', 'America/Chicago'));\n\n $generatedAt = Carbon::parse('2026-02-24 06:00:00', 'America/Chicago');\n\n $result = $this->service->hasPassedScheduledTime($generatedAt, 'America/Chicago');\n\n $this->assertFalse($result);\n\n Carbon::setTestNow();\n }\n\n public function testHasPassedScheduledTimeBeforeScheduledTimeToday(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-02-24 04:00:00', 'America/Chicago'));\n\n $generatedAt = Carbon::parse('2026-02-24 01:00:00', 'America/Chicago');\n\n $result = $this->service->hasPassedScheduledTime($generatedAt, 'America/Chicago');\n\n $this->assertFalse($result);\n\n Carbon::setTestNow();\n }\n\n public function testShouldSendReportWithEmptyUsers(): void\n {\n $result = $this->service->shouldSendReport([]);\n\n $this->assertFalse($result);\n }\n\n public function testShouldSendReportAtScheduledTime(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-02-24 05:00:00', 'America/Chicago'));\n\n $users = [\n ['email' => 'test@example.com', 'name' => 'Test User', 'timezone' => 'America/Chicago'],\n ];\n\n $result = $this->service->shouldSendReport($users);\n\n $this->assertTrue($result);\n\n Carbon::setTestNow();\n }\n\n public function testShouldSendReportNotAtScheduledTimeWithoutGeneratedAt(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-02-24 10:00:00', 'America/Chicago'));\n\n $users = [\n ['email' => 'test@example.com', 'name' => 'Test User', 'timezone' => 'America/Chicago'],\n ];\n\n $result = $this->service->shouldSendReport($users);\n\n $this->assertFalse($result);\n\n Carbon::setTestNow();\n }\n\n public function testShouldSendReportWhenScheduledTimeMissed(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-02-24 10:00:00', 'America/Chicago'));\n\n $users = [\n ['email' => 'test@example.com', 'name' => 'Test User', 'timezone' => 'America/Chicago'],\n ];\n\n $generatedAt = Carbon::parse('2026-02-24 01:00:00', 'America/Chicago');\n\n $result = $this->service->shouldSendReport($users, $generatedAt);\n\n $this->assertTrue($result);\n\n Carbon::setTestNow();\n }\n\n public function testShouldSendReportWhenGeneratedAfterScheduledTime(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-02-24 10:00:00', 'America/Chicago'));\n\n $users = [\n ['email' => 'test@example.com', 'name' => 'Test User', 'timezone' => 'America/Chicago'],\n ];\n\n $generatedAt = Carbon::parse('2026-02-24 06:00:00', 'America/Chicago');\n\n $result = $this->service->shouldSendReport($users, $generatedAt);\n\n $this->assertFalse($result);\n\n Carbon::setTestNow();\n }\n\n public function testGetTypes(): void\n {\n $types = AutomatedReportsService::getTypes();\n\n $this->assertIsArray($types);\n $this->assertContains('exec_summary', $types);\n $this->assertContains('coaching_profiles', $types);\n $this->assertContains('loss_analysis', $types);\n $this->assertNotContains('ask_jiminny', $types);\n }\n\n public function testGetCallTypes(): void\n {\n $callTypes = AutomatedReportsService::getCallTypes();\n\n $this->assertIsArray($callTypes);\n $this->assertContains('conference', $callTypes);\n $this->assertContains('dialer', $callTypes);\n }\n\n public function testGetFrequencies(): void\n {\n $frequencies = AutomatedReportsService::getFrequencies();\n\n $this->assertIsArray($frequencies);\n $this->assertContains('weekly', $frequencies);\n $this->assertContains('monthly', $frequencies);\n $this->assertContains('quarterly', $frequencies);\n $this->assertContains('one_off', $frequencies);\n $this->assertNotContains('daily', $frequencies);\n }\n\n public function testGetAskJiminnyFrequencies(): void\n {\n $frequencies = AutomatedReportsService::getAskJiminnyFrequencies();\n\n $this->assertIsArray($frequencies);\n $this->assertContains('daily', $frequencies);\n $this->assertContains('weekly', $frequencies);\n $this->assertContains('monthly', $frequencies);\n $this->assertNotContains('quarterly', $frequencies);\n $this->assertNotContains('one_off', $frequencies);\n }\n\n public function testGetReportEnabledFieldData(): void\n {\n $result = $this->service->getReportEnabledFieldData(true);\n\n $this->assertEquals('report_enabled', $result['id']);\n $this->assertTrue($result['value']);\n }\n\n public function testGetReportEnabledFieldDataDefault(): void\n {\n $result = $this->service->getReportEnabledFieldData();\n\n $this->assertFalse($result['value']);\n }\n\n public function testGetOrganizationFieldDataShortVersion(): void\n {\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->method('getTeamsForKiosk')->willReturn(new Collection([]));\n\n $service = $this->getService(mockTeamRepository: $mockTeamRepository);\n $result = $service->getOrganizationFieldData(null, true);\n\n $this->assertEquals('organization', $result['id']);\n $this->assertArrayNotHasKey('inputType', $result);\n $this->assertArrayHasKey('options', $result);\n }\n\n public function testGetOrganizationFieldDataFullVersion(): void\n {\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->method('getTeamsForKiosk')->willReturn(new Collection([]));\n\n $service = $this->getService(mockTeamRepository: $mockTeamRepository);\n $result = $service->getOrganizationFieldData('team-uuid-1', false);\n\n $this->assertEquals('organization', $result['id']);\n $this->assertArrayHasKey('inputType', $result);\n $this->assertEquals('team-uuid-1', $result['value']);\n $this->assertArrayHasKey('dependencies', $result);\n }\n\n public function testGetTeamFieldDataShortVersion(): void\n {\n $result = $this->service->getTeamFieldData([], [], true);\n\n $this->assertEquals('teams', $result['id']);\n $this->assertArrayNotHasKey('inputType', $result);\n }\n\n public function testGetTeamFieldDataFullVersion(): void\n {\n $result = $this->service->getTeamFieldData(['opt1'], ['val1'], false);\n\n $this->assertEquals('teams', $result['id']);\n $this->assertArrayHasKey('inputType', $result);\n $this->assertEquals(['opt1'], $result['options']);\n $this->assertEquals(['val1'], $result['value']);\n }\n\n public function testGetReportTypeFieldDataShortVersion(): void\n {\n $result = $this->service->getReportTypeFieldData(null, true);\n\n $this->assertEquals('report_type', $result['id']);\n $this->assertArrayNotHasKey('inputType', $result);\n }\n\n public function testGetReportTypeFieldDataFullVersion(): void\n {\n $result = $this->service->getReportTypeFieldData('exec_summary', false);\n\n $this->assertEquals('report_type', $result['id']);\n $this->assertArrayHasKey('inputType', $result);\n $this->assertEquals('exec_summary', $result['value']);\n }\n\n public function testGetReportTypeFieldDataWithTeamHavingBothFeatures(): void\n {\n $team = $this->createMock(\\Jiminny\\Models\\Team::class);\n $team->method('hasFeature')->willReturnMap([\n [\\Jiminny\\Models\\Feature\\FeatureEnum::AUTOMATED_REPORTS, true],\n [\\Jiminny\\Models\\Feature\\FeatureEnum::ASK_JIMINNY_REPORTS, true],\n ]);\n\n $result = $this->service->getReportTypeFieldData(null, true, $team);\n\n $ids = array_column($result['options'], 'id');\n $this->assertContains('exec_summary', $ids);\n $this->assertContains(AutomatedReportsService::TYPE_ASK_JIMINNY, $ids);\n $this->assertLessThan(\n array_search(AutomatedReportsService::TYPE_ASK_JIMINNY, $ids),\n array_search('exec_summary', $ids)\n );\n }\n\n public function testGetReportTypeFieldDataWithTeamHavingOnlyAutomatedReports(): void\n {\n $team = $this->createMock(\\Jiminny\\Models\\Team::class);\n $team->method('hasFeature')->willReturnMap([\n [\\Jiminny\\Models\\Feature\\FeatureEnum::AUTOMATED_REPORTS, true],\n [\\Jiminny\\Models\\Feature\\FeatureEnum::ASK_JIMINNY_REPORTS, false],\n ]);\n\n $result = $this->service->getReportTypeFieldData(null, true, $team);\n\n $ids = array_column($result['options'], 'id');\n $this->assertContains('exec_summary', $ids);\n $this->assertNotContains(AutomatedReportsService::TYPE_ASK_JIMINNY, $ids);\n }\n\n public function testGetReportTypeFieldDataWithTeamHavingOnlyAskJiminny(): void\n {\n $team = $this->createMock(\\Jiminny\\Models\\Team::class);\n $team->method('hasFeature')->willReturnMap([\n [\\Jiminny\\Models\\Feature\\FeatureEnum::AUTOMATED_REPORTS, false],\n [\\Jiminny\\Models\\Feature\\FeatureEnum::ASK_JIMINNY_REPORTS, true],\n ]);\n\n $result = $this->service->getReportTypeFieldData(null, true, $team);\n\n $ids = array_column($result['options'], 'id');\n $this->assertContains(AutomatedReportsService::TYPE_ASK_JIMINNY, $ids);\n $this->assertNotContains('exec_summary', $ids);\n }\n\n public function testGetReportTypeFieldDataWithNullTeamFallsBackToStandardTypes(): void\n {\n $result = $this->service->getReportTypeFieldData(null, true, null);\n\n $ids = array_column($result['options'], 'id');\n $this->assertContains('exec_summary', $ids);\n $this->assertNotContains(AutomatedReportsService::TYPE_ASK_JIMINNY, $ids);\n }\n\n public function testGetFrequencyFieldData(): void\n {\n $result = $this->service->getFrequencyFieldData('weekly');\n\n $this->assertEquals('frequency', $result['id']);\n $this->assertEquals('weekly', $result['value']);\n $this->assertArrayHasKey('options', $result);\n }\n\n public function testGetPeriodFieldData(): void\n {\n $result = $this->service->getPeriodFieldData('2025-01-01', '2025-01-31');\n\n $this->assertEquals('period', $result['id']);\n $this->assertEquals('2025-01-01', $result['value']['startDate']);\n $this->assertEquals('2025-01-31', $result['value']['endDate']);\n }\n\n public function testGetCallDurationFieldData(): void\n {\n $result = $this->service->getCallDurationFieldData(5, 60);\n\n $this->assertEquals('call_duration', $result['id']);\n $this->assertEquals(5, $result['value']['min']);\n $this->assertEquals(60, $result['value']['max']);\n }\n\n public function testGetDealValueFieldData(): void\n {\n $result = $this->service->getDealValueFieldData(1000, 5000);\n\n $this->assertEquals('deal_value', $result['id']);\n $this->assertEquals(1000, $result['value']['min']);\n $this->assertEquals(5000, $result['value']['max']);\n }\n\n public function testGetCustomReportNameFieldData(): void\n {\n $result = $this->service->getCustomReportNameFieldData('My Report');\n\n $this->assertEquals('custom_name', $result['id']);\n $this->assertEquals('My Report', $result['value']);\n }\n\n public function testGetAdditionalPromptInputFieldData(): void\n {\n $result = $this->service->getAdditionalPromptInputFieldData('Some prompt');\n\n $this->assertEquals('additional_prompt_input', $result['id']);\n $this->assertEquals('Some prompt', $result['value']);\n }\n\n public function testGetCallTypeFieldDataBothOn(): void\n {\n $result = $this->service->getCallTypeFieldData(true, true);\n\n $this->assertEquals('call_type', $result['id']);\n $this->assertCount(2, $result['value']);\n }\n\n public function testGetCallTypeFieldDataNoneOn(): void\n {\n $result = $this->service->getCallTypeFieldData(false, false);\n\n $this->assertEquals('call_type', $result['id']);\n $this->assertEmpty($result['value']);\n }\n\n public function testGetCallTypeFieldDataConferenceOnly(): void\n {\n $result = $this->service->getCallTypeFieldData(true, false);\n\n $this->assertCount(1, $result['value']);\n $this->assertEquals('conference', $result['value'][0]['id']);\n }\n\n public function testGetCallTypeFieldDataDialerOnly(): void\n {\n $result = $this->service->getCallTypeFieldData(false, true);\n\n $this->assertCount(1, $result['value']);\n $this->assertEquals('dialer', $result['value'][0]['id']);\n }\n\n public function testTransformDurationToMinutesNull(): void\n {\n $result = $this->service->transformDurationToMinutes(null);\n\n $this->assertNull($result);\n }\n\n public function testTransformDurationToMinutesZero(): void\n {\n $result = $this->service->transformDurationToMinutes(0);\n\n $this->assertNull($result);\n }\n\n public function testTransformDurationToMinutes(): void\n {\n $result = $this->service->transformDurationToMinutes(300);\n\n $this->assertEquals(5, $result);\n }\n\n public function testGetTeam(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->expects($this->once())\n ->method('idOrUuid')\n ->with('team-uuid')\n ->willReturn($mockTeam);\n\n $service = $this->getService(mockTeamRepository: $mockTeamRepository);\n $result = $service->getTeam('team-uuid');\n\n $this->assertSame($mockTeam, $result);\n }\n\n public function testGetTeamById(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->expects($this->once())\n ->method('find')\n ->with(42)\n ->willReturn($mockTeam);\n\n $service = $this->getService(mockTeamRepository: $mockTeamRepository);\n $result = $service->getTeamById(42);\n\n $this->assertSame($mockTeam, $result);\n }\n\n public function testGetGroupsUuidsEmpty(): void\n {\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getGroups')->willReturn([]);\n\n $result = $this->service->getGroupsUuids($report);\n\n $this->assertEquals([], $result);\n }\n\n public function testGetGroupsUuidsWithGroups(): void\n {\n $mockGroup = $this->createMock(Group::class);\n $mockGroup->method('getUuid')->willReturn('group-uuid-1');\n\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n $mockGroupRepository->method('find')->willReturnMap([\n [10, $mockGroup],\n [99, null],\n ]);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getGroups')->willReturn([10, 99]);\n\n $result = $service->getGroupsUuids($report);\n\n $this->assertEquals(['group-uuid-1'], $result);\n }\n\n public function testGetPlaybookCategoriesUuidsEmpty(): void\n {\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getPlaybookCategories')->willReturn([]);\n\n $result = $this->service->getPlaybookCategoriesUuids($report);\n\n $this->assertEquals([], $result);\n }\n\n public function testGetPlaybookCategoriesUuidsWithCategories(): void\n {\n $mockCategory = $this->createMock(\\Jiminny\\Models\\PlaybookCategory::class);\n $mockCategory->method('getUuid')->willReturn('cat-uuid-1');\n\n $mockPlaybookCategoryRepository = $this->createMock(PlaybookCategoryRepository::class);\n $mockPlaybookCategoryRepository->method('find')->willReturnMap([\n [1, $mockCategory],\n [2, null],\n ]);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $mockPlaybookCategoryRepository,\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getPlaybookCategories')->willReturn([1, 2]);\n\n $result = $service->getPlaybookCategoriesUuids($report);\n\n $this->assertEquals(['cat-uuid-1'], $result);\n }\n\n public function testGetDealAtCallStagesUuidsEmpty(): void\n {\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getDealAtCallStages')->willReturn([]);\n\n $result = $this->service->getDealAtCallStagesUuids($report);\n\n $this->assertEquals([], $result);\n }\n\n public function testGetDealAtCallStagesUuidsWithStages(): void\n {\n $mockStage = $this->createMock(\\Jiminny\\Models\\Stage::class);\n $mockStage->method('getUuid')->willReturn('stage-uuid-1');\n\n $mockStageRepository = $this->createMock(StageRepository::class);\n $mockStageRepository->method('find')->willReturnMap([\n [5, $mockStage],\n [9, null],\n ]);\n\n $service = $this->getService(mockStageRepository: $mockStageRepository);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getDealAtCallStages')->willReturn([5, 9]);\n\n $result = $service->getDealAtCallStagesUuids($report);\n\n $this->assertEquals(['stage-uuid-1'], $result);\n }\n\n public function testGetJiminnyUsersUuids(): void\n {\n $mockUser = $this->createMock(User::class);\n $mockUser->method('getUuid')->willReturn('user-uuid-1');\n\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturn($mockUser);\n\n $service = $this->getService(mockUserRepository: $mockUserRepository);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getJiminnyRecipients')->willReturn(['users' => [1]]);\n\n $result = $service->getJiminnyUsersUuids($report);\n\n $this->assertEquals(['user-uuid-1'], $result);\n }\n\n public function testGetRecipientUsers(): void\n {\n $mockUser = $this->createMock(User::class);\n $mockUser->method('getEmailAddress')->willReturn('user@test.com');\n $mockUser->method('getName')->willReturn('Test User');\n $timezone = $this->createMock(\\DateTimeZone::class);\n $timezone->method('getName')->willReturn('UTC');\n $mockUser->method('getTimezone')->willReturn($timezone);\n\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturn($mockUser);\n\n $service = $this->getService(mockUserRepository: $mockUserRepository);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getRecipients')->willReturn(['users' => [1]]);\n\n $result = $service->getRecipientUsers($report);\n\n $this->assertCount(1, $result);\n $this->assertEquals('user@test.com', $result[0]['email']);\n $this->assertEquals('Test User', $result[0]['name']);\n }\n\n public function testGetValidRecipientUsersFiltersEmptyEmail(): void\n {\n $mockUserWithEmail = $this->createMock(User::class);\n $mockUserWithEmail->method('getEmailAddress')->willReturn('valid@test.com');\n $mockUserWithEmail->method('getName')->willReturn('Valid User');\n $timezone = $this->createMock(\\DateTimeZone::class);\n $timezone->method('getName')->willReturn('UTC');\n $mockUserWithEmail->method('getTimezone')->willReturn($timezone);\n\n $mockUserNoEmail = $this->createMock(User::class);\n $mockUserNoEmail->method('getEmailAddress')->willReturn('');\n $mockUserNoEmail->method('getName')->willReturn('No Email User');\n $mockUserNoEmail->method('getTimezone')->willReturn($timezone);\n\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturnMap([\n [1, $mockUserWithEmail],\n [2, $mockUserNoEmail],\n ]);\n\n $service = $this->getService(mockUserRepository: $mockUserRepository);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getRecipients')->willReturn(['users' => [1, 2]]);\n $report->method('getJiminnyRecipients')->willReturn(['users' => []]);\n\n $result = $service->getValidRecipientUsers($report);\n\n $this->assertCount(1, $result);\n $this->assertEquals('valid@test.com', $result[0]['email']);\n }\n\n public function testGetValidRecipientUsersWithJiminny(): void\n {\n $tz = $this->createMock(\\DateTimeZone::class);\n $tz->method('getName')->willReturn('UTC');\n\n $mockUser1 = $this->createMock(User::class);\n $mockUser1->method('getEmailAddress')->willReturn('user1@test.com');\n $mockUser1->method('getName')->willReturn('User1');\n $mockUser1->method('getTimezone')->willReturn($tz);\n\n $mockUser2 = $this->createMock(User::class);\n $mockUser2->method('getEmailAddress')->willReturn('jiminny@test.com');\n $mockUser2->method('getName')->willReturn('Jiminny');\n $mockUser2->method('getTimezone')->willReturn($tz);\n\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturnMap([\n [1, $mockUser1],\n [2, $mockUser2],\n ]);\n\n $service = $this->getService(mockUserRepository: $mockUserRepository);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getRecipients')->willReturn(['users' => [1]]);\n $report->method('getJiminnyRecipients')->willReturn(['users' => [2]]);\n\n $result = $service->getValidRecipientUsers($report, true);\n\n $this->assertCount(2, $result);\n }\n\n public function testGetReportTypeName(): void\n {\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getType')->willReturn('exec_summary');\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getReport')->willReturn($report);\n\n $result = $this->service->getReportTypeName($mockResult);\n\n $this->assertEquals('Exec Summary', $result);\n }\n\n public function testGetReportPeriodNameThrowsOnNullFrom(): void\n {\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getFrequency')->willReturn('weekly');\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getReport')->willReturn($report);\n $mockResult->method('getFromDate')->willReturn(null);\n $mockResult->method('getToDate')->willReturn(IlluminateCarbon::parse('2025-01-15'));\n\n $this->expectException(\\Jiminny\\Exceptions\\ApplicationException::class);\n\n $this->service->getReportPeriodName($mockResult);\n }\n\n public function testGetReportPeriodNameThrowsOnNullTo(): void\n {\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getFrequency')->willReturn('weekly');\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getReport')->willReturn($report);\n $mockResult->method('getFromDate')->willReturn(IlluminateCarbon::parse('2025-01-08'));\n $mockResult->method('getToDate')->willReturn(null);\n\n $this->expectException(\\Jiminny\\Exceptions\\ApplicationException::class);\n\n $this->service->getReportPeriodName($mockResult);\n }\n\n #[DataProvider('formatReportPeriodNameDataProvider')]\n public function testGetReportPeriodName(\n string $frequency,\n string $from,\n string $to,\n string $expected\n ): void {\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getFrequency')->willReturn($frequency);\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getReport')->willReturn($report);\n $mockResult->method('getFromDate')->willReturn(IlluminateCarbon::parse($from));\n $mockResult->method('getToDate')->willReturn(IlluminateCarbon::parse($to));\n\n $result = $this->service->getReportPeriodName($mockResult);\n\n $this->assertEquals($expected, $result);\n }\n\n public static function formatReportPeriodNameDataProvider(): array\n {\n return [\n 'daily' => [\n 'frequency' => 'daily',\n 'from' => '2025-05-15',\n 'to' => '2025-05-15',\n 'expected' => '15 May 2025',\n ],\n 'monthly same year' => [\n 'frequency' => 'monthly',\n 'from' => '2025-05-01',\n 'to' => '2025-05-31',\n 'expected' => 'May 2025',\n ],\n 'weekly same month' => [\n 'frequency' => 'weekly',\n 'from' => '2025-08-04',\n 'to' => '2025-08-08',\n 'expected' => '4 - 8 Aug 2025',\n ],\n 'weekly different months same year' => [\n 'frequency' => 'weekly',\n 'from' => '2025-10-27',\n 'to' => '2025-11-03',\n 'expected' => '27 Oct - 3 Nov 2025',\n ],\n 'weekly different years' => [\n 'frequency' => 'weekly',\n 'from' => '2024-12-28',\n 'to' => '2025-01-03',\n 'expected' => '28 Dec 2024 - 3 Jan 2025',\n ],\n 'quarterly same year' => [\n 'frequency' => 'quarterly',\n 'from' => '2025-01-01',\n 'to' => '2025-04-01',\n 'expected' => 'Jan - Mar 2025',\n ],\n 'quarterly different years' => [\n 'frequency' => 'quarterly',\n 'from' => '2024-11-01',\n 'to' => '2025-02-01',\n 'expected' => 'Nov 2024 - Jan 2025',\n ],\n 'one_off same month' => [\n 'frequency' => 'one_off',\n 'from' => '2025-05-02',\n 'to' => '2025-05-31',\n 'expected' => '2 - 31 May 2025',\n ],\n 'one_off different months same year' => [\n 'frequency' => 'one_off',\n 'from' => '2025-05-15',\n 'to' => '2025-06-15',\n 'expected' => '15 May - 15 Jun 2025',\n ],\n 'one_off different years' => [\n 'frequency' => 'one_off',\n 'from' => '2024-12-15',\n 'to' => '2025-01-15',\n 'expected' => '15 Dec 2024 - 15 Jan 2025',\n ],\n 'unknown frequency falls back to default' => [\n 'frequency' => 'unknown',\n 'from' => '2025-05-01',\n 'to' => '2025-05-31',\n 'expected' => '1 May 2025 - 31 May 2025',\n ],\n ];\n }\n\n public function testGetReportTeamsNameEmpty(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getGroups')->willReturn([]);\n\n $result = $this->service->getReportTeamsName($mockResult);\n\n $this->assertEquals('All', $result);\n }\n\n public function testGetReportTeamsNameSingleGroup(): void\n {\n $mockGroup = $this->createMock(Group::class);\n $mockGroup->method('getName')->willReturn('Sales Team');\n\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n $mockGroupRepository->method('find')->willReturn($mockGroup);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getGroups')->willReturn([10]);\n\n $result = $service->getReportTeamsName($mockResult);\n\n $this->assertEquals('Sales Team', $result);\n }\n\n public function testGetReportTeamsNameMultipleGroups(): void\n {\n $mockGroup1 = $this->createMock(Group::class);\n $mockGroup1->method('getName')->willReturn('Sales Team');\n\n $mockGroup2 = $this->createMock(Group::class);\n $mockGroup2->method('getName')->willReturn('Marketing Team');\n\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n $mockGroupRepository->method('find')->willReturnMap([\n [10, $mockGroup1],\n [20, $mockGroup2],\n [99, null],\n ]);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getGroups')->willReturn([10, 20, 99]);\n\n $result = $service->getReportTeamsName($mockResult);\n\n $this->assertEquals('Sales Team, Marketing Team', $result);\n }\n\n public function testGetReportFound(): void\n {\n $mockReport = $this->createMock(AutomatedReport::class);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('findByUuid')\n ->with('report-uuid')\n ->willReturn($mockReport);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->getReport('report-uuid');\n\n $this->assertSame($mockReport, $result);\n }\n\n public function testGetReportNotFound(): void\n {\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->method('findByUuid')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(ModelNotFoundException::class);\n\n $service->getReport('non-existent-uuid');\n }\n\n public function testDeleteReportNotFound(): void\n {\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->method('findByUuid')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(ModelNotFoundException::class);\n\n $service->delete('non-existent-uuid');\n }\n\n public function testDeleteReportSuccess(): void\n {\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->expects($this->once())->method('delete');\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->method('findByUuid')->willReturn($mockReport);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $service->delete('report-uuid');\n }\n\n public function testUpdateStatusNotFound(): void\n {\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->method('findByUuid')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(ModelNotFoundException::class);\n\n $service->updateStatus('non-existent-uuid', ['report_enabled' => true]);\n }\n\n public function testGetReportResultFound(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('findResultByUuid')\n ->with('result-uuid')\n ->willReturn($mockResult);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->getReportResult('result-uuid');\n\n $this->assertSame($mockResult, $result);\n }\n\n public function testGetReportResultNotFound(): void\n {\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->method('findResultByUuid')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(ModelNotFoundException::class);\n\n $service->getReportResult('non-existent-uuid');\n }\n\n public function testFindChildResult(): void\n {\n $mockParent = $this->createMock(AutomatedReportResult::class);\n $mockChild = $this->createMock(AutomatedReportResult::class);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('findChildResult')\n ->with($mockParent, 'podcast')\n ->willReturn($mockChild);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->findChildResult($mockParent, 'podcast');\n\n $this->assertSame($mockChild, $result);\n }\n\n #[DataProvider('calculateFromAndToDatePeriodDataProvider')]\n public function testCalculateFromAndToDatePeriod(string $frequency): void\n {\n Carbon::setTestNow(Carbon::parse('2025-06-15 12:00:00'));\n\n $result = $this->service->calculateFromAndToDatePeriod($frequency);\n\n $this->assertArrayHasKey('fromDate', $result);\n $this->assertArrayHasKey('toDate', $result);\n $this->assertInstanceOf(Carbon::class, $result['fromDate']);\n $this->assertInstanceOf(Carbon::class, $result['toDate']);\n\n Carbon::setTestNow();\n }\n\n public static function calculateFromAndToDatePeriodDataProvider(): array\n {\n return [\n 'daily' => ['daily'],\n 'weekly' => ['weekly'],\n 'monthly' => ['monthly'],\n 'quarterly' => ['quarterly'],\n ];\n }\n\n public function testCalculateFromAndToDatePeriodOneOff(): void\n {\n $from = IlluminateCarbon::parse('2025-01-01');\n $to = IlluminateCarbon::parse('2025-01-31');\n\n $result = $this->service->calculateFromAndToDatePeriod('one_off', $from, $to);\n\n $this->assertSame($from, $result['fromDate']);\n $this->assertSame($to, $result['toDate']);\n }\n\n public function testCalculateFromAndToDatePeriodInvalidFrequency(): void\n {\n $this->expectException(InvalidArgumentException::class);\n\n $this->service->calculateFromAndToDatePeriod('invalid_frequency');\n }\n\n public function testGetMediaPath(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PDF);\n $mockResult->method('getPdfUrl')->willReturn('https://example.com/reports/file.pdf');\n\n $result = $this->service->getMediaPath($mockResult);\n\n $this->assertEquals('/reports/file.pdf', $result);\n }\n\n public function testGetMediaPathPodcast(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PODCAST);\n $mockResult->method('getPodcastAudioUrl')->willReturn('https://example.com/audio/file.mp3');\n\n $result = $this->service->getMediaPath($mockResult);\n\n $this->assertEquals('/audio/file.mp3', $result);\n }\n\n public function testGetMediaPathNullUrl(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn('unknown_type');\n\n $result = $this->service->getMediaPath($mockResult);\n\n $this->assertNull($result);\n }\n\n public function testGetMediaPathPdfNullUrl(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PDF);\n $mockResult->method('getPdfUrl')->willReturn(null);\n\n $result = $this->service->getMediaPath($mockResult);\n\n $this->assertNull($result);\n }\n\n public function testGetFilenameSuffixPodcast(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PODCAST);\n\n $result = $this->service->getFilenameSuffix($mockResult);\n\n $this->assertEquals('Podcast', $result);\n }\n\n public function testGetFilenameSuffixPdf(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PDF);\n\n $result = $this->service->getFilenameSuffix($mockResult);\n\n $this->assertNull($result);\n }\n\n public function testGetMailSubjectSuffixPdf(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PDF);\n\n $result = $this->service->getMailSubjectSuffix($mockResult);\n\n $this->assertEquals('report', $result);\n }\n\n public function testGetMailSubjectSuffixPodcast(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PODCAST);\n\n $result = $this->service->getMailSubjectSuffix($mockResult);\n\n $this->assertEquals('podcast', $result);\n }\n\n public function testGetMailSubjectSuffixUnknown(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn('unknown_type');\n\n $result = $this->service->getMailSubjectSuffix($mockResult);\n\n $this->assertEquals('', $result);\n }\n\n public function testGetMediaTypeMetadataPdf(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PDF);\n\n $result = $this->service->getMediaTypeMetadata($mockResult);\n\n $this->assertEquals('pdf', $result['extension']);\n $this->assertEquals('application/pdf', $result['mime']);\n }\n\n public function testGetMediaTypeMetadataPodcast(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PODCAST);\n\n $result = $this->service->getMediaTypeMetadata($mockResult);\n\n $this->assertEquals('mp3', $result['extension']);\n $this->assertEquals('audio/mpeg', $result['mime']);\n }\n\n public function testGetMediaTypeMetadataUnknown(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn('unknown');\n\n $result = $this->service->getMediaTypeMetadata($mockResult);\n\n $this->assertNull($result['extension']);\n $this->assertNull($result['mime']);\n }\n\n public function testGetTeamIdsWithReportsResults(): void\n {\n $expected = new Collection([1, 2, 3]);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('getTeamIdsWithReportsResults')\n ->with(5)\n ->willReturn($expected);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->getTeamIdsWithReportsResults(5);\n\n $this->assertSame($expected, $result);\n }\n\n public function testGetTeamReports(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $expected = new \\Illuminate\\Database\\Eloquent\\Collection();\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('getReportsByTeam')\n ->with($mockTeam)\n ->willReturn($expected);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->getTeamReports($mockTeam);\n\n $this->assertSame($expected, $result);\n }\n\n public function testGetReportResults(): void\n {\n $mockReport = $this->createMock(AutomatedReport::class);\n $expected = new \\Illuminate\\Database\\Eloquent\\Collection();\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('getResultsByReport')\n ->with($mockReport)\n ->willReturn($expected);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->getReportResults($mockReport);\n\n $this->assertSame($expected, $result);\n }\n\n public function testDeleteReportsResultsInRetentionPeriodNoReports(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $retentionDate = \\Carbon\\CarbonImmutable::parse('2025-01-01');\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('getReportIdsByTeam')\n ->willReturn(new Collection([]));\n $mockRepo->expects($this->never())\n ->method('getReportResultsQueryForRetention');\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->deleteReportsResultsInRetentionPeriod($mockTeam, $retentionDate);\n\n $this->assertEquals(0, $result);\n }\n\n public function testDeleteReportsResultsInRetentionPeriodWithNoQueryResults(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $mockTeam->method('getId')->willReturn(1);\n $retentionDate = \\Carbon\\CarbonImmutable::parse('2025-01-01');\n\n $mockQuery = Mockery::mock(Builder::class);\n $mockQuery->shouldReceive('exists')->andReturn(false);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->method('getReportIdsByTeam')->willReturn(new Collection([1, 2]));\n $mockRepo->method('getReportResultsQueryForRetention')->willReturn($mockQuery);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n Log::shouldReceive('info')->zeroOrMoreTimes();\n\n $result = $service->deleteReportsResultsInRetentionPeriod($mockTeam, $retentionDate);\n\n $this->assertEquals(0, $result);\n }\n\n public function testUpdateAskJiminnyReportStatusNotAskJiminny(): void\n {\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('isAskJiminnyReport')->willReturn(false);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $mockUser = $this->createMock(User::class);\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Report is not an Ask Jiminny report');\n\n $service->updateAskJiminnyReport($mockReport, [], $mockUser);\n }\n\n public function testUpdateAskJiminnyReportStatusThrowsWhenEnablingWithMissingReferences(): void\n {\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->expects($this->once())\n ->method('isAskJiminnyReport')\n ->willReturn(true);\n $mockReport->expects($this->once())\n ->method('canExecute')\n ->willReturn(false);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->never())->method('update');\n\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $property = $reflection->getProperty('automatedReportsRepository');\n $property->setAccessible(true);\n $property->setValue($this->service, $mockRepo);\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('This report is missing a saved search or prompt.');\n\n $this->service->updateAskJiminnyReportStatus($mockReport, true);\n }\n\n public function testUpdateAskJiminnyReportStatusDoesNotValidateWhenDisabling(): void\n {\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->expects($this->never())->method('isAskJiminnyReport');\n $mockReport->expects($this->never())->method('canExecute');\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('update')\n ->with($mockReport, ['status' => false])\n ->willThrowException(new \\RuntimeException('stop-after-update'));\n\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $property = $reflection->getProperty('automatedReportsRepository');\n $property->setAccessible(true);\n $property->setValue($this->service, $mockRepo);\n\n $this->expectException(\\RuntimeException::class);\n $this->expectExceptionMessage('stop-after-update');\n\n $this->service->updateAskJiminnyReportStatus($mockReport, false);\n }\n\n public function testGetAskJiminnyReportFilters(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $mockSearch = $this->createMock(Search::class);\n $mockSearch->method('getUuid')->willReturn('search-uuid-1');\n $mockSearch->method('getName')->willReturn('My Search');\n\n $mockSearchRepository = $this->createMock(SearchRepository::class);\n $mockSearchRepository->expects($this->once())\n ->method('findByUserOrderedByName')\n ->with($mockUser)\n ->willReturn(new Collection([$mockSearch]));\n\n $mockPromptDto = new AskAnythingPromptDto(\n id: 'prompt-uuid-1',\n title: 'My Prompt',\n content: 'Prompt text',\n target: AskAnythingPromptTarget::on_demand,\n );\n\n $mockPromptService = $this->createMock(AskAnythingPromptService::class);\n $mockPromptService->expects($this->once())\n ->method('get')\n ->with($mockUser, AskAnythingPromptTarget::on_demand)\n ->willReturn([$mockPromptDto]);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $mockPromptService,\n $mockSearchRepository,\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->getAskJiminnyReportFilters($mockUser);\n\n $this->assertCount(2, $result);\n $promptFilter = collect($result)->firstWhere('id', 'prompt');\n $searchFilter = collect($result)->firstWhere('id', 'saved_search');\n\n $this->assertCount(1, $promptFilter['options']);\n $this->assertEquals('prompt-uuid-1', $promptFilter['options'][0]['id']);\n $this->assertCount(1, $searchFilter['options']);\n $this->assertEquals('search-uuid-1', $searchFilter['options'][0]['id']);\n }\n\n public function testGetAskJiminnyReportFormDataWithoutReport(): void\n {\n $timezone = new \\DateTimeZone('UTC');\n\n $mockUser = $this->createMock(User::class);\n $mockUser->method('getTimezone')->willReturn($timezone);\n\n $mockTeam = $this->createMock(Team::class);\n $mockUser->method('getTeam')->willReturn($mockTeam);\n\n $mockSearchRepository = $this->createMock(SearchRepository::class);\n $mockSearchRepository->method('findByUserOrderedByName')->willReturn(new Collection([]));\n\n $mockPromptService = $this->createMock(AskAnythingPromptService::class);\n $mockPromptService->method('get')->willReturn([]);\n\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n $mockGroupRepository->method('getAllByTeam')->willReturn(new \\Illuminate\\Database\\Eloquent\\Collection([]));\n\n $mockRecipientsService = $this->createMock(RecipientsService::class);\n $mockRecipientsService->method('getRecipientsFieldData')->willReturn(['options' => []]);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $mockRecipientsService,\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $mockPromptService,\n $mockSearchRepository,\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->getAskJiminnyReportFormData($mockUser);\n\n $this->assertArrayHasKey('fields', $result);\n $this->assertIsArray($result['fields']);\n\n $fieldIds = array_column($result['fields'], 'id');\n $this->assertContains('enabled', $fieldIds);\n $this->assertContains('report_name', $fieldIds);\n $this->assertContains('frequency', $fieldIds);\n $this->assertContains('expires_on', $fieldIds);\n $this->assertContains('saved_search', $fieldIds);\n $this->assertContains('ask_jiminny_prompt', $fieldIds);\n }\n\n public function testGetAskJiminnyReportFormDataWithReport(): void\n {\n $timezone = new \\DateTimeZone('UTC');\n\n $mockUser = $this->createMock(User::class);\n $mockUser->method('getTimezone')->willReturn($timezone);\n\n $mockTeam = $this->createMock(Team::class);\n $mockUser->method('getTeam')->willReturn($mockTeam);\n\n $mockSavedSearch = $this->createMock(Search::class);\n $mockSavedSearch->method('getUuid')->willReturn('search-uuid');\n $mockSavedSearch->method('getName')->willReturn('My Search');\n\n $mockPromptModel = $this->createMock(AskAnythingPrompt::class);\n $mockPromptModel->method('getUuid')->willReturn('prompt-uuid');\n $mockPromptModel->method('getTitle')->willReturn('My Prompt');\n\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getStatus')->willReturn(true);\n $mockReport->method('getCustomName')->willReturn('Test Report');\n $mockReport->method('getFrequency')->willReturn('daily');\n $mockReport->method('getExpiresAt')->willReturn(IlluminateCarbon::parse('2025-12-31'));\n $mockReport->method('getGroups')->willReturn([]);\n $mockReport->method('getRecipients')->willReturn(['users' => []]);\n $mockReport->method('getAttribute')->with('created_by')->willReturn(1);\n $mockReport->method('getSavedSearch')->willReturn($mockSavedSearch);\n $mockReport->method('getAskAnythingPrompt')->willReturn($mockPromptModel);\n\n $mockSearchRepository = $this->createMock(SearchRepository::class);\n $mockSearchRepository->method('findByUserOrderedByName')->willReturn(new Collection([]));\n\n $mockPromptService = $this->createMock(AskAnythingPromptService::class);\n $mockPromptService->method('get')->willReturn([]);\n\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n $mockGroupRepository->method('getAllByTeam')->willReturn(new \\Illuminate\\Database\\Eloquent\\Collection([]));\n\n $mockRecipientsService = $this->createMock(RecipientsService::class);\n $mockRecipientsService->method('getRecipientsFieldData')->willReturn(['options' => []]);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $mockRecipientsService,\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $mockPromptService,\n $mockSearchRepository,\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->getAskJiminnyReportFormData($mockUser, $mockReport);\n\n $fields = collect($result['fields'])->keyBy('id');\n\n $this->assertTrue($fields['enabled']['value']);\n $this->assertEquals('Test Report', $fields['report_name']['value']);\n }\n\n public function testValidateAskJiminnyReportDataMissingName(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Report name is required');\n\n $service->createAskJiminnyReport(['report_name' => ''], $mockUser);\n }\n\n public function testValidateAskJiminnyReportDataNameTooLong(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Report name must be 50 characters or less');\n\n $service->createAskJiminnyReport(['report_name' => str_repeat('a', 51)], $mockUser);\n }\n\n public function testValidateAskJiminnyReportDataInvalidFrequency(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Frequency must be daily, weekly, or monthly');\n\n $service->createAskJiminnyReport(['report_name' => 'Valid Name', 'frequency' => 'quarterly'], $mockUser);\n }\n\n public function testValidateAskJiminnyReportDataMissingExpiresOn(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Expiration date is required');\n\n $service->createAskJiminnyReport(\n ['report_name' => 'Valid Name', 'frequency' => 'daily'],\n $mockUser\n );\n }\n\n public function testValidateAskJiminnyReportDataExpiresInPast(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Expiration date cannot be in the past');\n\n $service->createAskJiminnyReport(\n ['report_name' => 'Valid Name', 'frequency' => 'daily', 'expires_on' => '2020-01-01'],\n $mockUser\n );\n }\n\n public function testValidateAskJiminnyReportDataExpiresTooFar(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Expiration date cannot be more than 1 year from now');\n\n $service->createAskJiminnyReport(\n ['report_name' => 'Valid Name', 'frequency' => 'daily', 'expires_on' => '2099-01-01'],\n $mockUser\n );\n }\n\n public function testValidateAskJiminnyReportDataExpiresExactlyOneYearLaterTimeOfDayIsAccepted(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-04-20 09:00:00'));\n\n try {\n $mockUser = $this->createMock(User::class);\n $mockUser->method('getId')->willReturn(1);\n $mockUser->method('getTeamId')->willReturn(1);\n\n $savedSearch = $this->createMock(Search::class);\n $savedSearch->method('getId')->willReturn(10);\n\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->method('getId')->willReturn(5);\n\n $activitySearchRepository = $this->createMock(SearchRepository::class);\n $activitySearchRepository->method('findByUuidAndUser')->willReturn($savedSearch);\n\n $askAnythingRepository = $this->createMock(AskAnythingRepository::class);\n $askAnythingRepository->method('getPromptByUuid')->willReturn($prompt);\n\n $automatedReportsRepository = $this->createMock(AutomatedReportsRepository::class);\n $automatedReportsRepository->method('create')->willReturn($this->createMock(AutomatedReport::class));\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $automatedReportsRepository,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $activitySearchRepository,\n $askAnythingRepository,\n );\n\n $service->createAskJiminnyReport([\n 'report_name' => 'Valid Name',\n 'frequency' => 'daily',\n 'expires_on' => '2027-04-20T23:00:00',\n 'saved_search' => 'some-uuid',\n 'ask_jiminny_prompt' => 'prompt-uuid',\n ], $mockUser);\n\n $this->assertTrue(true);\n } finally {\n Carbon::setTestNow();\n }\n }\n\n public function testValidateAskJiminnyReportDataMissingSavedSearch(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Saved search is required');\n\n $service->createAskJiminnyReport(\n ['report_name' => 'Valid Name', 'frequency' => 'daily', 'expires_on' => now()->addMonth()->toDateString()],\n $mockUser\n );\n }\n\n public function testValidateAskJiminnyReportDataSavedSearchNotFound(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $mockSearchRepository = $this->createMock(SearchRepository::class);\n $mockSearchRepository->method('findByUuidAndUser')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $mockSearchRepository,\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Saved search not found or does not belong to you');\n\n $service->createAskJiminnyReport(\n [\n 'report_name' => 'Valid Name',\n 'frequency' => 'daily',\n 'expires_on' => now()->addMonth()->toDateString(),\n 'saved_search' => 'non-existent-uuid',\n ],\n $mockUser\n );\n }\n\n public function testValidateAskJiminnyReportDataMissingPrompt(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $mockSearch = $this->createMock(Search::class);\n $mockSearchRepository = $this->createMock(SearchRepository::class);\n $mockSearchRepository->method('findByUuidAndUser')->willReturn($mockSearch);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $mockSearchRepository,\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Ask Jiminny prompt is required');\n\n $service->createAskJiminnyReport(\n [\n 'report_name' => 'Valid Name',\n 'frequency' => 'daily',\n 'expires_on' => now()->addMonth()->toDateString(),\n 'saved_search' => 'search-uuid',\n ],\n $mockUser\n );\n }\n\n public function testValidateAskJiminnyReportDataPromptNotFound(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $mockSearch = $this->createMock(Search::class);\n $mockSearchRepository = $this->createMock(SearchRepository::class);\n $mockSearchRepository->method('findByUuidAndUser')->willReturn($mockSearch);\n\n $mockAskAnythingRepository = $this->createMock(AskAnythingRepository::class);\n $mockAskAnythingRepository->method('getPromptByUuid')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $mockSearchRepository,\n $mockAskAnythingRepository,\n );\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Ask Jiminny prompt not found');\n\n $service->createAskJiminnyReport(\n [\n 'report_name' => 'Valid Name',\n 'frequency' => 'daily',\n 'expires_on' => now()->addMonth()->toDateString(),\n 'saved_search' => 'search-uuid',\n 'ask_jiminny_prompt' => 'non-existent-prompt-uuid',\n ],\n $mockUser\n );\n }\n\n public function testTransformRecipientsWithNullUsers(): void\n {\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $method = $reflection->getMethod('transformRecipients');\n $method->setAccessible(true);\n\n $result = $method->invoke($this->service, []);\n\n $this->assertEquals([], $result);\n }\n\n public function testTransformRecipientsWithUsersKey(): void\n {\n $mockUser = $this->createMock(User::class);\n $mockUser->method('getUuid')->willReturn('user-uuid-1');\n $mockUser->method('getName')->willReturn('User One');\n $mockUser->method('getEmailAddress')->willReturn('user1@test.com');\n $mockUser->method('getPhotoUrl')->willReturn(null);\n\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturn($mockUser);\n\n $service = $this->getService(mockUserRepository: $mockUserRepository);\n\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $method = $reflection->getMethod('transformRecipients');\n $method->setAccessible(true);\n\n $result = $method->invoke($service, ['users' => [1]]);\n\n $this->assertCount(1, $result);\n $this->assertEquals('user-uuid-1', $result[0]['id']);\n }\n\n public function testGetTeamsGroupsOptions(): void\n {\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n\n $mockTeam = $this->createMock(Team::class);\n $mockTeam->method('getUuid')->willReturn('team-uuid-1');\n $mockTeam->method('getName')->willReturn('Sales Team');\n $mockTeam->method('hasFeature')\n ->with(FeatureEnum::AUTOMATED_REPORTS)\n ->willReturn(true);\n\n $mockGroupsRelation = $this->createMock(HasMany::class);\n $mockGroupsRelation->method('get')->willReturn(new \\Illuminate\\Database\\Eloquent\\Collection([]));\n $mockTeam->method('groups')->willReturn($mockGroupsRelation);\n\n $mockTeamRepository->method('getTeamsForKiosk')->willReturn(new Collection([$mockTeam]));\n $mockTeamRepository->method('idOrUuid')->willReturn($mockTeam);\n\n $service = $this->getService(mockTeamRepository: $mockTeamRepository);\n\n $result = $service->getTeamsGroupsOptions();\n\n $this->assertCount(1, $result);\n $this->assertEquals('Sales Team', $result[0]['label']);\n $this->assertArrayHasKey('groups', $result[0]);\n }\n\n public function testGetTeamsGroupsOptionsWithFilter(): void\n {\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n\n $mockTeam1 = $this->createMock(Team::class);\n $mockTeam1->method('getUuid')->willReturn('team-uuid-1');\n $mockTeam1->method('getName')->willReturn('Sales Team');\n $mockTeam1->method('hasFeature')->willReturn(true);\n\n $mockTeam2 = $this->createMock(Team::class);\n $mockTeam2->method('getUuid')->willReturn('team-uuid-2');\n $mockTeam2->method('getName')->willReturn('Marketing Team');\n $mockTeam2->method('hasFeature')->willReturn(true);\n\n $mockTeamRepository->method('getTeamsForKiosk')\n ->willReturn(new Collection([$mockTeam1, $mockTeam2]));\n\n $mockGroupsRelation = $this->createMock(HasMany::class);\n $mockGroupsRelation->method('get')->willReturn(new \\Illuminate\\Database\\Eloquent\\Collection([]));\n $mockTeam1->method('groups')->willReturn($mockGroupsRelation);\n\n $mockTeamRepository->method('idOrUuid')->willReturn($mockTeam1);\n\n $service = $this->getService(mockTeamRepository: $mockTeamRepository);\n\n $result = $service->getTeamsGroupsOptions(['team-uuid-1']);\n\n $this->assertCount(1, $result);\n $this->assertEquals('Sales Team', $result[0]['label']);\n }\n\n public function testGetReturnsTransformedReport(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getType')->willReturn('exec_summary');\n $mockReport->method('getUuid')->willReturn('report-uuid');\n $mockReport->method('getFrequency')->willReturn('weekly');\n $mockReport->method('getTeam')->willReturn($mockTeam);\n $mockReport->method('getStatus')->willReturn(true);\n $mockReport->method('getFrom')->willReturn(null);\n $mockReport->method('getTo')->willReturn(null);\n $mockReport->method('getDealValueMin')->willReturn(null);\n $mockReport->method('getDealValueMax')->willReturn(null);\n $mockReport->method('getCallTypes')->willReturn([]);\n $mockReport->method('getMediaTypes')->willReturn([]);\n $mockReport->method('getCallDurationMin')->willReturn(null);\n $mockReport->method('getCallDurationMax')->willReturn(null);\n $mockReport->method('getGroups')->willReturn([]);\n $mockReport->method('getDealAtCallStages')->willReturn([]);\n $mockReport->method('getCurrentDealStages')->willReturn([]);\n $mockReport->method('getRecipients')->willReturn([]);\n $mockReport->method('getCreator')->willReturn(null);\n $mockReport->method('getAdditionalPromptInput')->willReturn(null);\n $mockReport->method('getCustomName')->willReturn('My Report');\n $mockReport->method('getCreatedAt')->willReturn(IlluminateCarbon::parse('2025-01-01'));\n $mockReport->method('getUpdatedAt')->willReturn(IlluminateCarbon::parse('2025-01-01'));\n $mockReport->method('getDeletedAt')->willReturn(null);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('findByUuid')\n ->with('report-uuid')\n ->willReturn($mockReport);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->get('report-uuid');\n\n $this->assertIsArray($result);\n $this->assertEquals('report-uuid', $result['id']);\n }\n\n public function testGetThrowsWhenReportNotFound(): void\n {\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->method('findByUuid')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(ModelNotFoundException::class);\n\n $service->get('missing-uuid');\n }\n\n public function testListReturnsData(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getType')->willReturn('exec_summary');\n $mockReport->method('getUuid')->willReturn('report-uuid');\n $mockReport->method('getFrequency')->willReturn('weekly');\n $mockReport->method('getTeam')->willReturn($mockTeam);\n $mockReport->method('getStatus')->willReturn(true);\n $mockReport->method('getFrom')->willReturn(null);\n $mockReport->method('getTo')->willReturn(null);\n $mockReport->method('getDealValueMin')->willReturn(null);\n $mockReport->method('getDealValueMax')->willReturn(null);\n $mockReport->method('getCallTypes')->willReturn([]);\n $mockReport->method('getMediaTypes')->willReturn([]);\n $mockReport->method('getCallDurationMin')->willReturn(null);\n $mockReport->method('getCallDurationMax')->willReturn(null);\n $mockReport->method('getGroups')->willReturn([]);\n $mockReport->method('getDealAtCallStages')->willReturn([]);\n $mockReport->method('getCurrentDealStages')->willReturn([]);\n $mockReport->method('getRecipients')->willReturn([]);\n $mockReport->method('getCreator')->willReturn(null);\n $mockReport->method('getAdditionalPromptInput')->willReturn(null);\n $mockReport->method('getCustomName')->willReturn('My Report');\n $mockReport->method('getCreatedAt')->willReturn(IlluminateCarbon::parse('2025-01-01'));\n $mockReport->method('getUpdatedAt')->willReturn(IlluminateCarbon::parse('2025-01-01'));\n $mockReport->method('getDeletedAt')->willReturn(null);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('getAllStandardReports')\n ->willReturn(new \\Illuminate\\Database\\Eloquent\\Collection([$mockReport]));\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->list();\n\n $this->assertArrayHasKey('data', $result);\n $this->assertCount(1, $result['data']);\n }\n\n public function testListAskJiminnyReportsReturnsData(): void\n {\n $mockUser = $this->createMock(User::class);\n $mockTeam = $this->createMock(Team::class);\n\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getType')->willReturn('ask_jiminny');\n $mockReport->method('getUuid')->willReturn('report-uuid');\n $mockReport->method('getFrequency')->willReturn('daily');\n $mockReport->method('getTeam')->willReturn($mockTeam);\n $mockReport->method('getStatus')->willReturn(true);\n $mockReport->method('getGroups')->willReturn([]);\n $mockReport->method('getRecipients')->willReturn([]);\n $mockReport->method('getCustomName')->willReturn('AJ Report');\n $mockReport->method('getExpiresAt')->willReturn(null);\n $mockReport->method('getSavedSearch')->willReturn(null);\n $mockReport->method('getAskAnythingPrompt')->willReturn(null);\n $mockReport->method('getAttribute')->with('created_by')->willReturn(null);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('getAskJiminnyReportsByUser')\n ->with($mockUser, 'created_at', 'desc')\n ->willReturn(new \\Illuminate\\Database\\Eloquent\\Collection([$mockReport]));\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->listAskJiminnyReports($mockUser);\n\n $this->assertArrayHasKey('data', $result);\n $this->assertCount(1, $result['data']);\n }\n\n public function testGetActivityTypesFieldDataDelegatesToService(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $mockActivityTypeService = $this->createMock(ActivityTypeService::class);\n $mockActivityTypeService->expects($this->once())\n ->method('getActivityTypeFieldData')\n ->with(team: $mockTeam, value: ['a'], groupIds: ['g1'])\n ->willReturn(['id' => 'activity_types', 'options' => []]);\n\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $service = $reflection->newInstanceWithoutConstructor();\n $prop = $reflection->getProperty('activityTypeService');\n $prop->setAccessible(true);\n $prop->setValue($service, $mockActivityTypeService);\n\n $result = $service->getActivityTypesFieldData($mockTeam, ['a'], ['g1']);\n\n $this->assertEquals(['id' => 'activity_types', 'options' => []], $result);\n }\n\n public function testGetDealStageAtCallFieldDataDelegatesToService(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $mockDealStagesService = $this->createMock(DealStagesService::class);\n $mockDealStagesService->expects($this->once())\n ->method('getDealStageAtCallFieldData')\n ->with(team: $mockTeam, value: [])\n ->willReturn(['id' => 'deal_stage_at_call']);\n\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $service = $reflection->newInstanceWithoutConstructor();\n $prop = $reflection->getProperty('dealStagesService');\n $prop->setAccessible(true);\n $prop->setValue($service, $mockDealStagesService);\n\n $result = $service->getDealStageAtCallFieldData($mockTeam);\n\n $this->assertEquals(['id' => 'deal_stage_at_call'], $result);\n }\n\n public function testGetCurrentDealStageFieldDataDelegatesToService(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $mockDealStagesService = $this->createMock(DealStagesService::class);\n $mockDealStagesService->expects($this->once())\n ->method('getCurrentDealStageFieldData')\n ->with(team: $mockTeam, value: [])\n ->willReturn(['id' => 'current_deal_stage']);\n\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $service = $reflection->newInstanceWithoutConstructor();\n $prop = $reflection->getProperty('dealStagesService');\n $prop->setAccessible(true);\n $prop->setValue($service, $mockDealStagesService);\n\n $result = $service->getCurrentDealStageFieldData($mockTeam);\n\n $this->assertEquals(['id' => 'current_deal_stage'], $result);\n }\n\n public function testGetRecipientsFieldDataDelegatesToService(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $mockRecipientsService = $this->createMock(RecipientsService::class);\n $mockRecipientsService->expects($this->once())\n ->method('getRecipientsFieldData')\n ->with(team: $mockTeam, value: [])\n ->willReturn(['id' => 'recipients']);\n\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $service = $reflection->newInstanceWithoutConstructor();\n $prop = $reflection->getProperty('recipientsService');\n $prop->setAccessible(true);\n $prop->setValue($service, $mockRecipientsService);\n\n $result = $service->getRecipientsFieldData($mockTeam);\n\n $this->assertEquals(['id' => 'recipients'], $result);\n }\n\n public function testGetJiminnyRecipientsFieldDataDelegatesToService(): void\n {\n $mockRecipientsService = $this->createMock(RecipientsService::class);\n $mockRecipientsService->expects($this->once())\n ->method('getJiminnyRecipientsFieldData')\n ->with(['user-1'])\n ->willReturn(['id' => 'jiminny_recipients']);\n\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $service = $reflection->newInstanceWithoutConstructor();\n $prop = $reflection->getProperty('recipientsService');\n $prop->setAccessible(true);\n $prop->setValue($service, $mockRecipientsService);\n\n $result = $service->getJiminnyRecipientsFieldData(['user-1']);\n\n $this->assertEquals(['id' => 'jiminny_recipients'], $result);\n }\n\n public function testCreateReportResultDelegatesToRepository(): void\n {\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getId')->willReturn(42);\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('createResult')\n ->willReturn($mockResult);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->createReportResult($mockReport);\n\n $this->assertSame($mockResult, $result);\n }\n\n public function testDeleteReportResultDeletesS3AndModel(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getReport')->willReturn($this->createMock(AutomatedReport::class));\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PDF);\n $mockResult->expects($this->once())->method('delete');\n\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $service = $reflection->newInstanceWithoutConstructor();\n\n foreach ([\n 'teamRepository' => TeamRepository::class,\n 'groupRepository' => GroupRepository::class,\n 'userRepository' => UserRepository::class,\n 'stageRepository' => StageRepository::class,\n 'dealStagesService' => DealStagesService::class,\n 'recipientsService' => RecipientsService::class,\n 'automatedReportsRepository' => AutomatedReportsRepository::class,\n 'webhookService' => Webhook::class,\n 'dispatcher' => Dispatcher::class,\n 'activityTypeService' => ActivityTypeService::class,\n 'playbookCategoryRepository' => PlaybookCategoryRepository::class,\n 'askAnythingPromptService' => AskAnythingPromptService::class,\n 'activitySearchRepository' => SearchRepository::class,\n 'askAnythingRepository' => AskAnythingRepository::class,\n ] as $propName => $class) {\n $prop = $reflection->getProperty($propName);\n $prop->setAccessible(true);\n $prop->setValue($service, $this->createMock($class));\n }\n\n Storage::shouldReceive('exists')->andReturn(false);\n Log::shouldReceive('info')->zeroOrMoreTimes();\n\n $service->deleteReportResult($mockResult);\n }\n\n public function testDeleteAllReportResultsIteratesAndDeletes(): void\n {\n $mockResult1 = $this->createMock(AutomatedReportResult::class);\n $mockResult1->method('getId')->willReturn(1);\n $mockResult1->method('getReport')->willReturn($this->createMock(AutomatedReport::class));\n $mockResult1->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PDF);\n $mockResult1->expects($this->once())->method('delete');\n\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getId')->willReturn(10);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('getResultsByReport')\n ->with($mockReport)\n ->willReturn(new \\Illuminate\\Database\\Eloquent\\Collection([$mockResult1]));\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n Storage::shouldReceive('exists')->andReturn(false);\n Log::shouldReceive('info')->zeroOrMoreTimes();\n\n $service->deleteAllReportResults($mockReport);\n }\n\n public function testDeleteAllDataDeletesReportsAndResults(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getId')->willReturn(1);\n $mockResult->method('getReport')->willReturn($this->createMock(AutomatedReport::class));\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PDF);\n $mockResult->expects($this->once())->method('delete');\n\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getId')->willReturn(10);\n $mockReport->expects($this->once())->method('delete');\n\n $mockTeam = $this->createMock(Team::class);\n $mockTeam->method('getId')->willReturn(1);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('getReportsByTeam')\n ->with($mockTeam)\n ->willReturn(new \\Illuminate\\Database\\Eloquent\\Collection([$mockReport]));\n $mockRepo->expects($this->once())\n ->method('getResultsByReport')\n ->with($mockReport)\n ->willReturn(new \\Illuminate\\Database\\Eloquent\\Collection([$mockResult]));\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n Storage::shouldReceive('exists')->andReturn(false);\n Log::shouldReceive('info')->zeroOrMoreTimes();\n\n $service->deleteAllData($mockTeam);\n }\n\n public function testDeleteReportResultsThrowsWhenReportNotFound(): void\n {\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->method('findByUuid')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(ModelNotFoundException::class);\n\n $service->deleteReportResults('missing-uuid');\n }\n\n public function testGetValidRecipientUsersAskJiminnyIncludesCreator(): void\n {\n $tz = $this->createMock(\\DateTimeZone::class);\n $tz->method('getName')->willReturn('UTC');\n\n $creator = $this->createMock(User::class);\n $creator->method('getEmailAddress')->willReturn('creator@test.com');\n $creator->method('getName')->willReturn('Creator');\n $creator->method('getTimezone')->willReturn($tz);\n\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturn($creator);\n\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n $mockGroupRepository->method('find')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $mockUserRepository,\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getRecipients')->willReturn(['users' => []]);\n $report->method('getGroups')->willReturn([]);\n\n $result = $service->getValidRecipientUsers($report);\n\n $this->assertCount(1, $result);\n $this->assertEquals('creator@test.com', $result[0]['email']);\n }\n\n public function testGetValidRecipientUsersAskJiminnyDeduplicatesCreatorAndExplicitRecipient(): void\n {\n $tz = $this->createMock(\\DateTimeZone::class);\n $tz->method('getName')->willReturn('UTC');\n\n $creator = $this->createMock(User::class);\n $creator->method('getEmailAddress')->willReturn('shared@test.com');\n $creator->method('getName')->willReturn('Creator');\n $creator->method('getTimezone')->willReturn($tz);\n\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturn($creator);\n\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n $mockGroupRepository->method('find')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $mockUserRepository,\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getRecipients')->willReturn(['users' => [1]]);\n $report->method('getGroups')->willReturn([]);\n\n $result = $service->getValidRecipientUsers($report);\n\n $this->assertCount(1, $result);\n $this->assertEquals('shared@test.com', $result[0]['email']);\n }\n\n public function testGetValidRecipientUsersAskJiminnyIncludesGroupMembers(): void\n {\n $tz = $this->createMock(\\DateTimeZone::class);\n $tz->method('getName')->willReturn('UTC');\n\n $creator = $this->createMock(User::class);\n $creator->method('getEmailAddress')->willReturn('creator@test.com');\n $creator->method('getName')->willReturn('Creator');\n $creator->method('getTimezone')->willReturn($tz);\n\n $member = $this->createMock(User::class);\n $member->method('getEmailAddress')->willReturn('member@test.com');\n $member->method('getName')->willReturn('Member');\n $member->method('getTimezone')->willReturn($tz);\n\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturn($creator);\n\n $mockGroup = $this->createMock(Group::class);\n $mockGroup->method('getMembers')->willReturn(new \\Illuminate\\Database\\Eloquent\\Collection([$member]));\n\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n $mockGroupRepository->method('find')->willReturn($mockGroup);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $mockUserRepository,\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getRecipients')->willReturn(['users' => []]);\n $report->method('getGroups')->willReturn([10]);\n\n $result = $service->getValidRecipientUsers($report);\n\n $this->assertCount(2, $result);\n $emails = array_column($result, 'email');\n $this->assertContains('creator@test.com', $emails);\n $this->assertContains('member@test.com', $emails);\n }\n\n public function testGetValidRecipientUsersAskJiminnyNullCreatorSkipped(): void\n {\n $tz = $this->createMock(\\DateTimeZone::class);\n $tz->method('getName')->willReturn('UTC');\n\n $shareUser = $this->createMock(User::class);\n $shareUser->method('getEmailAddress')->willReturn('shared@test.com');\n $shareUser->method('getName')->willReturn('Shared');\n $shareUser->method('getTimezone')->willReturn($tz);\n\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturnMap([\n [1, null],\n [2, $shareUser],\n ]);\n\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n $mockGroupRepository->method('find')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $mockUserRepository,\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn(null);\n $report->method('getRecipients')->willReturn(['users' => [2]]);\n $report->method('getGroups')->willReturn([]);\n\n $result = $service->getValidRecipientUsers($report);\n\n $this->assertCount(1, $result);\n $this->assertEquals('shared@test.com', $result[0]['email']);\n }\n\n public function testGetValidRecipientUsersStandardReportDoesNotIncludeCreator(): void\n {\n $tz = $this->createMock(\\DateTimeZone::class);\n $tz->method('getName')->willReturn('UTC');\n\n $user = $this->createMock(User::class);\n $user->method('getEmailAddress')->willReturn('user@test.com');\n $user->method('getName')->willReturn('User');\n $user->method('getTimezone')->willReturn($tz);\n\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturn($user);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $mockUserRepository,\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(false);\n $report->method('getRecipients')->willReturn(['users' => [5]]);\n $report->method('getJiminnyRecipients')->willReturn(['users' => []]);\n $report->method('getGroups')->willReturn([]);\n\n $result = $service->getValidRecipientUsers($report);\n\n $this->assertCount(1, $result);\n $this->assertEquals('user@test.com', $result[0]['email']);\n }\n\n public function testGetReportPeriodNameAskJiminnyMonthlyFallback(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-03-07 00:00:00'));\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getFrequency')->willReturn('monthly');\n $report->method('isAskJiminnyReport')->willReturn(true);\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getReport')->willReturn($report);\n $mockResult->method('getFromDate')->willReturn(null);\n $mockResult->method('getToDate')->willReturn(null);\n\n $result = $this->service->getReportPeriodName($mockResult);\n\n $this->assertMatchesRegularExpression('/^[A-Z][a-z]+ \\d{4}$/', $result);\n $this->assertStringContainsString('2026', $result);\n\n Carbon::setTestNow();\n }\n\n public function testGetReportPeriodNameAskJiminnyWeeklyFallback(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-04-07 00:00:00'));\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getFrequency')->willReturn('weekly');\n $report->method('isAskJiminnyReport')->willReturn(true);\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getReport')->willReturn($report);\n $mockResult->method('getFromDate')->willReturn(null);\n $mockResult->method('getToDate')->willReturn(null);\n\n $result = $this->service->getReportPeriodName($mockResult);\n\n $this->assertStringContainsString(' - ', $result);\n $this->assertStringContainsString('2026', $result);\n\n Carbon::setTestNow();\n }\n\n public function testGetReportPeriodNameAskJiminnyDailyFallback(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-04-07 00:00:00'));\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('isAskJiminnyReport')->willReturn(true);\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getReport')->willReturn($report);\n $mockResult->method('getFromDate')->willReturn(null);\n $mockResult->method('getToDate')->willReturn(null);\n\n $result = $this->service->getReportPeriodName($mockResult);\n\n $this->assertStringNotContainsString(' - ', $result);\n $this->assertStringContainsString('2026', $result);\n\n Carbon::setTestNow();\n }\n\n public function testGetReportPeriodNameAskJiminnyWithExplicitDates(): void\n {\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getFrequency')->willReturn('monthly');\n $report->method('isAskJiminnyReport')->willReturn(true);\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getReport')->willReturn($report);\n $mockResult->method('getFromDate')->willReturn(IlluminateCarbon::parse('2026-02-07'));\n $mockResult->method('getToDate')->willReturn(IlluminateCarbon::parse('2026-03-07'));\n\n $result = $this->service->getReportPeriodName($mockResult);\n\n $this->assertEquals('Feb 2026', $result);\n }\n\n public function testGetReportThrowsWhenNotFound(): void\n {\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $property = $reflection->getProperty('automatedReportsRepository');\n $property->setAccessible(true);\n /** @var AutomatedReportsRepository&\\PHPUnit\\Framework\\MockObject\\MockObject $mockRepo */\n $mockRepo = $property->getValue($this->service);\n\n $mockRepo->expects($this->once())\n ->method('findByUuid')\n ->with('missing-uuid')\n ->willReturn(null);\n\n $this->expectException(ModelNotFoundException::class);\n $this->service->getReport('missing-uuid');\n }\n\n public function testGetReportWithDefaultPartnerSkipsPartnerCheck(): void\n {\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $property = $reflection->getProperty('automatedReportsRepository');\n $property->setAccessible(true);\n /** @var AutomatedReportsRepository&\\PHPUnit\\Framework\\MockObject\\MockObject $mockRepo */\n $mockRepo = $property->getValue($this->service);\n\n $report = new AutomatedReport();\n $mockRepo->expects($this->once())\n ->method('findByUuid')\n ->willReturn($report);\n\n $partner = $this->createMock(Partner::class);\n $partner->method('isDefaultPartner')->willReturn(true);\n\n $result = $this->service->getReport('some-uuid', $partner);\n $this->assertSame($report, $result);\n }\n\n public function testGetReportWithNonDefaultPartnerAndMatchingPartnerIdReturnsReport(): void\n {\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $property = $reflection->getProperty('automatedReportsRepository');\n $property->setAccessible(true);\n /** @var AutomatedReportsRepository&\\PHPUnit\\Framework\\MockObject\\MockObject $mockRepo */\n $mockRepo = $property->getValue($this->service);\n\n $partnerId = 5;\n $team = new Team();\n $team->partner_id = $partnerId;\n\n $report = new AutomatedReport();\n $report->setRelation('team', $team);\n\n $mockRepo->expects($this->once())\n ->method('findByUuid')\n ->willReturn($report);\n\n $partner = $this->createMock(Partner::class);\n $partner->method('isDefaultPartner')->willReturn(false);\n $partner->method('getId')->willReturn($partnerId);\n\n $result = $this->service->getReport('some-uuid', $partner);\n $this->assertSame($report, $result);\n }\n\n public function testGetReportWithNonDefaultPartnerAndMismatchedPartnerIdThrows(): void\n {\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $property = $reflection->getProperty('automatedReportsRepository');\n $property->setAccessible(true);\n /** @var AutomatedReportsRepository&\\PHPUnit\\Framework\\MockObject\\MockObject $mockRepo */\n $mockRepo = $property->getValue($this->service);\n\n $team = new Team();\n $team->partner_id = 5;\n\n $report = new AutomatedReport();\n $report->setRelation('team', $team);\n\n $mockRepo->expects($this->once())\n ->method('findByUuid')\n ->willReturn($report);\n\n $partner = $this->createMock(Partner::class);\n $partner->method('isDefaultPartner')->willReturn(false);\n $partner->method('getId')->willReturn(2);\n\n $this->expectException(ModelNotFoundException::class);\n $this->service->getReport('some-uuid', $partner);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Services\\Kiosk\\AutomatedReports;\n\nuse Carbon\\Carbon;\nuse Illuminate\\Support\\Carbon as IlluminateCarbon;\nuse Illuminate\\Contracts\\Bus\\Dispatcher;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Database\\Eloquent\\Relations\\HasMany;\nuse Illuminate\\Support\\Facades\\Log;\nuse Illuminate\\Support\\Facades\\Storage;\nuse Jiminny\\Component\\AskAnything\\AskAnythingPromptService;\nuse Jiminny\\Component\\AskAnything\\Dtos\\AskAnythingPromptDto;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Contracts\\Repositories\\PlaybookCategoryRepository;\nuse Jiminny\\Contracts\\Repositories\\TeamRepository;\nuse Jiminny\\Contracts\\Repositories\\UserRepository;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Exceptions\\ModelNotFoundException;\nuse Illuminate\\Support\\Collection;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPrompt;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPromptTarget;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Group;\nuse Jiminny\\Models\\Partner;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AskAnythingRepository;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Repositories\\GroupRepository;\nuse Jiminny\\Repositories\\SearchRepository;\nuse Jiminny\\Repositories\\StageRepository;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\ActivityTypeService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\AutomatedReportsService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\DealStagesService;\nuse Jiminny\\Services\\Kiosk\\AutomatedReports\\RecipientsService;\nuse Mockery;\nuse PHPUnit\\Framework\\Attributes\\DataProvider;\nuse Tests\\TestCase;\n\nclass AutomatedReportsServiceTest extends TestCase\n{\n private AutomatedReportsService $service;\n\n protected function setUp(): void\n {\n parent::setUp();\n\n // Create a real instance of the service without calling the constructor\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $this->service = $reflection->newInstanceWithoutConstructor();\n\n // Manually set the dependencies using reflection\n $dependencies = [\n 'teamRepository' => TeamRepository::class,\n 'groupRepository' => GroupRepository::class,\n 'userRepository' => UserRepository::class,\n 'stageRepository' => StageRepository::class,\n 'dealStagesService' => DealStagesService::class,\n 'recipientsService' => RecipientsService::class,\n 'automatedReportsRepository' => AutomatedReportsRepository::class,\n 'webhookService' => Webhook::class,\n 'dispatcher' => Dispatcher::class,\n 'activityTypeService' => ActivityTypeService::class,\n 'playbookCategoryRepository' => PlaybookCategoryRepository::class,\n 'askAnythingPromptService' => AskAnythingPromptService::class,\n 'activitySearchRepository' => SearchRepository::class,\n 'askAnythingRepository' => AskAnythingRepository::class,\n ];\n\n foreach ($dependencies as $propertyName => $class) {\n $property = $reflection->getProperty($propertyName);\n $property->setAccessible(true);\n $property->setValue($this->service, $this->createMock($class));\n }\n }\n\n protected function tearDown(): void\n {\n parent::tearDown();\n Mockery::close();\n }\n\n private function getService(\n $mockUserRepository = null,\n $mockStageRepository = null,\n $mockTeamRepository = null,\n ): AutomatedReportsService {\n return new AutomatedReportsService(\n ($mockTeamRepository ?? $this->createMock(TeamRepository::class)),\n $this->createMock(GroupRepository::class),\n ($mockUserRepository ?? $this->createMock(UserRepository::class)),\n ($mockStageRepository ?? $this->createMock(StageRepository::class)),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n }\n\n #[DataProvider('transformMediaTypesDataProvider')]\n public function testTransformMediaTypes(array $mediaTypes, array $expected): void\n {\n $report = new AutomatedReport(['media_types' => $mediaTypes]);\n\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $method = $reflection->getMethod('transformMediaTypes');\n\n $result = $method->invoke($this->service, $report);\n\n $this->assertEquals($expected, $result);\n }\n\n public function testGetMediaTypeFieldDataWithoutReport(): void\n {\n $result = $this->service->getMediaTypeFieldData(null);\n\n $this->assertIsArray($result);\n $this->assertArrayHasKey('value', $result);\n $this->assertEmpty($result['value']);\n $this->assertEquals('media_types', $result['id']);\n }\n\n public function testGetMediaTypeFieldDataWithReport(): void\n {\n $mediaTypes = ['pdf', 'podcast'];\n $report = new AutomatedReport(['media_types' => $mediaTypes]);\n\n $result = $this->service->getMediaTypeFieldData($report);\n\n $expectedValue = [\n ['id' => 'pdf', 'name' => 'PDF'],\n ['id' => 'podcast', 'name' => 'Podcast'],\n ];\n\n $this->assertIsArray($result);\n $this->assertArrayHasKey('value', $result);\n $this->assertEquals($expectedValue, $result['value']);\n }\n\n public static function transformMediaTypesDataProvider(): array\n {\n return [\n 'empty array' => [\n 'mediaTypes' => [],\n 'expected' => [],\n ],\n 'pdf only' => [\n 'mediaTypes' => ['pdf'],\n 'expected' => [\n ['id' => 'pdf', 'name' => 'PDF'],\n ],\n ],\n 'podcast only' => [\n 'mediaTypes' => ['podcast'],\n 'expected' => [\n ['id' => 'podcast', 'name' => 'Podcast'],\n ],\n ],\n 'both pdf and podcast' => [\n 'mediaTypes' => ['pdf', 'podcast'],\n 'expected' => [\n ['id' => 'pdf', 'name' => 'PDF'],\n ['id' => 'podcast', 'name' => 'Podcast'],\n ],\n ],\n 'with invalid type' => [\n 'mediaTypes' => ['pdf', 'invalid', 'podcast'],\n 'expected' => [\n ['id' => 'pdf', 'name' => 'PDF'],\n ['id' => 'podcast', 'name' => 'Podcast'],\n ],\n ],\n ];\n }\n\n #[DataProvider('hasCallTypeConferenceDataProvider')]\n public function testHasCallTypeConference(array $callTypes, bool $expected): void\n {\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getCallTypes')->willReturn($callTypes);\n\n $result = $this->service->hasCallTypeConference($report);\n\n $this->assertEquals($expected, $result);\n }\n\n #[DataProvider('hasCallTypeDialerDataProvider')]\n public function testHasCallTypeDialer(array $callTypes, bool $expected): void\n {\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getCallTypes')->willReturn($callTypes);\n\n $result = $this->service->hasCallTypeDialer($report);\n\n $this->assertEquals($expected, $result);\n }\n\n public static function hasCallTypeConferenceDataProvider(): array\n {\n return [\n 'has conference' => [\n 'callTypes' => ['conference', 'dialer'],\n 'expected' => true,\n ],\n 'does not have conference' => [\n 'callTypes' => ['dialer', 'other'],\n 'expected' => false,\n ],\n 'empty call types' => [\n 'callTypes' => [],\n 'expected' => false,\n ],\n ];\n }\n\n public static function hasCallTypeDialerDataProvider(): array\n {\n return [\n 'has dialer' => [\n 'callTypes' => ['conference', 'dialer'],\n 'expected' => true,\n ],\n 'does not have dialer' => [\n 'callTypes' => ['conference', 'other'],\n 'expected' => false,\n ],\n 'empty call types' => [\n 'callTypes' => [],\n 'expected' => false,\n ],\n ];\n }\n\n public function testTransformReportResultsWithEmptyCollection(): void\n {\n $emptyCollection = new Collection([]);\n\n $result = $this->service->transformReportResults($emptyCollection);\n\n $this->assertIsArray($result);\n $this->assertEmpty($result);\n }\n\n public function testTransformReportResultsStructure(): void\n {\n // Create a mock AutomatedReportResult with minimal setup to test structure\n $mockReportResult = $this->createMockReportResult();\n $collection = new Collection([$mockReportResult]);\n\n $result = $this->service->transformReportResults($collection);\n\n $this->assertIsArray($result);\n $this->assertCount(1, $result);\n\n $transformedResult = $result[0];\n\n // Verify all expected keys are present\n $expectedKeys = [\n 'id', 'name', 'frequency', 'recipients',\n 'report_type', 'media_type', 'downloadUrl', 'viewUrl', 'generated_at',\n ];\n\n foreach ($expectedKeys as $key) {\n $this->assertArrayHasKey($key, $transformedResult);\n }\n\n // Verify structure of nested arrays\n $this->assertIsArray($transformedResult['frequency']);\n $this->assertArrayHasKey('id', $transformedResult['frequency']);\n $this->assertArrayHasKey('name', $transformedResult['frequency']);\n\n $this->assertIsArray($transformedResult['report_type']);\n $this->assertArrayHasKey('id', $transformedResult['report_type']);\n $this->assertArrayHasKey('name', $transformedResult['report_type']);\n\n $this->assertIsArray($transformedResult['recipients']);\n\n // Verify TODO fields are null as expected\n $this->assertEquals(AutomatedReportsService::MEDIA_TYPE_PODCAST, $transformedResult['media_type']);\n $this->assertEquals(route('ai-reports.audio.download', ['uuid' => 'test-uuid']), $transformedResult['downloadUrl']);\n $this->assertEquals(route('ai-reports.audio.view', ['uuid' => 'test-uuid']), $transformedResult['viewUrl']);\n }\n\n public function testTransformReportResultsWithMultipleResults(): void\n {\n $mockReportResult1 = $this->createMockReportResult('result-uuid-1', 'exec_summary');\n $mockReportResult2 = $this->createMockReportResult('result-uuid-2', 'coaching_profiles');\n $collection = new Collection([$mockReportResult1, $mockReportResult2]);\n\n $result = $this->service->transformReportResults($collection);\n\n $this->assertIsArray($result);\n $this->assertCount(2, $result);\n\n // Verify different UUIDs\n $this->assertEquals('result-uuid-1', $result[0]['id']);\n $this->assertEquals('result-uuid-2', $result[1]['id']);\n\n // Verify both results have the expected structure\n foreach ($result as $transformedResult) {\n $this->assertArrayHasKey('id', $transformedResult);\n $this->assertArrayHasKey('name', $transformedResult);\n $this->assertArrayHasKey('frequency', $transformedResult);\n $this->assertArrayHasKey('recipients', $transformedResult);\n $this->assertArrayHasKey('report_type', $transformedResult);\n }\n }\n\n #[DataProvider('isUserRecipientOfReportDataProvider')]\n public function testIsUserRecipientOfReport(int $userId, array $recipients, bool $expected): void\n {\n // Create mock User\n $mockUser = $this->createMock(\\Jiminny\\Models\\User::class);\n $mockUser->method('getId')->willReturn($userId);\n $mockUser->method('getGroupId')->willReturn(null);\n\n // Create mock AutomatedReport\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getRecipients')->willReturn($recipients);\n $mockReport->method('isAskJiminnyReport')->willReturn(false);\n $mockReport->method('getGroups')->willReturn([]);\n\n $result = $this->service->isUserRecipientOfReport($mockUser, $mockReport);\n\n $this->assertEquals($expected, $result);\n }\n\n #[DataProvider('isUserRecipientOfAskJiminnyReportDataProvider')]\n public function testIsUserRecipientOfAskJiminnyReportViaGroup(\n int $userId,\n ?int $groupId,\n array $recipients,\n array $reportGroups,\n bool $expected,\n ): void {\n $mockUser = $this->createMock(\\Jiminny\\Models\\User::class);\n $mockUser->method('getId')->willReturn($userId);\n $mockUser->method('getGroupId')->willReturn($groupId);\n\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getRecipients')->willReturn($recipients);\n $mockReport->method('isAskJiminnyReport')->willReturn(true);\n $mockReport->method('getGroups')->willReturn($reportGroups);\n\n $this->assertSame($expected, $this->service->isUserRecipientOfReport($mockUser, $mockReport));\n }\n\n public function testIsUserRecipientOfNonAskJiminnyReportIgnoresGroups(): void\n {\n $mockUser = $this->createMock(\\Jiminny\\Models\\User::class);\n $mockUser->method('getId')->willReturn(123);\n $mockUser->method('getGroupId')->willReturn(5);\n\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getRecipients')->willReturn(['users' => []]);\n $mockReport->method('isAskJiminnyReport')->willReturn(false);\n $mockReport->method('getGroups')->willReturn([5]);\n\n $this->assertFalse($this->service->isUserRecipientOfReport($mockUser, $mockReport));\n }\n\n public static function isUserRecipientOfAskJiminnyReportDataProvider(): array\n {\n return [\n 'group member - ask jiminny' => [\n 'userId' => 123,\n 'groupId' => 7,\n 'recipients' => ['users' => []],\n 'reportGroups' => [7],\n 'expected' => true,\n ],\n 'group mismatch - ask jiminny' => [\n 'userId' => 123,\n 'groupId' => 9,\n 'recipients' => ['users' => []],\n 'reportGroups' => [7, 8],\n 'expected' => false,\n ],\n 'user with no group - ask jiminny' => [\n 'userId' => 123,\n 'groupId' => null,\n 'recipients' => ['users' => []],\n 'reportGroups' => [7],\n 'expected' => false,\n ],\n 'recipient users take precedence over group' => [\n 'userId' => 123,\n 'groupId' => null,\n 'recipients' => ['users' => [123]],\n 'reportGroups' => [],\n 'expected' => true,\n ],\n ];\n }\n\n public function testIsUserRecipientOfReportWithEmptyRecipients(): void\n {\n // Create mock User\n $mockUser = $this->createMock(\\Jiminny\\Models\\User::class);\n $mockUser->method('getId')->willReturn(123);\n\n // Create mock AutomatedReport with no recipients\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getRecipients')->willReturn([]);\n\n $result = $this->service->isUserRecipientOfReport($mockUser, $mockReport);\n\n $this->assertFalse($result);\n }\n\n public function testIsUserRecipientOfReportWithNoUsersKey(): void\n {\n // Create mock User\n $mockUser = $this->createMock(\\Jiminny\\Models\\User::class);\n $mockUser->method('getId')->willReturn(123);\n\n // Create mock AutomatedReport with recipients but no 'users' key\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getRecipients')->willReturn(['other_key' => [456, 789]]);\n\n $result = $this->service->isUserRecipientOfReport($mockUser, $mockReport);\n\n $this->assertFalse($result);\n }\n\n public static function isUserRecipientOfReportDataProvider(): array\n {\n return [\n 'user is recipient - single user' => [\n 'userId' => 123,\n 'recipients' => ['users' => [123]],\n 'expected' => true,\n ],\n 'user is recipient - multiple users' => [\n 'userId' => 456,\n 'recipients' => ['users' => [123, 456, 789]],\n 'expected' => true,\n ],\n 'user is not recipient - single user' => [\n 'userId' => 999,\n 'recipients' => ['users' => [123]],\n 'expected' => false,\n ],\n 'user is not recipient - multiple users' => [\n 'userId' => 999,\n 'recipients' => ['users' => [123, 456, 789]],\n 'expected' => false,\n ],\n 'user is recipient - string IDs converted to int' => [\n 'userId' => 123,\n 'recipients' => ['users' => ['123', '456']],\n 'expected' => true,\n ],\n 'user is not recipient - string IDs converted to int' => [\n 'userId' => 999,\n 'recipients' => ['users' => ['123', '456']],\n 'expected' => false,\n ],\n 'empty users array' => [\n 'userId' => 123,\n 'recipients' => ['users' => []],\n 'expected' => false,\n ],\n ];\n }\n\n private function createMockReportResult(string $uuid = 'test-uuid', string $reportType = 'exec_summary'): AutomatedReportResult\n {\n // Create mock AutomatedReport\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getFrequency')->willReturn('weekly');\n $mockReport->method('getRecipients')->willReturn(['users' => [1, 2]]);\n $mockReport->method('getGroups')->willReturn([10, 20]);\n $mockReport->method('getType')->willReturn($reportType);\n\n // Create mock Team\n $mockTeam = $this->createMock(\\Jiminny\\Models\\Team::class);\n\n // Create mock Group\n $mockGroup = $this->createMock(\\Jiminny\\Models\\Group::class);\n $mockGroup->method('getUuid')->willReturn('group-uuid-10');\n $mockGroup->method('getName')->willReturn('Test Team');\n\n $mockQueryBuilder = Mockery::mock();\n $mockQueryBuilder->shouldReceive('where')->andReturnSelf();\n $mockQueryBuilder->shouldReceive('first')->andReturn($mockGroup);\n\n $dataRelation = Mockery::mock(HasMany::class);\n $dataRelation->shouldReceive('where')->andReturn($mockQueryBuilder);\n $dataRelation->shouldReceive('get')->andReturn(\n new \\Illuminate\\Database\\Eloquent\\Collection([$mockGroup])\n );\n\n $mockTeam->method('groups')->willReturn($dataRelation);\n $mockReport->method('getTeam')->willReturn($mockTeam);\n\n // Create mock AutomatedReportResult\n $mockReportResult = $this->createMock(AutomatedReportResult::class);\n $mockReportResult->method('getUuid')->willReturn($uuid);\n $mockReportResult->method('getGeneratedAt')->willReturn(\n \\Illuminate\\Support\\Carbon::parse('2024-01-15T10:30:00Z')\n );\n\n $mockReportResult->method('getReport')->willReturn($mockReport);\n\n // Mock methods used in getReportFileName\n $mockReportResult->method('getReportType')->willReturn($reportType);\n $mockReportResult->method('getFromDate')->willReturn(\n \\Illuminate\\Support\\Carbon::parse('2024-01-08')\n );\n $mockReportResult->method('getToDate')->willReturn(\n \\Illuminate\\Support\\Carbon::parse('2024-01-15')\n );\n $mockReportResult->method('getGroups')->willReturn([10]);\n $mockReportResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PODCAST);\n\n return $mockReportResult;\n }\n\n #[DataProvider('getUsersUuidsDataProvider')]\n public function testGetUsersUuids(array $recipients, array $mockUsers, array $expectedUuids): void\n {\n // Create mock UserRepository\n $mockUserRepository = $this->createMock(UserRepository::class);\n\n // Configure the mock to return specific users for specific IDs using a callback\n $mockUserRepository->method('find')\n ->willReturnCallback(function ($userId) use ($mockUsers) {\n if (! isset($mockUsers[$userId])) {\n return null;\n }\n\n $userUuid = $mockUsers[$userId]['uuid'] ?? null;\n\n if ($userUuid === null) {\n return null;\n }\n\n $mockUser = $this->createMock(\\Jiminny\\Models\\User::class);\n $mockUser->method('getUuid')->willReturn((string) $userUuid);\n\n return $mockUser;\n });\n\n // Create service with mocked UserRepository\n $automatedReportsService = $this->getService(mockUserRepository: $mockUserRepository);\n\n // Create mock AutomatedReport\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getRecipients')->willReturn($recipients);\n\n $result = $automatedReportsService->getUsersUuids($mockReport);\n\n $this->assertEquals($expectedUuids, $result);\n }\n\n public function testGetUsersUuidsWithEmptyRecipients(): void\n {\n // Create mock AutomatedReport with empty recipients\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getRecipients')->willReturn([]);\n\n $result = $this->service->getUsersUuids($mockReport);\n\n $this->assertEquals([], $result);\n }\n\n public function testGetUsersUuidsWithNoUsersKey(): void\n {\n // Create mock AutomatedReport with recipients but no 'users' key\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getRecipients')->willReturn(['other_key' => [1, 2, 3]]);\n\n $result = $this->service->getUsersUuids($mockReport);\n\n $this->assertEquals([], $result);\n }\n\n public function testGetUsersUuidsWithNonExistentUsers(): void\n {\n // Create mock UserRepository that returns null for all users\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturn(null);\n\n // Create service with mocked UserRepository\n $automatedReportsService = $this->getService(mockUserRepository: $mockUserRepository);\n\n // Create mock AutomatedReport\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getRecipients')->willReturn(['users' => [1, 2, 3]]);\n\n $result = $automatedReportsService->getUsersUuids($mockReport);\n\n // Should return array with null values for non-existent users\n $this->assertEquals([], $result);\n }\n\n public static function getUsersUuidsDataProvider(): array\n {\n return [\n 'single user found' => [\n 'recipients' => ['users' => [123]],\n 'mockUsers' => [\n 123 => ['id' => 123, 'uuid' => 'user-uuid-123'],\n ],\n 'expectedUuids' => ['user-uuid-123'],\n ],\n 'multiple users found' => [\n 'recipients' => ['users' => [123, 456, 789]],\n 'mockUsers' => [\n 123 => ['id' => 123, 'uuid' => 'user-uuid-123'],\n 456 => ['id' => 456, 'uuid' => 'user-uuid-456'],\n 789 => ['id' => 789, 'uuid' => 'user-uuid-789'],\n ],\n 'expectedUuids' => ['user-uuid-123', 'user-uuid-456', 'user-uuid-789'],\n ],\n 'mixed found and not found users' => [\n 'recipients' => ['users' => [123, 456, 789]],\n 'mockUsers' => [\n 123 => ['id' => 123, 'uuid' => 'user-uuid-123'],\n // 456 not found in DB\n 789 => ['id' => 789, 'uuid' => 'user-uuid-789'],\n ],\n 'expectedUuids' => ['user-uuid-123', 'user-uuid-789'], // Updated to reflect that nulls are filtered out\n ],\n 'empty users array' => [\n 'recipients' => ['users' => []],\n 'mockUsers' => [],\n 'expectedUuids' => [],\n ],\n 'all users not found' => [\n 'recipients' => ['users' => [123, 456]],\n 'mockUsers' => [], // No users found\n 'expectedUuids' => [], // Updated to reflect that nulls are filtered out\n ],\n ];\n }\n\n #[DataProvider('getCurrentDealStagesUuidsDataProvider')]\n public function testGetCurrentDealStagesUuids(array $currentDealStages, array $mockStages, array $expectedUuids): void\n {\n // Create mock StageRepository\n $mockStageRepository = $this->createMock(StageRepository::class);\n\n // Configure the mock to return specific stages for specific IDs using a callback\n $mockStageRepository->method('find')\n ->willReturnCallback(function ($stageId) use ($mockStages) {\n if (! isset($mockStages[$stageId])) {\n return null;\n }\n\n $stageUuid = $mockStages[$stageId]['uuid'] ?? null;\n\n if ($stageUuid === null) {\n return null;\n }\n\n $mockStage = $this->createMock(\\Jiminny\\Models\\Stage::class);\n $mockStage->method('getUuid')->willReturn((string) $stageUuid);\n\n return $mockStage;\n });\n\n // Create service with mocked StageRepository\n $automatedReportsService = $this->getService(mockStageRepository: $mockStageRepository);\n\n // Create mock AutomatedReport\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getCurrentDealStages')->willReturn($currentDealStages);\n\n $result = $automatedReportsService->getCurrentDealStagesUuids($mockReport);\n\n $this->assertEquals($expectedUuids, $result);\n }\n\n public function testGetCurrentDealStagesUuidsWithEmptyStages(): void\n {\n // Create mock AutomatedReport with empty current deal stages\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getCurrentDealStages')->willReturn([]);\n\n $result = $this->service->getCurrentDealStagesUuids($mockReport);\n\n $this->assertEquals([], $result);\n }\n\n public function testGetCurrentDealStagesUuidsWithNonExistentStages(): void\n {\n // Create mock StageRepository that returns null for all stages\n $mockStageRepository = $this->createMock(StageRepository::class);\n $mockStageRepository->method('find')->willReturn(null);\n\n // Create service with mocked StageRepository\n $automatedReportsService = $this->getService(mockStageRepository: $mockStageRepository);\n\n // Create mock AutomatedReport\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getCurrentDealStages')->willReturn([1, 2, 3]);\n\n $result = $automatedReportsService->getCurrentDealStagesUuids($mockReport);\n\n // Should return array with null values for non-existent stages\n $this->assertEquals([], $result);\n }\n\n public static function getCurrentDealStagesUuidsDataProvider(): array\n {\n return [\n 'single stage found' => [\n 'currentDealStages' => [10],\n 'mockStages' => [\n 10 => ['id' => 10, 'uuid' => 'stage-uuid-10'],\n ],\n 'expectedUuids' => ['stage-uuid-10'],\n ],\n 'multiple stages found' => [\n 'currentDealStages' => [10, 20, 30],\n 'mockStages' => [\n 10 => ['id' => 10, 'uuid' => 'stage-uuid-10'],\n 20 => ['id' => 20, 'uuid' => 'stage-uuid-20'],\n 30 => ['id' => 30, 'uuid' => 'stage-uuid-30'],\n ],\n 'expectedUuids' => ['stage-uuid-10', 'stage-uuid-20', 'stage-uuid-30'],\n ],\n 'mixed found and not found stages' => [\n 'currentDealStages' => [10, 20, 30],\n 'mockStages' => [\n 10 => ['id' => 10, 'uuid' => 'stage-uuid-10'],\n // 20 not found in DB\n 30 => ['id' => 30, 'uuid' => 'stage-uuid-30'],\n ],\n 'expectedUuids' => ['stage-uuid-10', 'stage-uuid-30'], // Updated to reflect that nulls are filtered out\n ],\n 'empty stages array' => [\n 'currentDealStages' => [],\n 'mockStages' => [],\n 'expectedUuids' => [],\n ],\n 'all stages not found' => [\n 'currentDealStages' => [10, 20],\n 'mockStages' => [], // No stages found\n 'expectedUuids' => [], // Updated to reflect that nulls are filtered out\n ],\n ];\n }\n\n #[DataProvider('getTeamGroupsDataProvider')]\n public function testGetTeamGroups(string $teamUuid, ?array $mockTeamData, array $mockGroups, array $expectedResult): void\n {\n // Create mock TeamRepository\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n\n if ($mockTeamData === null) {\n // Team not found\n $mockTeamRepository->method('idOrUuid')\n ->with($teamUuid)\n ->willReturn(null);\n } else {\n // Team found - create mock team with groups\n $mockTeam = $this->createMock(\\Jiminny\\Models\\Team::class);\n\n // Create mock groups collection\n $mockGroupsCollection = $this->createMock(\\Illuminate\\Database\\Eloquent\\Collection::class);\n\n // Create mock Group objects\n $groupObjects = [];\n foreach ($mockGroups as $groupData) {\n $mockGroup = $this->createMock(\\Jiminny\\Models\\Group::class);\n $mockGroup->method('getUuid')->willReturn($groupData['id']);\n $mockGroup->method('getName')->willReturn($groupData['name']);\n $groupObjects[] = $mockGroup;\n }\n\n // Mock the groups collection to return our mock groups\n $mockGroupsCollection->method('getIterator')->willReturn(new \\ArrayIterator($groupObjects));\n\n // Mock the groups() relation\n $mockGroupsRelation = $this->createMock(\\Illuminate\\Database\\Eloquent\\Relations\\HasMany::class);\n $mockGroupsRelation->method('get')->willReturn($mockGroupsCollection);\n $mockTeam->method('groups')->willReturn($mockGroupsRelation);\n\n $mockTeamRepository->method('idOrUuid')\n ->with($teamUuid)\n ->willReturn($mockTeam);\n }\n\n // Create service with mocked TeamRepository\n $automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);\n\n $result = $automatedReportsService->getTeamGroups($teamUuid);\n\n $this->assertEquals($expectedResult, $result);\n }\n\n public function testGetTeamGroupsWithNonExistentTeam(): void\n {\n // Create mock TeamRepository that returns null (team not found)\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->method('idOrUuid')->willReturn(null);\n\n // Create service with mocked TeamRepository\n $automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);\n\n $result = $automatedReportsService->getTeamGroups('non-existent-team-uuid');\n\n $this->assertEquals([], $result);\n }\n\n public function testGetTeamGroupsWithEmptyGroups(): void\n {\n // Create mock team with no groups\n $mockTeam = $this->createMock(\\Jiminny\\Models\\Team::class);\n\n // Create empty groups collection\n $mockGroupsCollection = $this->createMock(\\Illuminate\\Database\\Eloquent\\Collection::class);\n $mockGroupsCollection->method('getIterator')->willReturn(new \\ArrayIterator([]));\n\n $mockGroupsRelation = $this->createMock(\\Illuminate\\Database\\Eloquent\\Relations\\HasMany::class);\n $mockGroupsRelation->method('get')->willReturn($mockGroupsCollection);\n $mockTeam->method('groups')->willReturn($mockGroupsRelation);\n\n // Create mock TeamRepository\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->method('idOrUuid')->willReturn($mockTeam);\n\n // Create service with mocked TeamRepository\n $automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);\n\n $result = $automatedReportsService->getTeamGroups('team-with-no-groups');\n\n $this->assertEquals([], $result);\n }\n\n public static function getTeamGroupsDataProvider(): array\n {\n return [\n 'team with single group' => [\n 'teamUuid' => 'team-uuid-123',\n 'mockTeamData' => ['id' => 'team-uuid-123', 'name' => 'Test Team'],\n 'mockGroups' => [\n ['id' => 'group-uuid-1', 'name' => 'Sales Team'],\n ],\n 'expectedResult' => [\n ['id' => 'group-uuid-1', 'name' => 'Sales Team'],\n ],\n ],\n 'team with multiple groups' => [\n 'teamUuid' => 'team-uuid-456',\n 'mockTeamData' => ['id' => 'team-uuid-456', 'name' => 'Another Team'],\n 'mockGroups' => [\n ['id' => 'group-uuid-1', 'name' => 'Sales Team'],\n ['id' => 'group-uuid-2', 'name' => 'Marketing Team'],\n ['id' => 'group-uuid-3', 'name' => 'Support Team'],\n ],\n 'expectedResult' => [\n ['id' => 'group-uuid-1', 'name' => 'Sales Team'],\n ['id' => 'group-uuid-2', 'name' => 'Marketing Team'],\n ['id' => 'group-uuid-3', 'name' => 'Support Team'],\n ],\n ],\n 'team not found' => [\n 'teamUuid' => 'non-existent-uuid',\n 'mockTeamData' => null,\n 'mockGroups' => [],\n 'expectedResult' => [],\n ],\n 'team with no groups' => [\n 'teamUuid' => 'team-uuid-empty',\n 'mockTeamData' => ['id' => 'team-uuid-empty', 'name' => 'Empty Team'],\n 'mockGroups' => [],\n 'expectedResult' => [],\n ],\n ];\n }\n\n #[DataProvider('getTeamsDataProvider')]\n public function testGetTeams(array $mockTeams, array $expectedResult): void\n {\n // Create mock TeamRepository\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n\n // Create mock Team objects\n $teamObjects = [];\n foreach ($mockTeams as $teamData) {\n $mockTeam = $this->createMock(\\Jiminny\\Models\\Team::class);\n $mockTeam->method('getUuid')->willReturn($teamData['id']);\n $mockTeam->method('getName')->willReturn($teamData['name']);\n $mockTeam->method('hasFeature')\n ->with(\\Jiminny\\Models\\Feature\\FeatureEnum::AUTOMATED_REPORTS)\n ->willReturn($teamData['hasAutomatedReports']);\n $teamObjects[] = $mockTeam;\n }\n\n // Mock the repository to return a Collection (not array)\n $mockTeamRepository->method('getTeamsForKiosk')\n ->with('active')\n ->willReturn(new Collection($teamObjects));\n\n // Create service with mocked TeamRepository\n $automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);\n\n $result = $automatedReportsService->getTeams();\n\n $this->assertEquals($expectedResult, $result);\n }\n\n public function testGetTeamsWithNoTeams(): void\n {\n // Create mock TeamRepository that returns empty Collection\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->method('getTeamsForKiosk')->willReturn(new Collection([]));\n\n // Create service with mocked TeamRepository\n $automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);\n\n $result = $automatedReportsService->getTeams();\n\n $this->assertEquals([], $result);\n }\n\n public function testGetTeamsWithAllTeamsWithoutFeature(): void\n {\n // Create mock teams without AUTOMATED_REPORTS feature\n $mockTeam1 = $this->createMock(\\Jiminny\\Models\\Team::class);\n $mockTeam1->method('hasFeature')\n ->with(\\Jiminny\\Models\\Feature\\FeatureEnum::AUTOMATED_REPORTS)\n ->willReturn(false);\n\n $mockTeam2 = $this->createMock(\\Jiminny\\Models\\Team::class);\n $mockTeam2->method('hasFeature')\n ->with(\\Jiminny\\Models\\Feature\\FeatureEnum::AUTOMATED_REPORTS)\n ->willReturn(false);\n\n // Create mock TeamRepository that returns Collection\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->method('getTeamsForKiosk')->willReturn(new Collection([$mockTeam1, $mockTeam2]));\n\n // Create service with mocked TeamRepository\n $automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);\n\n $result = $automatedReportsService->getTeams();\n\n $this->assertEquals([], $result);\n }\n\n public function testGetTeamsForwardsPartnerToRepository(): void\n {\n $partner = $this->createMock(Partner::class);\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->expects(self::once())\n ->method('getTeamsForKiosk')\n ->with(Team::STATUS_ACTIVE, $partner)\n ->willReturn(new Collection([]));\n\n $service = $this->getService(mockTeamRepository: $mockTeamRepository);\n $service->getTeams(partner: $partner);\n }\n\n public function testGetOrganizationFieldDataForwardsPartnerToRepository(): void\n {\n $partner = $this->createMock(Partner::class);\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->expects(self::once())\n ->method('getTeamsForKiosk')\n ->with(Team::STATUS_ACTIVE, $partner)\n ->willReturn(new Collection([]));\n\n $service = $this->getService(mockTeamRepository: $mockTeamRepository);\n $service->getOrganizationFieldData(partner: $partner);\n }\n\n public function testGetTeamsGroupsOptionsForwardsPartnerToRepository(): void\n {\n $partner = $this->createMock(Partner::class);\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->expects(self::once())\n ->method('getTeamsForKiosk')\n ->with(Team::STATUS_ACTIVE, $partner)\n ->willReturn(new Collection([]));\n\n $service = $this->getService(mockTeamRepository: $mockTeamRepository);\n $service->getTeamsGroupsOptions(partner: $partner);\n }\n\n public static function getTeamsDataProvider(): array\n {\n return [\n 'single team with feature' => [\n 'mockTeams' => [\n [\n 'id' => 'team-uuid-1',\n 'name' => 'Sales Team',\n 'hasAutomatedReports' => true,\n ],\n ],\n 'expectedResult' => [\n ['id' => 'team-uuid-1', 'name' => 'Sales Team'],\n ],\n ],\n 'multiple teams with feature' => [\n 'mockTeams' => [\n [\n 'id' => 'team-uuid-1',\n 'name' => 'Sales Team',\n 'hasAutomatedReports' => true,\n ],\n [\n 'id' => 'team-uuid-2',\n 'name' => 'Marketing Team',\n 'hasAutomatedReports' => true,\n ],\n [\n 'id' => 'team-uuid-3',\n 'name' => 'Support Team',\n 'hasAutomatedReports' => true,\n ],\n ],\n 'expectedResult' => [\n ['id' => 'team-uuid-1', 'name' => 'Sales Team'],\n ['id' => 'team-uuid-2', 'name' => 'Marketing Team'],\n ['id' => 'team-uuid-3', 'name' => 'Support Team'],\n ],\n ],\n 'mixed teams - some with feature, some without' => [\n 'mockTeams' => [\n [\n 'id' => 'team-uuid-1',\n 'name' => 'Sales Team',\n 'hasAutomatedReports' => true,\n ],\n [\n 'id' => 'team-uuid-2',\n 'name' => 'Marketing Team',\n 'hasAutomatedReports' => false,\n ],\n [\n 'id' => 'team-uuid-3',\n 'name' => 'Support Team',\n 'hasAutomatedReports' => true,\n ],\n ],\n 'expectedResult' => [\n ['id' => 'team-uuid-1', 'name' => 'Sales Team'],\n ['id' => 'team-uuid-3', 'name' => 'Support Team'],\n ],\n ],\n 'all teams without feature' => [\n 'mockTeams' => [\n [\n 'id' => 'team-uuid-1',\n 'name' => 'Sales Team',\n 'hasAutomatedReports' => false,\n ],\n [\n 'id' => 'team-uuid-2',\n 'name' => 'Marketing Team',\n 'hasAutomatedReports' => false,\n ],\n ],\n 'expectedResult' => [],\n ],\n 'empty teams array' => [\n 'mockTeams' => [],\n 'expectedResult' => [],\n ],\n ];\n }\n\n #[DataProvider('deleteS3FilesDataProvider')]\n public function testDeleteS3Files(\n string $mediaType,\n array $expectedFileExtensions,\n array $existingFiles,\n string $pathSuffix,\n int $expectedDeletes\n ): void {\n // Arrange\n $teamUuid = 'team-uuid-123';\n $reportUuid = 'report-uuid-456';\n $basePath = sprintf('%s/reports/%s', $teamUuid, $reportUuid);\n\n $team = Mockery::mock(Team::class);\n $team->allows('getUuid')->andReturn($teamUuid);\n\n $report = Mockery::mock(AutomatedReport::class);\n $report->allows('getTeam')->andReturn($team);\n\n $result = Mockery::mock(AutomatedReportResult::class);\n $result->allows('getReport')->andReturn($report);\n $result->allows('getUuid')->andReturn($reportUuid);\n $result->allows('getMediaType')->andReturn($mediaType);\n\n Storage::fake();\n Log::shouldReceive('info')->times($expectedDeletes);\n\n foreach ($existingFiles as $extension) {\n $filePath = $basePath . $pathSuffix . '.' . $extension;\n Storage::put($filePath, 'dummy content');\n }\n\n // Act\n $this->service->deleteS3Files($result);\n\n // Assert\n foreach ($expectedFileExtensions as $extension) {\n $filePath = $basePath . $pathSuffix . '.' . $extension;\n if (in_array($extension, $existingFiles, true)) {\n Storage::assertMissing($filePath);\n } else {\n // To be sure no unexpected files were created and deleted\n Storage::assertMissing($filePath);\n }\n }\n }\n\n public static function deleteS3FilesDataProvider(): array\n {\n return [\n 'PDF report, all files exist' => [\n 'mediaType' => AutomatedReportsService::MEDIA_TYPE_PDF,\n 'expectedFileExtensions' => ['html', 'MD', 'pdf'],\n 'existingFiles' => ['html', 'MD', 'pdf'],\n 'pathSuffix' => '',\n 'expectedDeletes' => 3,\n ],\n 'PDF report, some files exist' => [\n 'mediaType' => AutomatedReportsService::MEDIA_TYPE_PDF,\n 'expectedFileExtensions' => ['html', 'MD', 'pdf'],\n 'existingFiles' => ['html', 'pdf'],\n 'pathSuffix' => '',\n 'expectedDeletes' => 2,\n ],\n 'PDF report, no files exist' => [\n 'mediaType' => AutomatedReportsService::MEDIA_TYPE_PDF,\n 'expectedFileExtensions' => ['html', 'MD', 'pdf'],\n 'existingFiles' => [],\n 'pathSuffix' => '',\n 'expectedDeletes' => 0,\n ],\n 'Podcast report, all files exist' => [\n 'mediaType' => AutomatedReportsService::MEDIA_TYPE_PODCAST,\n 'expectedFileExtensions' => ['json', 'mp3', 'ssml'],\n 'existingFiles' => ['json', 'mp3', 'ssml'],\n 'pathSuffix' => '_podcast',\n 'expectedDeletes' => 3,\n ],\n 'Podcast report, some files exist' => [\n 'mediaType' => AutomatedReportsService::MEDIA_TYPE_PODCAST,\n 'expectedFileExtensions' => ['json', 'mp3', 'ssml'],\n 'existingFiles' => ['mp3'],\n 'pathSuffix' => '_podcast',\n 'expectedDeletes' => 1,\n ],\n 'Podcast report, no files exist' => [\n 'mediaType' => AutomatedReportsService::MEDIA_TYPE_PODCAST,\n 'expectedFileExtensions' => ['json', 'mp3', 'ssml'],\n 'existingFiles' => [],\n 'pathSuffix' => '_podcast',\n 'expectedDeletes' => 0,\n ],\n 'Other media type, should do nothing' => [\n 'mediaType' => 'some_other_type',\n 'expectedFileExtensions' => [],\n 'existingFiles' => [],\n 'pathSuffix' => '',\n 'expectedDeletes' => 0,\n ],\n ];\n }\n\n public function testDeleteReportsResultsInRetentionPeriodWithLogging(): void\n {\n // Create mocks for the test\n $automatedReportsService = Mockery::mock(AutomatedReportsService::class);\n\n $team = Mockery::mock(Team::class);\n $team->shouldReceive('getId')->andReturn(123);\n\n $from = now()->subDays(30);\n $to = now();\n $source = 'test-source';\n\n // Expect the method to be called with specific parameters\n $automatedReportsService->shouldReceive('deleteReportsResultsInRetentionPeriodWithLogging')\n ->once()\n ->with(\n $team,\n Mockery::on(function ($arg) use ($from) {\n return $arg->timestamp === $from->timestamp;\n }),\n Mockery::on(function ($arg) use ($to) {\n return $arg->timestamp === $to->timestamp;\n }),\n $source\n )\n ->andReturn(5);\n\n // Call the method and verify the result\n $result = $automatedReportsService->deleteReportsResultsInRetentionPeriodWithLogging(\n $team,\n $from,\n $to,\n $source\n );\n\n $this->assertEquals(5, $result);\n }\n\n #[DataProvider('sanitizeFileNameDataProvider')]\n public function testSanitizeFileName(string $input, string $expected): void\n {\n $result = $this->service->sanitizeFileName($input);\n\n $this->assertEquals($expected, $result);\n }\n\n public static function sanitizeFileNameDataProvider(): array\n {\n return [\n 'no special characters' => [\n 'input' => 'Exec Summary - Sep 2025 - Business Development Team',\n 'expected' => 'Exec Summary - Sep 2025 - Business Development Team',\n ],\n 'forward slash in team name' => [\n 'input' => 'Exec Summary - Sep 2025 - ND/IRV',\n 'expected' => 'Exec Summary - Sep 2025 - ND-IRV',\n ],\n 'backslash in team name' => [\n 'input' => 'Exec Summary - Sep 2025 - ND\\IRV',\n 'expected' => 'Exec Summary - Sep 2025 - ND-IRV',\n ],\n 'multiple forward slashes' => [\n 'input' => 'Report - Team A/B/C',\n 'expected' => 'Report - Team A-B-C',\n ],\n 'multiple backslashes' => [\n 'input' => 'Report - Team A\\B\\C',\n 'expected' => 'Report - Team A-B-C',\n ],\n 'mixed slashes and backslashes' => [\n 'input' => 'Report - Team A/B\\C',\n 'expected' => 'Report - Team A-B-C',\n ],\n 'complex team name with slashes' => [\n 'input' => 'Exec Summary - Sep 2025 - Business Development Team - ND/IRV, Net Driven - Acquisition (Sales)',\n 'expected' => 'Exec Summary - Sep 2025 - Business Development Team - ND-IRV, Net Driven - Acquisition (Sales)',\n ],\n 'only slashes' => [\n 'input' => '//\\\\\\\\',\n 'expected' => '----',\n ],\n 'empty string' => [\n 'input' => '',\n 'expected' => '',\n ],\n 'slash at start' => [\n 'input' => '/Report Name',\n 'expected' => '-Report Name',\n ],\n 'slash at end' => [\n 'input' => 'Report Name/',\n 'expected' => 'Report Name-',\n ],\n ];\n }\n\n public function testGetReportFileNameSanitizesOutput(): void\n {\n // Create mock GroupRepository\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n\n // Create mock Group with slash in name\n $mockGroup = $this->createMock(\\Jiminny\\Models\\Group::class);\n $mockGroup->method('getName')->willReturn('ND/IRV, Net Driven - Acquisition (Sales)');\n\n $mockGroupRepository->method('find')->willReturn($mockGroup);\n\n // Create service with mocked GroupRepository\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n // Create mock AutomatedReportResult\n $mockReportResult = $this->createMock(AutomatedReportResult::class);\n\n // Create mock AutomatedReport\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getType')->willReturn('exec_summary');\n $mockReport->method('getFrequency')->willReturn('monthly');\n\n $mockReportResult->method('getReport')->willReturn($mockReport);\n $mockReportResult->method('getFromDate')->willReturn(\n \\Illuminate\\Support\\Carbon::parse('2025-09-01')\n );\n $mockReportResult->method('getToDate')->willReturn(\n \\Illuminate\\Support\\Carbon::parse('2025-09-30')\n );\n $mockReportResult->method('getGroups')->willReturn([123]);\n $mockReportResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PDF);\n\n // Call getReportFileName\n $result = $service->getReportFileName($mockReportResult);\n\n // Verify the result does not contain slashes or backslashes\n $this->assertStringNotContainsString('/', $result);\n $this->assertStringNotContainsString('\\\\', $result);\n\n // Verify the slash was replaced with dash\n $this->assertStringContainsString('ND-IRV', $result);\n }\n\n public function testGetReportFileNameWithExtensionSanitizesOutput(): void\n {\n // Create mock GroupRepository\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n\n // Create mock Group with backslash in name\n $mockGroup = $this->createMock(\\Jiminny\\Models\\Group::class);\n $mockGroup->method('getName')->willReturn('Team\\Name');\n\n $mockGroupRepository->method('find')->willReturn($mockGroup);\n\n // Create service with mocked GroupRepository\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n // Create mock AutomatedReportResult\n $mockReportResult = $this->createMock(AutomatedReportResult::class);\n\n // Create mock AutomatedReport\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getType')->willReturn('exec_summary');\n $mockReport->method('getFrequency')->willReturn('monthly');\n\n $mockReportResult->method('getReport')->willReturn($mockReport);\n $mockReportResult->method('getFromDate')->willReturn(\n \\Illuminate\\Support\\Carbon::parse('2025-09-01')\n );\n $mockReportResult->method('getToDate')->willReturn(\n \\Illuminate\\Support\\Carbon::parse('2025-09-30')\n );\n $mockReportResult->method('getGroups')->willReturn([123]);\n $mockReportResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PDF);\n\n // Call getReportFileNameWithExtension\n $result = $service->getReportFileNameWithExtension($mockReportResult);\n\n // Verify the result does not contain backslashes\n $this->assertStringNotContainsString('\\\\', $result);\n $this->assertStringNotContainsString('/', $result);\n\n // Verify the backslash was replaced with dash\n $this->assertStringContainsString('Team-Name', $result);\n\n // Verify extension is added\n $this->assertStringEndsWith('.pdf', $result);\n }\n\n public function testHasPassedScheduledTimeWithNullGeneratedAt(): void\n {\n $result = $this->service->hasPassedScheduledTime(null, 'America/Chicago');\n\n $this->assertFalse($result);\n }\n\n public function testHasPassedScheduledTimeWhenScheduledTimePassed(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-02-24 10:00:00', 'America/Chicago'));\n\n $generatedAt = Carbon::parse('2026-02-24 01:00:00', 'America/Chicago');\n\n $result = $this->service->hasPassedScheduledTime($generatedAt, 'America/Chicago');\n\n $this->assertTrue($result);\n\n Carbon::setTestNow();\n }\n\n public function testHasPassedScheduledTimeWhenGeneratedAfterScheduledTime(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-02-24 10:00:00', 'America/Chicago'));\n\n $generatedAt = Carbon::parse('2026-02-24 06:00:00', 'America/Chicago');\n\n $result = $this->service->hasPassedScheduledTime($generatedAt, 'America/Chicago');\n\n $this->assertFalse($result);\n\n Carbon::setTestNow();\n }\n\n public function testHasPassedScheduledTimeBeforeScheduledTimeToday(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-02-24 04:00:00', 'America/Chicago'));\n\n $generatedAt = Carbon::parse('2026-02-24 01:00:00', 'America/Chicago');\n\n $result = $this->service->hasPassedScheduledTime($generatedAt, 'America/Chicago');\n\n $this->assertFalse($result);\n\n Carbon::setTestNow();\n }\n\n public function testShouldSendReportWithEmptyUsers(): void\n {\n $result = $this->service->shouldSendReport([]);\n\n $this->assertFalse($result);\n }\n\n public function testShouldSendReportAtScheduledTime(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-02-24 05:00:00', 'America/Chicago'));\n\n $users = [\n ['email' => 'test@example.com', 'name' => 'Test User', 'timezone' => 'America/Chicago'],\n ];\n\n $result = $this->service->shouldSendReport($users);\n\n $this->assertTrue($result);\n\n Carbon::setTestNow();\n }\n\n public function testShouldSendReportNotAtScheduledTimeWithoutGeneratedAt(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-02-24 10:00:00', 'America/Chicago'));\n\n $users = [\n ['email' => 'test@example.com', 'name' => 'Test User', 'timezone' => 'America/Chicago'],\n ];\n\n $result = $this->service->shouldSendReport($users);\n\n $this->assertFalse($result);\n\n Carbon::setTestNow();\n }\n\n public function testShouldSendReportWhenScheduledTimeMissed(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-02-24 10:00:00', 'America/Chicago'));\n\n $users = [\n ['email' => 'test@example.com', 'name' => 'Test User', 'timezone' => 'America/Chicago'],\n ];\n\n $generatedAt = Carbon::parse('2026-02-24 01:00:00', 'America/Chicago');\n\n $result = $this->service->shouldSendReport($users, $generatedAt);\n\n $this->assertTrue($result);\n\n Carbon::setTestNow();\n }\n\n public function testShouldSendReportWhenGeneratedAfterScheduledTime(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-02-24 10:00:00', 'America/Chicago'));\n\n $users = [\n ['email' => 'test@example.com', 'name' => 'Test User', 'timezone' => 'America/Chicago'],\n ];\n\n $generatedAt = Carbon::parse('2026-02-24 06:00:00', 'America/Chicago');\n\n $result = $this->service->shouldSendReport($users, $generatedAt);\n\n $this->assertFalse($result);\n\n Carbon::setTestNow();\n }\n\n public function testGetTypes(): void\n {\n $types = AutomatedReportsService::getTypes();\n\n $this->assertIsArray($types);\n $this->assertContains('exec_summary', $types);\n $this->assertContains('coaching_profiles', $types);\n $this->assertContains('loss_analysis', $types);\n $this->assertNotContains('ask_jiminny', $types);\n }\n\n public function testGetCallTypes(): void\n {\n $callTypes = AutomatedReportsService::getCallTypes();\n\n $this->assertIsArray($callTypes);\n $this->assertContains('conference', $callTypes);\n $this->assertContains('dialer', $callTypes);\n }\n\n public function testGetFrequencies(): void\n {\n $frequencies = AutomatedReportsService::getFrequencies();\n\n $this->assertIsArray($frequencies);\n $this->assertContains('weekly', $frequencies);\n $this->assertContains('monthly', $frequencies);\n $this->assertContains('quarterly', $frequencies);\n $this->assertContains('one_off', $frequencies);\n $this->assertNotContains('daily', $frequencies);\n }\n\n public function testGetAskJiminnyFrequencies(): void\n {\n $frequencies = AutomatedReportsService::getAskJiminnyFrequencies();\n\n $this->assertIsArray($frequencies);\n $this->assertContains('daily', $frequencies);\n $this->assertContains('weekly', $frequencies);\n $this->assertContains('monthly', $frequencies);\n $this->assertNotContains('quarterly', $frequencies);\n $this->assertNotContains('one_off', $frequencies);\n }\n\n public function testGetReportEnabledFieldData(): void\n {\n $result = $this->service->getReportEnabledFieldData(true);\n\n $this->assertEquals('report_enabled', $result['id']);\n $this->assertTrue($result['value']);\n }\n\n public function testGetReportEnabledFieldDataDefault(): void\n {\n $result = $this->service->getReportEnabledFieldData();\n\n $this->assertFalse($result['value']);\n }\n\n public function testGetOrganizationFieldDataShortVersion(): void\n {\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->method('getTeamsForKiosk')->willReturn(new Collection([]));\n\n $service = $this->getService(mockTeamRepository: $mockTeamRepository);\n $result = $service->getOrganizationFieldData(null, true);\n\n $this->assertEquals('organization', $result['id']);\n $this->assertArrayNotHasKey('inputType', $result);\n $this->assertArrayHasKey('options', $result);\n }\n\n public function testGetOrganizationFieldDataFullVersion(): void\n {\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->method('getTeamsForKiosk')->willReturn(new Collection([]));\n\n $service = $this->getService(mockTeamRepository: $mockTeamRepository);\n $result = $service->getOrganizationFieldData('team-uuid-1', false);\n\n $this->assertEquals('organization', $result['id']);\n $this->assertArrayHasKey('inputType', $result);\n $this->assertEquals('team-uuid-1', $result['value']);\n $this->assertArrayHasKey('dependencies', $result);\n }\n\n public function testGetTeamFieldDataShortVersion(): void\n {\n $result = $this->service->getTeamFieldData([], [], true);\n\n $this->assertEquals('teams', $result['id']);\n $this->assertArrayNotHasKey('inputType', $result);\n }\n\n public function testGetTeamFieldDataFullVersion(): void\n {\n $result = $this->service->getTeamFieldData(['opt1'], ['val1'], false);\n\n $this->assertEquals('teams', $result['id']);\n $this->assertArrayHasKey('inputType', $result);\n $this->assertEquals(['opt1'], $result['options']);\n $this->assertEquals(['val1'], $result['value']);\n }\n\n public function testGetReportTypeFieldDataShortVersion(): void\n {\n $result = $this->service->getReportTypeFieldData(null, true);\n\n $this->assertEquals('report_type', $result['id']);\n $this->assertArrayNotHasKey('inputType', $result);\n }\n\n public function testGetReportTypeFieldDataFullVersion(): void\n {\n $result = $this->service->getReportTypeFieldData('exec_summary', false);\n\n $this->assertEquals('report_type', $result['id']);\n $this->assertArrayHasKey('inputType', $result);\n $this->assertEquals('exec_summary', $result['value']);\n }\n\n public function testGetReportTypeFieldDataWithTeamHavingBothFeatures(): void\n {\n $team = $this->createMock(\\Jiminny\\Models\\Team::class);\n $team->method('hasFeature')->willReturnMap([\n [\\Jiminny\\Models\\Feature\\FeatureEnum::AUTOMATED_REPORTS, true],\n [\\Jiminny\\Models\\Feature\\FeatureEnum::ASK_JIMINNY_REPORTS, true],\n ]);\n\n $result = $this->service->getReportTypeFieldData(null, true, $team);\n\n $ids = array_column($result['options'], 'id');\n $this->assertContains('exec_summary', $ids);\n $this->assertContains(AutomatedReportsService::TYPE_ASK_JIMINNY, $ids);\n $this->assertLessThan(\n array_search(AutomatedReportsService::TYPE_ASK_JIMINNY, $ids),\n array_search('exec_summary', $ids)\n );\n }\n\n public function testGetReportTypeFieldDataWithTeamHavingOnlyAutomatedReports(): void\n {\n $team = $this->createMock(\\Jiminny\\Models\\Team::class);\n $team->method('hasFeature')->willReturnMap([\n [\\Jiminny\\Models\\Feature\\FeatureEnum::AUTOMATED_REPORTS, true],\n [\\Jiminny\\Models\\Feature\\FeatureEnum::ASK_JIMINNY_REPORTS, false],\n ]);\n\n $result = $this->service->getReportTypeFieldData(null, true, $team);\n\n $ids = array_column($result['options'], 'id');\n $this->assertContains('exec_summary', $ids);\n $this->assertNotContains(AutomatedReportsService::TYPE_ASK_JIMINNY, $ids);\n }\n\n public function testGetReportTypeFieldDataWithTeamHavingOnlyAskJiminny(): void\n {\n $team = $this->createMock(\\Jiminny\\Models\\Team::class);\n $team->method('hasFeature')->willReturnMap([\n [\\Jiminny\\Models\\Feature\\FeatureEnum::AUTOMATED_REPORTS, false],\n [\\Jiminny\\Models\\Feature\\FeatureEnum::ASK_JIMINNY_REPORTS, true],\n ]);\n\n $result = $this->service->getReportTypeFieldData(null, true, $team);\n\n $ids = array_column($result['options'], 'id');\n $this->assertContains(AutomatedReportsService::TYPE_ASK_JIMINNY, $ids);\n $this->assertNotContains('exec_summary', $ids);\n }\n\n public function testGetReportTypeFieldDataWithNullTeamFallsBackToStandardTypes(): void\n {\n $result = $this->service->getReportTypeFieldData(null, true, null);\n\n $ids = array_column($result['options'], 'id');\n $this->assertContains('exec_summary', $ids);\n $this->assertNotContains(AutomatedReportsService::TYPE_ASK_JIMINNY, $ids);\n }\n\n public function testGetFrequencyFieldData(): void\n {\n $result = $this->service->getFrequencyFieldData('weekly');\n\n $this->assertEquals('frequency', $result['id']);\n $this->assertEquals('weekly', $result['value']);\n $this->assertArrayHasKey('options', $result);\n }\n\n public function testGetPeriodFieldData(): void\n {\n $result = $this->service->getPeriodFieldData('2025-01-01', '2025-01-31');\n\n $this->assertEquals('period', $result['id']);\n $this->assertEquals('2025-01-01', $result['value']['startDate']);\n $this->assertEquals('2025-01-31', $result['value']['endDate']);\n }\n\n public function testGetCallDurationFieldData(): void\n {\n $result = $this->service->getCallDurationFieldData(5, 60);\n\n $this->assertEquals('call_duration', $result['id']);\n $this->assertEquals(5, $result['value']['min']);\n $this->assertEquals(60, $result['value']['max']);\n }\n\n public function testGetDealValueFieldData(): void\n {\n $result = $this->service->getDealValueFieldData(1000, 5000);\n\n $this->assertEquals('deal_value', $result['id']);\n $this->assertEquals(1000, $result['value']['min']);\n $this->assertEquals(5000, $result['value']['max']);\n }\n\n public function testGetCustomReportNameFieldData(): void\n {\n $result = $this->service->getCustomReportNameFieldData('My Report');\n\n $this->assertEquals('custom_name', $result['id']);\n $this->assertEquals('My Report', $result['value']);\n }\n\n public function testGetAdditionalPromptInputFieldData(): void\n {\n $result = $this->service->getAdditionalPromptInputFieldData('Some prompt');\n\n $this->assertEquals('additional_prompt_input', $result['id']);\n $this->assertEquals('Some prompt', $result['value']);\n }\n\n public function testGetCallTypeFieldDataBothOn(): void\n {\n $result = $this->service->getCallTypeFieldData(true, true);\n\n $this->assertEquals('call_type', $result['id']);\n $this->assertCount(2, $result['value']);\n }\n\n public function testGetCallTypeFieldDataNoneOn(): void\n {\n $result = $this->service->getCallTypeFieldData(false, false);\n\n $this->assertEquals('call_type', $result['id']);\n $this->assertEmpty($result['value']);\n }\n\n public function testGetCallTypeFieldDataConferenceOnly(): void\n {\n $result = $this->service->getCallTypeFieldData(true, false);\n\n $this->assertCount(1, $result['value']);\n $this->assertEquals('conference', $result['value'][0]['id']);\n }\n\n public function testGetCallTypeFieldDataDialerOnly(): void\n {\n $result = $this->service->getCallTypeFieldData(false, true);\n\n $this->assertCount(1, $result['value']);\n $this->assertEquals('dialer', $result['value'][0]['id']);\n }\n\n public function testTransformDurationToMinutesNull(): void\n {\n $result = $this->service->transformDurationToMinutes(null);\n\n $this->assertNull($result);\n }\n\n public function testTransformDurationToMinutesZero(): void\n {\n $result = $this->service->transformDurationToMinutes(0);\n\n $this->assertNull($result);\n }\n\n public function testTransformDurationToMinutes(): void\n {\n $result = $this->service->transformDurationToMinutes(300);\n\n $this->assertEquals(5, $result);\n }\n\n public function testGetTeam(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->expects($this->once())\n ->method('idOrUuid')\n ->with('team-uuid')\n ->willReturn($mockTeam);\n\n $service = $this->getService(mockTeamRepository: $mockTeamRepository);\n $result = $service->getTeam('team-uuid');\n\n $this->assertSame($mockTeam, $result);\n }\n\n public function testGetTeamById(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n $mockTeamRepository->expects($this->once())\n ->method('find')\n ->with(42)\n ->willReturn($mockTeam);\n\n $service = $this->getService(mockTeamRepository: $mockTeamRepository);\n $result = $service->getTeamById(42);\n\n $this->assertSame($mockTeam, $result);\n }\n\n public function testGetGroupsUuidsEmpty(): void\n {\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getGroups')->willReturn([]);\n\n $result = $this->service->getGroupsUuids($report);\n\n $this->assertEquals([], $result);\n }\n\n public function testGetGroupsUuidsWithGroups(): void\n {\n $mockGroup = $this->createMock(Group::class);\n $mockGroup->method('getUuid')->willReturn('group-uuid-1');\n\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n $mockGroupRepository->method('find')->willReturnMap([\n [10, $mockGroup],\n [99, null],\n ]);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getGroups')->willReturn([10, 99]);\n\n $result = $service->getGroupsUuids($report);\n\n $this->assertEquals(['group-uuid-1'], $result);\n }\n\n public function testGetPlaybookCategoriesUuidsEmpty(): void\n {\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getPlaybookCategories')->willReturn([]);\n\n $result = $this->service->getPlaybookCategoriesUuids($report);\n\n $this->assertEquals([], $result);\n }\n\n public function testGetPlaybookCategoriesUuidsWithCategories(): void\n {\n $mockCategory = $this->createMock(\\Jiminny\\Models\\PlaybookCategory::class);\n $mockCategory->method('getUuid')->willReturn('cat-uuid-1');\n\n $mockPlaybookCategoryRepository = $this->createMock(PlaybookCategoryRepository::class);\n $mockPlaybookCategoryRepository->method('find')->willReturnMap([\n [1, $mockCategory],\n [2, null],\n ]);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $mockPlaybookCategoryRepository,\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getPlaybookCategories')->willReturn([1, 2]);\n\n $result = $service->getPlaybookCategoriesUuids($report);\n\n $this->assertEquals(['cat-uuid-1'], $result);\n }\n\n public function testGetDealAtCallStagesUuidsEmpty(): void\n {\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getDealAtCallStages')->willReturn([]);\n\n $result = $this->service->getDealAtCallStagesUuids($report);\n\n $this->assertEquals([], $result);\n }\n\n public function testGetDealAtCallStagesUuidsWithStages(): void\n {\n $mockStage = $this->createMock(\\Jiminny\\Models\\Stage::class);\n $mockStage->method('getUuid')->willReturn('stage-uuid-1');\n\n $mockStageRepository = $this->createMock(StageRepository::class);\n $mockStageRepository->method('find')->willReturnMap([\n [5, $mockStage],\n [9, null],\n ]);\n\n $service = $this->getService(mockStageRepository: $mockStageRepository);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getDealAtCallStages')->willReturn([5, 9]);\n\n $result = $service->getDealAtCallStagesUuids($report);\n\n $this->assertEquals(['stage-uuid-1'], $result);\n }\n\n public function testGetJiminnyUsersUuids(): void\n {\n $mockUser = $this->createMock(User::class);\n $mockUser->method('getUuid')->willReturn('user-uuid-1');\n\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturn($mockUser);\n\n $service = $this->getService(mockUserRepository: $mockUserRepository);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getJiminnyRecipients')->willReturn(['users' => [1]]);\n\n $result = $service->getJiminnyUsersUuids($report);\n\n $this->assertEquals(['user-uuid-1'], $result);\n }\n\n public function testGetRecipientUsers(): void\n {\n $mockUser = $this->createMock(User::class);\n $mockUser->method('getEmailAddress')->willReturn('user@test.com');\n $mockUser->method('getName')->willReturn('Test User');\n $timezone = $this->createMock(\\DateTimeZone::class);\n $timezone->method('getName')->willReturn('UTC');\n $mockUser->method('getTimezone')->willReturn($timezone);\n\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturn($mockUser);\n\n $service = $this->getService(mockUserRepository: $mockUserRepository);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getRecipients')->willReturn(['users' => [1]]);\n\n $result = $service->getRecipientUsers($report);\n\n $this->assertCount(1, $result);\n $this->assertEquals('user@test.com', $result[0]['email']);\n $this->assertEquals('Test User', $result[0]['name']);\n }\n\n public function testGetValidRecipientUsersFiltersEmptyEmail(): void\n {\n $mockUserWithEmail = $this->createMock(User::class);\n $mockUserWithEmail->method('getEmailAddress')->willReturn('valid@test.com');\n $mockUserWithEmail->method('getName')->willReturn('Valid User');\n $timezone = $this->createMock(\\DateTimeZone::class);\n $timezone->method('getName')->willReturn('UTC');\n $mockUserWithEmail->method('getTimezone')->willReturn($timezone);\n\n $mockUserNoEmail = $this->createMock(User::class);\n $mockUserNoEmail->method('getEmailAddress')->willReturn('');\n $mockUserNoEmail->method('getName')->willReturn('No Email User');\n $mockUserNoEmail->method('getTimezone')->willReturn($timezone);\n\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturnMap([\n [1, $mockUserWithEmail],\n [2, $mockUserNoEmail],\n ]);\n\n $service = $this->getService(mockUserRepository: $mockUserRepository);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getRecipients')->willReturn(['users' => [1, 2]]);\n $report->method('getJiminnyRecipients')->willReturn(['users' => []]);\n\n $result = $service->getValidRecipientUsers($report);\n\n $this->assertCount(1, $result);\n $this->assertEquals('valid@test.com', $result[0]['email']);\n }\n\n public function testGetValidRecipientUsersWithJiminny(): void\n {\n $tz = $this->createMock(\\DateTimeZone::class);\n $tz->method('getName')->willReturn('UTC');\n\n $mockUser1 = $this->createMock(User::class);\n $mockUser1->method('getEmailAddress')->willReturn('user1@test.com');\n $mockUser1->method('getName')->willReturn('User1');\n $mockUser1->method('getTimezone')->willReturn($tz);\n\n $mockUser2 = $this->createMock(User::class);\n $mockUser2->method('getEmailAddress')->willReturn('jiminny@test.com');\n $mockUser2->method('getName')->willReturn('Jiminny');\n $mockUser2->method('getTimezone')->willReturn($tz);\n\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturnMap([\n [1, $mockUser1],\n [2, $mockUser2],\n ]);\n\n $service = $this->getService(mockUserRepository: $mockUserRepository);\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getRecipients')->willReturn(['users' => [1]]);\n $report->method('getJiminnyRecipients')->willReturn(['users' => [2]]);\n\n $result = $service->getValidRecipientUsers($report, true);\n\n $this->assertCount(2, $result);\n }\n\n public function testGetReportTypeName(): void\n {\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getType')->willReturn('exec_summary');\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getReport')->willReturn($report);\n\n $result = $this->service->getReportTypeName($mockResult);\n\n $this->assertEquals('Exec Summary', $result);\n }\n\n public function testGetReportPeriodNameThrowsOnNullFrom(): void\n {\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getFrequency')->willReturn('weekly');\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getReport')->willReturn($report);\n $mockResult->method('getFromDate')->willReturn(null);\n $mockResult->method('getToDate')->willReturn(IlluminateCarbon::parse('2025-01-15'));\n\n $this->expectException(\\Jiminny\\Exceptions\\ApplicationException::class);\n\n $this->service->getReportPeriodName($mockResult);\n }\n\n public function testGetReportPeriodNameThrowsOnNullTo(): void\n {\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getFrequency')->willReturn('weekly');\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getReport')->willReturn($report);\n $mockResult->method('getFromDate')->willReturn(IlluminateCarbon::parse('2025-01-08'));\n $mockResult->method('getToDate')->willReturn(null);\n\n $this->expectException(\\Jiminny\\Exceptions\\ApplicationException::class);\n\n $this->service->getReportPeriodName($mockResult);\n }\n\n #[DataProvider('formatReportPeriodNameDataProvider')]\n public function testGetReportPeriodName(\n string $frequency,\n string $from,\n string $to,\n string $expected\n ): void {\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getFrequency')->willReturn($frequency);\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getReport')->willReturn($report);\n $mockResult->method('getFromDate')->willReturn(IlluminateCarbon::parse($from));\n $mockResult->method('getToDate')->willReturn(IlluminateCarbon::parse($to));\n\n $result = $this->service->getReportPeriodName($mockResult);\n\n $this->assertEquals($expected, $result);\n }\n\n public static function formatReportPeriodNameDataProvider(): array\n {\n return [\n 'daily' => [\n 'frequency' => 'daily',\n 'from' => '2025-05-15',\n 'to' => '2025-05-15',\n 'expected' => '15 May 2025',\n ],\n 'monthly same year' => [\n 'frequency' => 'monthly',\n 'from' => '2025-05-01',\n 'to' => '2025-05-31',\n 'expected' => 'May 2025',\n ],\n 'weekly same month' => [\n 'frequency' => 'weekly',\n 'from' => '2025-08-04',\n 'to' => '2025-08-08',\n 'expected' => '4 - 8 Aug 2025',\n ],\n 'weekly different months same year' => [\n 'frequency' => 'weekly',\n 'from' => '2025-10-27',\n 'to' => '2025-11-03',\n 'expected' => '27 Oct - 3 Nov 2025',\n ],\n 'weekly different years' => [\n 'frequency' => 'weekly',\n 'from' => '2024-12-28',\n 'to' => '2025-01-03',\n 'expected' => '28 Dec 2024 - 3 Jan 2025',\n ],\n 'quarterly same year' => [\n 'frequency' => 'quarterly',\n 'from' => '2025-01-01',\n 'to' => '2025-04-01',\n 'expected' => 'Jan - Mar 2025',\n ],\n 'quarterly different years' => [\n 'frequency' => 'quarterly',\n 'from' => '2024-11-01',\n 'to' => '2025-02-01',\n 'expected' => 'Nov 2024 - Jan 2025',\n ],\n 'one_off same month' => [\n 'frequency' => 'one_off',\n 'from' => '2025-05-02',\n 'to' => '2025-05-31',\n 'expected' => '2 - 31 May 2025',\n ],\n 'one_off different months same year' => [\n 'frequency' => 'one_off',\n 'from' => '2025-05-15',\n 'to' => '2025-06-15',\n 'expected' => '15 May - 15 Jun 2025',\n ],\n 'one_off different years' => [\n 'frequency' => 'one_off',\n 'from' => '2024-12-15',\n 'to' => '2025-01-15',\n 'expected' => '15 Dec 2024 - 15 Jan 2025',\n ],\n 'unknown frequency falls back to default' => [\n 'frequency' => 'unknown',\n 'from' => '2025-05-01',\n 'to' => '2025-05-31',\n 'expected' => '1 May 2025 - 31 May 2025',\n ],\n ];\n }\n\n public function testGetReportTeamsNameEmpty(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getGroups')->willReturn([]);\n\n $result = $this->service->getReportTeamsName($mockResult);\n\n $this->assertEquals('All', $result);\n }\n\n public function testGetReportTeamsNameSingleGroup(): void\n {\n $mockGroup = $this->createMock(Group::class);\n $mockGroup->method('getName')->willReturn('Sales Team');\n\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n $mockGroupRepository->method('find')->willReturn($mockGroup);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getGroups')->willReturn([10]);\n\n $result = $service->getReportTeamsName($mockResult);\n\n $this->assertEquals('Sales Team', $result);\n }\n\n public function testGetReportTeamsNameMultipleGroups(): void\n {\n $mockGroup1 = $this->createMock(Group::class);\n $mockGroup1->method('getName')->willReturn('Sales Team');\n\n $mockGroup2 = $this->createMock(Group::class);\n $mockGroup2->method('getName')->willReturn('Marketing Team');\n\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n $mockGroupRepository->method('find')->willReturnMap([\n [10, $mockGroup1],\n [20, $mockGroup2],\n [99, null],\n ]);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getGroups')->willReturn([10, 20, 99]);\n\n $result = $service->getReportTeamsName($mockResult);\n\n $this->assertEquals('Sales Team, Marketing Team', $result);\n }\n\n public function testGetReportFound(): void\n {\n $mockReport = $this->createMock(AutomatedReport::class);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('findByUuid')\n ->with('report-uuid')\n ->willReturn($mockReport);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->getReport('report-uuid');\n\n $this->assertSame($mockReport, $result);\n }\n\n public function testGetReportNotFound(): void\n {\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->method('findByUuid')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(ModelNotFoundException::class);\n\n $service->getReport('non-existent-uuid');\n }\n\n public function testDeleteReportNotFound(): void\n {\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->method('findByUuid')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(ModelNotFoundException::class);\n\n $service->delete('non-existent-uuid');\n }\n\n public function testDeleteReportSuccess(): void\n {\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->expects($this->once())->method('delete');\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->method('findByUuid')->willReturn($mockReport);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $service->delete('report-uuid');\n }\n\n public function testUpdateStatusNotFound(): void\n {\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->method('findByUuid')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(ModelNotFoundException::class);\n\n $service->updateStatus('non-existent-uuid', ['report_enabled' => true]);\n }\n\n public function testGetReportResultFound(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('findResultByUuid')\n ->with('result-uuid')\n ->willReturn($mockResult);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->getReportResult('result-uuid');\n\n $this->assertSame($mockResult, $result);\n }\n\n public function testGetReportResultNotFound(): void\n {\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->method('findResultByUuid')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(ModelNotFoundException::class);\n\n $service->getReportResult('non-existent-uuid');\n }\n\n public function testFindChildResult(): void\n {\n $mockParent = $this->createMock(AutomatedReportResult::class);\n $mockChild = $this->createMock(AutomatedReportResult::class);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('findChildResult')\n ->with($mockParent, 'podcast')\n ->willReturn($mockChild);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->findChildResult($mockParent, 'podcast');\n\n $this->assertSame($mockChild, $result);\n }\n\n #[DataProvider('calculateFromAndToDatePeriodDataProvider')]\n public function testCalculateFromAndToDatePeriod(string $frequency): void\n {\n Carbon::setTestNow(Carbon::parse('2025-06-15 12:00:00'));\n\n $result = $this->service->calculateFromAndToDatePeriod($frequency);\n\n $this->assertArrayHasKey('fromDate', $result);\n $this->assertArrayHasKey('toDate', $result);\n $this->assertInstanceOf(Carbon::class, $result['fromDate']);\n $this->assertInstanceOf(Carbon::class, $result['toDate']);\n\n Carbon::setTestNow();\n }\n\n public static function calculateFromAndToDatePeriodDataProvider(): array\n {\n return [\n 'daily' => ['daily'],\n 'weekly' => ['weekly'],\n 'monthly' => ['monthly'],\n 'quarterly' => ['quarterly'],\n ];\n }\n\n public function testCalculateFromAndToDatePeriodOneOff(): void\n {\n $from = IlluminateCarbon::parse('2025-01-01');\n $to = IlluminateCarbon::parse('2025-01-31');\n\n $result = $this->service->calculateFromAndToDatePeriod('one_off', $from, $to);\n\n $this->assertSame($from, $result['fromDate']);\n $this->assertSame($to, $result['toDate']);\n }\n\n public function testCalculateFromAndToDatePeriodInvalidFrequency(): void\n {\n $this->expectException(InvalidArgumentException::class);\n\n $this->service->calculateFromAndToDatePeriod('invalid_frequency');\n }\n\n public function testGetMediaPath(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PDF);\n $mockResult->method('getPdfUrl')->willReturn('https://example.com/reports/file.pdf');\n\n $result = $this->service->getMediaPath($mockResult);\n\n $this->assertEquals('/reports/file.pdf', $result);\n }\n\n public function testGetMediaPathPodcast(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PODCAST);\n $mockResult->method('getPodcastAudioUrl')->willReturn('https://example.com/audio/file.mp3');\n\n $result = $this->service->getMediaPath($mockResult);\n\n $this->assertEquals('/audio/file.mp3', $result);\n }\n\n public function testGetMediaPathNullUrl(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn('unknown_type');\n\n $result = $this->service->getMediaPath($mockResult);\n\n $this->assertNull($result);\n }\n\n public function testGetMediaPathPdfNullUrl(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PDF);\n $mockResult->method('getPdfUrl')->willReturn(null);\n\n $result = $this->service->getMediaPath($mockResult);\n\n $this->assertNull($result);\n }\n\n public function testGetFilenameSuffixPodcast(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PODCAST);\n\n $result = $this->service->getFilenameSuffix($mockResult);\n\n $this->assertEquals('Podcast', $result);\n }\n\n public function testGetFilenameSuffixPdf(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PDF);\n\n $result = $this->service->getFilenameSuffix($mockResult);\n\n $this->assertNull($result);\n }\n\n public function testGetMailSubjectSuffixPdf(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PDF);\n\n $result = $this->service->getMailSubjectSuffix($mockResult);\n\n $this->assertEquals('report', $result);\n }\n\n public function testGetMailSubjectSuffixPodcast(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PODCAST);\n\n $result = $this->service->getMailSubjectSuffix($mockResult);\n\n $this->assertEquals('podcast', $result);\n }\n\n public function testGetMailSubjectSuffixUnknown(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn('unknown_type');\n\n $result = $this->service->getMailSubjectSuffix($mockResult);\n\n $this->assertEquals('', $result);\n }\n\n public function testGetMediaTypeMetadataPdf(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PDF);\n\n $result = $this->service->getMediaTypeMetadata($mockResult);\n\n $this->assertEquals('pdf', $result['extension']);\n $this->assertEquals('application/pdf', $result['mime']);\n }\n\n public function testGetMediaTypeMetadataPodcast(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PODCAST);\n\n $result = $this->service->getMediaTypeMetadata($mockResult);\n\n $this->assertEquals('mp3', $result['extension']);\n $this->assertEquals('audio/mpeg', $result['mime']);\n }\n\n public function testGetMediaTypeMetadataUnknown(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getMediaType')->willReturn('unknown');\n\n $result = $this->service->getMediaTypeMetadata($mockResult);\n\n $this->assertNull($result['extension']);\n $this->assertNull($result['mime']);\n }\n\n public function testGetTeamIdsWithReportsResults(): void\n {\n $expected = new Collection([1, 2, 3]);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('getTeamIdsWithReportsResults')\n ->with(5)\n ->willReturn($expected);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->getTeamIdsWithReportsResults(5);\n\n $this->assertSame($expected, $result);\n }\n\n public function testGetTeamReports(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $expected = new \\Illuminate\\Database\\Eloquent\\Collection();\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('getReportsByTeam')\n ->with($mockTeam)\n ->willReturn($expected);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->getTeamReports($mockTeam);\n\n $this->assertSame($expected, $result);\n }\n\n public function testGetReportResults(): void\n {\n $mockReport = $this->createMock(AutomatedReport::class);\n $expected = new \\Illuminate\\Database\\Eloquent\\Collection();\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('getResultsByReport')\n ->with($mockReport)\n ->willReturn($expected);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->getReportResults($mockReport);\n\n $this->assertSame($expected, $result);\n }\n\n public function testDeleteReportsResultsInRetentionPeriodNoReports(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $retentionDate = \\Carbon\\CarbonImmutable::parse('2025-01-01');\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('getReportIdsByTeam')\n ->willReturn(new Collection([]));\n $mockRepo->expects($this->never())\n ->method('getReportResultsQueryForRetention');\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->deleteReportsResultsInRetentionPeriod($mockTeam, $retentionDate);\n\n $this->assertEquals(0, $result);\n }\n\n public function testDeleteReportsResultsInRetentionPeriodWithNoQueryResults(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $mockTeam->method('getId')->willReturn(1);\n $retentionDate = \\Carbon\\CarbonImmutable::parse('2025-01-01');\n\n $mockQuery = Mockery::mock(Builder::class);\n $mockQuery->shouldReceive('exists')->andReturn(false);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->method('getReportIdsByTeam')->willReturn(new Collection([1, 2]));\n $mockRepo->method('getReportResultsQueryForRetention')->willReturn($mockQuery);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n Log::shouldReceive('info')->zeroOrMoreTimes();\n\n $result = $service->deleteReportsResultsInRetentionPeriod($mockTeam, $retentionDate);\n\n $this->assertEquals(0, $result);\n }\n\n public function testUpdateAskJiminnyReportStatusNotAskJiminny(): void\n {\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('isAskJiminnyReport')->willReturn(false);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $mockUser = $this->createMock(User::class);\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Report is not an Ask Jiminny report');\n\n $service->updateAskJiminnyReport($mockReport, [], $mockUser);\n }\n\n public function testUpdateAskJiminnyReportStatusThrowsWhenEnablingWithMissingReferences(): void\n {\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->expects($this->once())\n ->method('isAskJiminnyReport')\n ->willReturn(true);\n $mockReport->expects($this->once())\n ->method('canExecute')\n ->willReturn(false);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->never())->method('update');\n\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $property = $reflection->getProperty('automatedReportsRepository');\n $property->setAccessible(true);\n $property->setValue($this->service, $mockRepo);\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('This report is missing a saved search or prompt.');\n\n $this->service->updateAskJiminnyReportStatus($mockReport, true);\n }\n\n public function testUpdateAskJiminnyReportStatusDoesNotValidateWhenDisabling(): void\n {\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->expects($this->never())->method('isAskJiminnyReport');\n $mockReport->expects($this->never())->method('canExecute');\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('update')\n ->with($mockReport, ['status' => false])\n ->willThrowException(new \\RuntimeException('stop-after-update'));\n\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $property = $reflection->getProperty('automatedReportsRepository');\n $property->setAccessible(true);\n $property->setValue($this->service, $mockRepo);\n\n $this->expectException(\\RuntimeException::class);\n $this->expectExceptionMessage('stop-after-update');\n\n $this->service->updateAskJiminnyReportStatus($mockReport, false);\n }\n\n public function testGetAskJiminnyReportFilters(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $mockSearch = $this->createMock(Search::class);\n $mockSearch->method('getUuid')->willReturn('search-uuid-1');\n $mockSearch->method('getName')->willReturn('My Search');\n\n $mockSearchRepository = $this->createMock(SearchRepository::class);\n $mockSearchRepository->expects($this->once())\n ->method('findByUserOrderedByName')\n ->with($mockUser)\n ->willReturn(new Collection([$mockSearch]));\n\n $mockPromptDto = new AskAnythingPromptDto(\n id: 'prompt-uuid-1',\n title: 'My Prompt',\n content: 'Prompt text',\n target: AskAnythingPromptTarget::on_demand,\n );\n\n $mockPromptService = $this->createMock(AskAnythingPromptService::class);\n $mockPromptService->expects($this->once())\n ->method('get')\n ->with($mockUser, AskAnythingPromptTarget::on_demand)\n ->willReturn([$mockPromptDto]);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $mockPromptService,\n $mockSearchRepository,\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->getAskJiminnyReportFilters($mockUser);\n\n $this->assertCount(2, $result);\n $promptFilter = collect($result)->firstWhere('id', 'prompt');\n $searchFilter = collect($result)->firstWhere('id', 'saved_search');\n\n $this->assertCount(1, $promptFilter['options']);\n $this->assertEquals('prompt-uuid-1', $promptFilter['options'][0]['id']);\n $this->assertCount(1, $searchFilter['options']);\n $this->assertEquals('search-uuid-1', $searchFilter['options'][0]['id']);\n }\n\n public function testGetAskJiminnyReportFormDataWithoutReport(): void\n {\n $timezone = new \\DateTimeZone('UTC');\n\n $mockUser = $this->createMock(User::class);\n $mockUser->method('getTimezone')->willReturn($timezone);\n\n $mockTeam = $this->createMock(Team::class);\n $mockUser->method('getTeam')->willReturn($mockTeam);\n\n $mockSearchRepository = $this->createMock(SearchRepository::class);\n $mockSearchRepository->method('findByUserOrderedByName')->willReturn(new Collection([]));\n\n $mockPromptService = $this->createMock(AskAnythingPromptService::class);\n $mockPromptService->method('get')->willReturn([]);\n\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n $mockGroupRepository->method('getAllByTeam')->willReturn(new \\Illuminate\\Database\\Eloquent\\Collection([]));\n\n $mockRecipientsService = $this->createMock(RecipientsService::class);\n $mockRecipientsService->method('getRecipientsFieldData')->willReturn(['options' => []]);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $mockRecipientsService,\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $mockPromptService,\n $mockSearchRepository,\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->getAskJiminnyReportFormData($mockUser);\n\n $this->assertArrayHasKey('fields', $result);\n $this->assertIsArray($result['fields']);\n\n $fieldIds = array_column($result['fields'], 'id');\n $this->assertContains('enabled', $fieldIds);\n $this->assertContains('report_name', $fieldIds);\n $this->assertContains('frequency', $fieldIds);\n $this->assertContains('expires_on', $fieldIds);\n $this->assertContains('saved_search', $fieldIds);\n $this->assertContains('ask_jiminny_prompt', $fieldIds);\n }\n\n public function testGetAskJiminnyReportFormDataWithReport(): void\n {\n $timezone = new \\DateTimeZone('UTC');\n\n $mockUser = $this->createMock(User::class);\n $mockUser->method('getTimezone')->willReturn($timezone);\n\n $mockTeam = $this->createMock(Team::class);\n $mockUser->method('getTeam')->willReturn($mockTeam);\n\n $mockSavedSearch = $this->createMock(Search::class);\n $mockSavedSearch->method('getUuid')->willReturn('search-uuid');\n $mockSavedSearch->method('getName')->willReturn('My Search');\n\n $mockPromptModel = $this->createMock(AskAnythingPrompt::class);\n $mockPromptModel->method('getUuid')->willReturn('prompt-uuid');\n $mockPromptModel->method('getTitle')->willReturn('My Prompt');\n\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getStatus')->willReturn(true);\n $mockReport->method('getCustomName')->willReturn('Test Report');\n $mockReport->method('getFrequency')->willReturn('daily');\n $mockReport->method('getExpiresAt')->willReturn(IlluminateCarbon::parse('2025-12-31'));\n $mockReport->method('getGroups')->willReturn([]);\n $mockReport->method('getRecipients')->willReturn(['users' => []]);\n $mockReport->method('getAttribute')->with('created_by')->willReturn(1);\n $mockReport->method('getSavedSearch')->willReturn($mockSavedSearch);\n $mockReport->method('getAskAnythingPrompt')->willReturn($mockPromptModel);\n\n $mockSearchRepository = $this->createMock(SearchRepository::class);\n $mockSearchRepository->method('findByUserOrderedByName')->willReturn(new Collection([]));\n\n $mockPromptService = $this->createMock(AskAnythingPromptService::class);\n $mockPromptService->method('get')->willReturn([]);\n\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n $mockGroupRepository->method('getAllByTeam')->willReturn(new \\Illuminate\\Database\\Eloquent\\Collection([]));\n\n $mockRecipientsService = $this->createMock(RecipientsService::class);\n $mockRecipientsService->method('getRecipientsFieldData')->willReturn(['options' => []]);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $mockRecipientsService,\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $mockPromptService,\n $mockSearchRepository,\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->getAskJiminnyReportFormData($mockUser, $mockReport);\n\n $fields = collect($result['fields'])->keyBy('id');\n\n $this->assertTrue($fields['enabled']['value']);\n $this->assertEquals('Test Report', $fields['report_name']['value']);\n }\n\n public function testValidateAskJiminnyReportDataMissingName(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Report name is required');\n\n $service->createAskJiminnyReport(['report_name' => ''], $mockUser);\n }\n\n public function testValidateAskJiminnyReportDataNameTooLong(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Report name must be 50 characters or less');\n\n $service->createAskJiminnyReport(['report_name' => str_repeat('a', 51)], $mockUser);\n }\n\n public function testValidateAskJiminnyReportDataInvalidFrequency(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Frequency must be daily, weekly, or monthly');\n\n $service->createAskJiminnyReport(['report_name' => 'Valid Name', 'frequency' => 'quarterly'], $mockUser);\n }\n\n public function testValidateAskJiminnyReportDataMissingExpiresOn(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Expiration date is required');\n\n $service->createAskJiminnyReport(\n ['report_name' => 'Valid Name', 'frequency' => 'daily'],\n $mockUser\n );\n }\n\n public function testValidateAskJiminnyReportDataExpiresInPast(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Expiration date cannot be in the past');\n\n $service->createAskJiminnyReport(\n ['report_name' => 'Valid Name', 'frequency' => 'daily', 'expires_on' => '2020-01-01'],\n $mockUser\n );\n }\n\n public function testValidateAskJiminnyReportDataExpiresTooFar(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Expiration date cannot be more than 1 year from now');\n\n $service->createAskJiminnyReport(\n ['report_name' => 'Valid Name', 'frequency' => 'daily', 'expires_on' => '2099-01-01'],\n $mockUser\n );\n }\n\n public function testValidateAskJiminnyReportDataExpiresExactlyOneYearLaterTimeOfDayIsAccepted(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-04-20 09:00:00'));\n\n try {\n $mockUser = $this->createMock(User::class);\n $mockUser->method('getId')->willReturn(1);\n $mockUser->method('getTeamId')->willReturn(1);\n\n $savedSearch = $this->createMock(Search::class);\n $savedSearch->method('getId')->willReturn(10);\n\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->method('getId')->willReturn(5);\n\n $activitySearchRepository = $this->createMock(SearchRepository::class);\n $activitySearchRepository->method('findByUuidAndUser')->willReturn($savedSearch);\n\n $askAnythingRepository = $this->createMock(AskAnythingRepository::class);\n $askAnythingRepository->method('getPromptByUuid')->willReturn($prompt);\n\n $automatedReportsRepository = $this->createMock(AutomatedReportsRepository::class);\n $automatedReportsRepository->method('create')->willReturn($this->createMock(AutomatedReport::class));\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $automatedReportsRepository,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $activitySearchRepository,\n $askAnythingRepository,\n );\n\n $service->createAskJiminnyReport([\n 'report_name' => 'Valid Name',\n 'frequency' => 'daily',\n 'expires_on' => '2027-04-20T23:00:00',\n 'saved_search' => 'some-uuid',\n 'ask_jiminny_prompt' => 'prompt-uuid',\n ], $mockUser);\n\n $this->assertTrue(true);\n } finally {\n Carbon::setTestNow();\n }\n }\n\n public function testValidateAskJiminnyReportDataMissingSavedSearch(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Saved search is required');\n\n $service->createAskJiminnyReport(\n ['report_name' => 'Valid Name', 'frequency' => 'daily', 'expires_on' => now()->addMonth()->toDateString()],\n $mockUser\n );\n }\n\n public function testValidateAskJiminnyReportDataSavedSearchNotFound(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $mockSearchRepository = $this->createMock(SearchRepository::class);\n $mockSearchRepository->method('findByUuidAndUser')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $mockSearchRepository,\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Saved search not found or does not belong to you');\n\n $service->createAskJiminnyReport(\n [\n 'report_name' => 'Valid Name',\n 'frequency' => 'daily',\n 'expires_on' => now()->addMonth()->toDateString(),\n 'saved_search' => 'non-existent-uuid',\n ],\n $mockUser\n );\n }\n\n public function testValidateAskJiminnyReportDataMissingPrompt(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $mockSearch = $this->createMock(Search::class);\n $mockSearchRepository = $this->createMock(SearchRepository::class);\n $mockSearchRepository->method('findByUuidAndUser')->willReturn($mockSearch);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $mockSearchRepository,\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Ask Jiminny prompt is required');\n\n $service->createAskJiminnyReport(\n [\n 'report_name' => 'Valid Name',\n 'frequency' => 'daily',\n 'expires_on' => now()->addMonth()->toDateString(),\n 'saved_search' => 'search-uuid',\n ],\n $mockUser\n );\n }\n\n public function testValidateAskJiminnyReportDataPromptNotFound(): void\n {\n $mockUser = $this->createMock(User::class);\n\n $mockSearch = $this->createMock(Search::class);\n $mockSearchRepository = $this->createMock(SearchRepository::class);\n $mockSearchRepository->method('findByUuidAndUser')->willReturn($mockSearch);\n\n $mockAskAnythingRepository = $this->createMock(AskAnythingRepository::class);\n $mockAskAnythingRepository->method('getPromptByUuid')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $mockSearchRepository,\n $mockAskAnythingRepository,\n );\n\n $this->expectException(InvalidArgumentException::class);\n $this->expectExceptionMessage('Ask Jiminny prompt not found');\n\n $service->createAskJiminnyReport(\n [\n 'report_name' => 'Valid Name',\n 'frequency' => 'daily',\n 'expires_on' => now()->addMonth()->toDateString(),\n 'saved_search' => 'search-uuid',\n 'ask_jiminny_prompt' => 'non-existent-prompt-uuid',\n ],\n $mockUser\n );\n }\n\n public function testTransformRecipientsWithNullUsers(): void\n {\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $method = $reflection->getMethod('transformRecipients');\n $method->setAccessible(true);\n\n $result = $method->invoke($this->service, []);\n\n $this->assertEquals([], $result);\n }\n\n public function testTransformRecipientsWithUsersKey(): void\n {\n $mockUser = $this->createMock(User::class);\n $mockUser->method('getUuid')->willReturn('user-uuid-1');\n $mockUser->method('getName')->willReturn('User One');\n $mockUser->method('getEmailAddress')->willReturn('user1@test.com');\n $mockUser->method('getPhotoUrl')->willReturn(null);\n\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturn($mockUser);\n\n $service = $this->getService(mockUserRepository: $mockUserRepository);\n\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $method = $reflection->getMethod('transformRecipients');\n $method->setAccessible(true);\n\n $result = $method->invoke($service, ['users' => [1]]);\n\n $this->assertCount(1, $result);\n $this->assertEquals('user-uuid-1', $result[0]['id']);\n }\n\n public function testGetTeamsGroupsOptions(): void\n {\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n\n $mockTeam = $this->createMock(Team::class);\n $mockTeam->method('getUuid')->willReturn('team-uuid-1');\n $mockTeam->method('getName')->willReturn('Sales Team');\n $mockTeam->method('hasFeature')\n ->with(FeatureEnum::AUTOMATED_REPORTS)\n ->willReturn(true);\n\n $mockGroupsRelation = $this->createMock(HasMany::class);\n $mockGroupsRelation->method('get')->willReturn(new \\Illuminate\\Database\\Eloquent\\Collection([]));\n $mockTeam->method('groups')->willReturn($mockGroupsRelation);\n\n $mockTeamRepository->method('getTeamsForKiosk')->willReturn(new Collection([$mockTeam]));\n $mockTeamRepository->method('idOrUuid')->willReturn($mockTeam);\n\n $service = $this->getService(mockTeamRepository: $mockTeamRepository);\n\n $result = $service->getTeamsGroupsOptions();\n\n $this->assertCount(1, $result);\n $this->assertEquals('Sales Team', $result[0]['label']);\n $this->assertArrayHasKey('groups', $result[0]);\n }\n\n public function testGetTeamsGroupsOptionsWithFilter(): void\n {\n $mockTeamRepository = $this->createMock(TeamRepository::class);\n\n $mockTeam1 = $this->createMock(Team::class);\n $mockTeam1->method('getUuid')->willReturn('team-uuid-1');\n $mockTeam1->method('getName')->willReturn('Sales Team');\n $mockTeam1->method('hasFeature')->willReturn(true);\n\n $mockTeam2 = $this->createMock(Team::class);\n $mockTeam2->method('getUuid')->willReturn('team-uuid-2');\n $mockTeam2->method('getName')->willReturn('Marketing Team');\n $mockTeam2->method('hasFeature')->willReturn(true);\n\n $mockTeamRepository->method('getTeamsForKiosk')\n ->willReturn(new Collection([$mockTeam1, $mockTeam2]));\n\n $mockGroupsRelation = $this->createMock(HasMany::class);\n $mockGroupsRelation->method('get')->willReturn(new \\Illuminate\\Database\\Eloquent\\Collection([]));\n $mockTeam1->method('groups')->willReturn($mockGroupsRelation);\n\n $mockTeamRepository->method('idOrUuid')->willReturn($mockTeam1);\n\n $service = $this->getService(mockTeamRepository: $mockTeamRepository);\n\n $result = $service->getTeamsGroupsOptions(['team-uuid-1']);\n\n $this->assertCount(1, $result);\n $this->assertEquals('Sales Team', $result[0]['label']);\n }\n\n public function testGetReturnsTransformedReport(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getType')->willReturn('exec_summary');\n $mockReport->method('getUuid')->willReturn('report-uuid');\n $mockReport->method('getFrequency')->willReturn('weekly');\n $mockReport->method('getTeam')->willReturn($mockTeam);\n $mockReport->method('getStatus')->willReturn(true);\n $mockReport->method('getFrom')->willReturn(null);\n $mockReport->method('getTo')->willReturn(null);\n $mockReport->method('getDealValueMin')->willReturn(null);\n $mockReport->method('getDealValueMax')->willReturn(null);\n $mockReport->method('getCallTypes')->willReturn([]);\n $mockReport->method('getMediaTypes')->willReturn([]);\n $mockReport->method('getCallDurationMin')->willReturn(null);\n $mockReport->method('getCallDurationMax')->willReturn(null);\n $mockReport->method('getGroups')->willReturn([]);\n $mockReport->method('getDealAtCallStages')->willReturn([]);\n $mockReport->method('getCurrentDealStages')->willReturn([]);\n $mockReport->method('getRecipients')->willReturn([]);\n $mockReport->method('getCreator')->willReturn(null);\n $mockReport->method('getAdditionalPromptInput')->willReturn(null);\n $mockReport->method('getCustomName')->willReturn('My Report');\n $mockReport->method('getCreatedAt')->willReturn(IlluminateCarbon::parse('2025-01-01'));\n $mockReport->method('getUpdatedAt')->willReturn(IlluminateCarbon::parse('2025-01-01'));\n $mockReport->method('getDeletedAt')->willReturn(null);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('findByUuid')\n ->with('report-uuid')\n ->willReturn($mockReport);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->get('report-uuid');\n\n $this->assertIsArray($result);\n $this->assertEquals('report-uuid', $result['id']);\n }\n\n public function testGetThrowsWhenReportNotFound(): void\n {\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->method('findByUuid')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(ModelNotFoundException::class);\n\n $service->get('missing-uuid');\n }\n\n public function testListReturnsData(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getType')->willReturn('exec_summary');\n $mockReport->method('getUuid')->willReturn('report-uuid');\n $mockReport->method('getFrequency')->willReturn('weekly');\n $mockReport->method('getTeam')->willReturn($mockTeam);\n $mockReport->method('getStatus')->willReturn(true);\n $mockReport->method('getFrom')->willReturn(null);\n $mockReport->method('getTo')->willReturn(null);\n $mockReport->method('getDealValueMin')->willReturn(null);\n $mockReport->method('getDealValueMax')->willReturn(null);\n $mockReport->method('getCallTypes')->willReturn([]);\n $mockReport->method('getMediaTypes')->willReturn([]);\n $mockReport->method('getCallDurationMin')->willReturn(null);\n $mockReport->method('getCallDurationMax')->willReturn(null);\n $mockReport->method('getGroups')->willReturn([]);\n $mockReport->method('getDealAtCallStages')->willReturn([]);\n $mockReport->method('getCurrentDealStages')->willReturn([]);\n $mockReport->method('getRecipients')->willReturn([]);\n $mockReport->method('getCreator')->willReturn(null);\n $mockReport->method('getAdditionalPromptInput')->willReturn(null);\n $mockReport->method('getCustomName')->willReturn('My Report');\n $mockReport->method('getCreatedAt')->willReturn(IlluminateCarbon::parse('2025-01-01'));\n $mockReport->method('getUpdatedAt')->willReturn(IlluminateCarbon::parse('2025-01-01'));\n $mockReport->method('getDeletedAt')->willReturn(null);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('getAllStandardReports')\n ->willReturn(new \\Illuminate\\Database\\Eloquent\\Collection([$mockReport]));\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->list();\n\n $this->assertArrayHasKey('data', $result);\n $this->assertCount(1, $result['data']);\n }\n\n public function testListAskJiminnyReportsReturnsData(): void\n {\n $mockUser = $this->createMock(User::class);\n $mockTeam = $this->createMock(Team::class);\n\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getType')->willReturn('ask_jiminny');\n $mockReport->method('getUuid')->willReturn('report-uuid');\n $mockReport->method('getFrequency')->willReturn('daily');\n $mockReport->method('getTeam')->willReturn($mockTeam);\n $mockReport->method('getStatus')->willReturn(true);\n $mockReport->method('getGroups')->willReturn([]);\n $mockReport->method('getRecipients')->willReturn([]);\n $mockReport->method('getCustomName')->willReturn('AJ Report');\n $mockReport->method('getExpiresAt')->willReturn(null);\n $mockReport->method('getSavedSearch')->willReturn(null);\n $mockReport->method('getAskAnythingPrompt')->willReturn(null);\n $mockReport->method('getAttribute')->with('created_by')->willReturn(null);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('getAskJiminnyReportsByUser')\n ->with($mockUser, 'created_at', 'desc')\n ->willReturn(new \\Illuminate\\Database\\Eloquent\\Collection([$mockReport]));\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->listAskJiminnyReports($mockUser);\n\n $this->assertArrayHasKey('data', $result);\n $this->assertCount(1, $result['data']);\n }\n\n public function testGetActivityTypesFieldDataDelegatesToService(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $mockActivityTypeService = $this->createMock(ActivityTypeService::class);\n $mockActivityTypeService->expects($this->once())\n ->method('getActivityTypeFieldData')\n ->with(team: $mockTeam, value: ['a'], groupIds: ['g1'])\n ->willReturn(['id' => 'activity_types', 'options' => []]);\n\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $service = $reflection->newInstanceWithoutConstructor();\n $prop = $reflection->getProperty('activityTypeService');\n $prop->setAccessible(true);\n $prop->setValue($service, $mockActivityTypeService);\n\n $result = $service->getActivityTypesFieldData($mockTeam, ['a'], ['g1']);\n\n $this->assertEquals(['id' => 'activity_types', 'options' => []], $result);\n }\n\n public function testGetDealStageAtCallFieldDataDelegatesToService(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $mockDealStagesService = $this->createMock(DealStagesService::class);\n $mockDealStagesService->expects($this->once())\n ->method('getDealStageAtCallFieldData')\n ->with(team: $mockTeam, value: [])\n ->willReturn(['id' => 'deal_stage_at_call']);\n\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $service = $reflection->newInstanceWithoutConstructor();\n $prop = $reflection->getProperty('dealStagesService');\n $prop->setAccessible(true);\n $prop->setValue($service, $mockDealStagesService);\n\n $result = $service->getDealStageAtCallFieldData($mockTeam);\n\n $this->assertEquals(['id' => 'deal_stage_at_call'], $result);\n }\n\n public function testGetCurrentDealStageFieldDataDelegatesToService(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $mockDealStagesService = $this->createMock(DealStagesService::class);\n $mockDealStagesService->expects($this->once())\n ->method('getCurrentDealStageFieldData')\n ->with(team: $mockTeam, value: [])\n ->willReturn(['id' => 'current_deal_stage']);\n\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $service = $reflection->newInstanceWithoutConstructor();\n $prop = $reflection->getProperty('dealStagesService');\n $prop->setAccessible(true);\n $prop->setValue($service, $mockDealStagesService);\n\n $result = $service->getCurrentDealStageFieldData($mockTeam);\n\n $this->assertEquals(['id' => 'current_deal_stage'], $result);\n }\n\n public function testGetRecipientsFieldDataDelegatesToService(): void\n {\n $mockTeam = $this->createMock(Team::class);\n $mockRecipientsService = $this->createMock(RecipientsService::class);\n $mockRecipientsService->expects($this->once())\n ->method('getRecipientsFieldData')\n ->with(team: $mockTeam, value: [])\n ->willReturn(['id' => 'recipients']);\n\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $service = $reflection->newInstanceWithoutConstructor();\n $prop = $reflection->getProperty('recipientsService');\n $prop->setAccessible(true);\n $prop->setValue($service, $mockRecipientsService);\n\n $result = $service->getRecipientsFieldData($mockTeam);\n\n $this->assertEquals(['id' => 'recipients'], $result);\n }\n\n public function testGetJiminnyRecipientsFieldDataDelegatesToService(): void\n {\n $mockRecipientsService = $this->createMock(RecipientsService::class);\n $mockRecipientsService->expects($this->once())\n ->method('getJiminnyRecipientsFieldData')\n ->with(['user-1'])\n ->willReturn(['id' => 'jiminny_recipients']);\n\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $service = $reflection->newInstanceWithoutConstructor();\n $prop = $reflection->getProperty('recipientsService');\n $prop->setAccessible(true);\n $prop->setValue($service, $mockRecipientsService);\n\n $result = $service->getJiminnyRecipientsFieldData(['user-1']);\n\n $this->assertEquals(['id' => 'jiminny_recipients'], $result);\n }\n\n public function testCreateReportResultDelegatesToRepository(): void\n {\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getId')->willReturn(42);\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('createResult')\n ->willReturn($mockResult);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $result = $service->createReportResult($mockReport);\n\n $this->assertSame($mockResult, $result);\n }\n\n public function testDeleteReportResultDeletesS3AndModel(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getReport')->willReturn($this->createMock(AutomatedReport::class));\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PDF);\n $mockResult->expects($this->once())->method('delete');\n\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $service = $reflection->newInstanceWithoutConstructor();\n\n foreach ([\n 'teamRepository' => TeamRepository::class,\n 'groupRepository' => GroupRepository::class,\n 'userRepository' => UserRepository::class,\n 'stageRepository' => StageRepository::class,\n 'dealStagesService' => DealStagesService::class,\n 'recipientsService' => RecipientsService::class,\n 'automatedReportsRepository' => AutomatedReportsRepository::class,\n 'webhookService' => Webhook::class,\n 'dispatcher' => Dispatcher::class,\n 'activityTypeService' => ActivityTypeService::class,\n 'playbookCategoryRepository' => PlaybookCategoryRepository::class,\n 'askAnythingPromptService' => AskAnythingPromptService::class,\n 'activitySearchRepository' => SearchRepository::class,\n 'askAnythingRepository' => AskAnythingRepository::class,\n ] as $propName => $class) {\n $prop = $reflection->getProperty($propName);\n $prop->setAccessible(true);\n $prop->setValue($service, $this->createMock($class));\n }\n\n Storage::shouldReceive('exists')->andReturn(false);\n Log::shouldReceive('info')->zeroOrMoreTimes();\n\n $service->deleteReportResult($mockResult);\n }\n\n public function testDeleteAllReportResultsIteratesAndDeletes(): void\n {\n $mockResult1 = $this->createMock(AutomatedReportResult::class);\n $mockResult1->method('getId')->willReturn(1);\n $mockResult1->method('getReport')->willReturn($this->createMock(AutomatedReport::class));\n $mockResult1->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PDF);\n $mockResult1->expects($this->once())->method('delete');\n\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getId')->willReturn(10);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('getResultsByReport')\n ->with($mockReport)\n ->willReturn(new \\Illuminate\\Database\\Eloquent\\Collection([$mockResult1]));\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n Storage::shouldReceive('exists')->andReturn(false);\n Log::shouldReceive('info')->zeroOrMoreTimes();\n\n $service->deleteAllReportResults($mockReport);\n }\n\n public function testDeleteAllDataDeletesReportsAndResults(): void\n {\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getId')->willReturn(1);\n $mockResult->method('getReport')->willReturn($this->createMock(AutomatedReport::class));\n $mockResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PDF);\n $mockResult->expects($this->once())->method('delete');\n\n $mockReport = $this->createMock(AutomatedReport::class);\n $mockReport->method('getId')->willReturn(10);\n $mockReport->expects($this->once())->method('delete');\n\n $mockTeam = $this->createMock(Team::class);\n $mockTeam->method('getId')->willReturn(1);\n\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->expects($this->once())\n ->method('getReportsByTeam')\n ->with($mockTeam)\n ->willReturn(new \\Illuminate\\Database\\Eloquent\\Collection([$mockReport]));\n $mockRepo->expects($this->once())\n ->method('getResultsByReport')\n ->with($mockReport)\n ->willReturn(new \\Illuminate\\Database\\Eloquent\\Collection([$mockResult]));\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n Storage::shouldReceive('exists')->andReturn(false);\n Log::shouldReceive('info')->zeroOrMoreTimes();\n\n $service->deleteAllData($mockTeam);\n }\n\n public function testDeleteReportResultsThrowsWhenReportNotFound(): void\n {\n $mockRepo = $this->createMock(AutomatedReportsRepository::class);\n $mockRepo->method('findByUuid')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $this->createMock(UserRepository::class),\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $mockRepo,\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $this->expectException(ModelNotFoundException::class);\n\n $service->deleteReportResults('missing-uuid');\n }\n\n public function testGetValidRecipientUsersAskJiminnyIncludesCreator(): void\n {\n $tz = $this->createMock(\\DateTimeZone::class);\n $tz->method('getName')->willReturn('UTC');\n\n $creator = $this->createMock(User::class);\n $creator->method('getEmailAddress')->willReturn('creator@test.com');\n $creator->method('getName')->willReturn('Creator');\n $creator->method('getTimezone')->willReturn($tz);\n\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturn($creator);\n\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n $mockGroupRepository->method('find')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $mockUserRepository,\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getRecipients')->willReturn(['users' => []]);\n $report->method('getGroups')->willReturn([]);\n\n $result = $service->getValidRecipientUsers($report);\n\n $this->assertCount(1, $result);\n $this->assertEquals('creator@test.com', $result[0]['email']);\n }\n\n public function testGetValidRecipientUsersAskJiminnyDeduplicatesCreatorAndExplicitRecipient(): void\n {\n $tz = $this->createMock(\\DateTimeZone::class);\n $tz->method('getName')->willReturn('UTC');\n\n $creator = $this->createMock(User::class);\n $creator->method('getEmailAddress')->willReturn('shared@test.com');\n $creator->method('getName')->willReturn('Creator');\n $creator->method('getTimezone')->willReturn($tz);\n\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturn($creator);\n\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n $mockGroupRepository->method('find')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $mockUserRepository,\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getRecipients')->willReturn(['users' => [1]]);\n $report->method('getGroups')->willReturn([]);\n\n $result = $service->getValidRecipientUsers($report);\n\n $this->assertCount(1, $result);\n $this->assertEquals('shared@test.com', $result[0]['email']);\n }\n\n public function testGetValidRecipientUsersAskJiminnyIncludesGroupMembers(): void\n {\n $tz = $this->createMock(\\DateTimeZone::class);\n $tz->method('getName')->willReturn('UTC');\n\n $creator = $this->createMock(User::class);\n $creator->method('getEmailAddress')->willReturn('creator@test.com');\n $creator->method('getName')->willReturn('Creator');\n $creator->method('getTimezone')->willReturn($tz);\n\n $member = $this->createMock(User::class);\n $member->method('getEmailAddress')->willReturn('member@test.com');\n $member->method('getName')->willReturn('Member');\n $member->method('getTimezone')->willReturn($tz);\n\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturn($creator);\n\n $mockGroup = $this->createMock(Group::class);\n $mockGroup->method('getMembers')->willReturn(new \\Illuminate\\Database\\Eloquent\\Collection([$member]));\n\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n $mockGroupRepository->method('find')->willReturn($mockGroup);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $mockUserRepository,\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn($creator);\n $report->method('getRecipients')->willReturn(['users' => []]);\n $report->method('getGroups')->willReturn([10]);\n\n $result = $service->getValidRecipientUsers($report);\n\n $this->assertCount(2, $result);\n $emails = array_column($result, 'email');\n $this->assertContains('creator@test.com', $emails);\n $this->assertContains('member@test.com', $emails);\n }\n\n public function testGetValidRecipientUsersAskJiminnyNullCreatorSkipped(): void\n {\n $tz = $this->createMock(\\DateTimeZone::class);\n $tz->method('getName')->willReturn('UTC');\n\n $shareUser = $this->createMock(User::class);\n $shareUser->method('getEmailAddress')->willReturn('shared@test.com');\n $shareUser->method('getName')->willReturn('Shared');\n $shareUser->method('getTimezone')->willReturn($tz);\n\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturnMap([\n [1, null],\n [2, $shareUser],\n ]);\n\n $mockGroupRepository = $this->createMock(GroupRepository::class);\n $mockGroupRepository->method('find')->willReturn(null);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $mockGroupRepository,\n $mockUserRepository,\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(true);\n $report->method('getCreator')->willReturn(null);\n $report->method('getRecipients')->willReturn(['users' => [2]]);\n $report->method('getGroups')->willReturn([]);\n\n $result = $service->getValidRecipientUsers($report);\n\n $this->assertCount(1, $result);\n $this->assertEquals('shared@test.com', $result[0]['email']);\n }\n\n public function testGetValidRecipientUsersStandardReportDoesNotIncludeCreator(): void\n {\n $tz = $this->createMock(\\DateTimeZone::class);\n $tz->method('getName')->willReturn('UTC');\n\n $user = $this->createMock(User::class);\n $user->method('getEmailAddress')->willReturn('user@test.com');\n $user->method('getName')->willReturn('User');\n $user->method('getTimezone')->willReturn($tz);\n\n $mockUserRepository = $this->createMock(UserRepository::class);\n $mockUserRepository->method('find')->willReturn($user);\n\n $service = new AutomatedReportsService(\n $this->createMock(TeamRepository::class),\n $this->createMock(GroupRepository::class),\n $mockUserRepository,\n $this->createMock(StageRepository::class),\n $this->createMock(DealStagesService::class),\n $this->createMock(RecipientsService::class),\n $this->createMock(AutomatedReportsRepository::class),\n $this->createMock(Webhook::class),\n $this->createMock(Dispatcher::class),\n $this->createMock(ActivityTypeService::class),\n $this->createMock(PlaybookCategoryRepository::class),\n $this->createMock(AskAnythingPromptService::class),\n $this->createMock(SearchRepository::class),\n $this->createMock(AskAnythingRepository::class),\n );\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('isAskJiminnyReport')->willReturn(false);\n $report->method('getRecipients')->willReturn(['users' => [5]]);\n $report->method('getJiminnyRecipients')->willReturn(['users' => []]);\n $report->method('getGroups')->willReturn([]);\n\n $result = $service->getValidRecipientUsers($report);\n\n $this->assertCount(1, $result);\n $this->assertEquals('user@test.com', $result[0]['email']);\n }\n\n public function testGetReportPeriodNameAskJiminnyMonthlyFallback(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-03-07 00:00:00'));\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getFrequency')->willReturn('monthly');\n $report->method('isAskJiminnyReport')->willReturn(true);\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getReport')->willReturn($report);\n $mockResult->method('getFromDate')->willReturn(null);\n $mockResult->method('getToDate')->willReturn(null);\n\n $result = $this->service->getReportPeriodName($mockResult);\n\n $this->assertMatchesRegularExpression('/^[A-Z][a-z]+ \\d{4}$/', $result);\n $this->assertStringContainsString('2026', $result);\n\n Carbon::setTestNow();\n }\n\n public function testGetReportPeriodNameAskJiminnyWeeklyFallback(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-04-07 00:00:00'));\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getFrequency')->willReturn('weekly');\n $report->method('isAskJiminnyReport')->willReturn(true);\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getReport')->willReturn($report);\n $mockResult->method('getFromDate')->willReturn(null);\n $mockResult->method('getToDate')->willReturn(null);\n\n $result = $this->service->getReportPeriodName($mockResult);\n\n $this->assertStringContainsString(' - ', $result);\n $this->assertStringContainsString('2026', $result);\n\n Carbon::setTestNow();\n }\n\n public function testGetReportPeriodNameAskJiminnyDailyFallback(): void\n {\n Carbon::setTestNow(Carbon::parse('2026-04-07 00:00:00'));\n\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getFrequency')->willReturn('daily');\n $report->method('isAskJiminnyReport')->willReturn(true);\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getReport')->willReturn($report);\n $mockResult->method('getFromDate')->willReturn(null);\n $mockResult->method('getToDate')->willReturn(null);\n\n $result = $this->service->getReportPeriodName($mockResult);\n\n $this->assertStringNotContainsString(' - ', $result);\n $this->assertStringContainsString('2026', $result);\n\n Carbon::setTestNow();\n }\n\n public function testGetReportPeriodNameAskJiminnyWithExplicitDates(): void\n {\n $report = $this->createMock(AutomatedReport::class);\n $report->method('getFrequency')->willReturn('monthly');\n $report->method('isAskJiminnyReport')->willReturn(true);\n\n $mockResult = $this->createMock(AutomatedReportResult::class);\n $mockResult->method('getReport')->willReturn($report);\n $mockResult->method('getFromDate')->willReturn(IlluminateCarbon::parse('2026-02-07'));\n $mockResult->method('getToDate')->willReturn(IlluminateCarbon::parse('2026-03-07'));\n\n $result = $this->service->getReportPeriodName($mockResult);\n\n $this->assertEquals('Feb 2026', $result);\n }\n\n public function testGetReportThrowsWhenNotFound(): void\n {\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $property = $reflection->getProperty('automatedReportsRepository');\n $property->setAccessible(true);\n /** @var AutomatedReportsRepository&\\PHPUnit\\Framework\\MockObject\\MockObject $mockRepo */\n $mockRepo = $property->getValue($this->service);\n\n $mockRepo->expects($this->once())\n ->method('findByUuid')\n ->with('missing-uuid')\n ->willReturn(null);\n\n $this->expectException(ModelNotFoundException::class);\n $this->service->getReport('missing-uuid');\n }\n\n public function testGetReportWithDefaultPartnerSkipsPartnerCheck(): void\n {\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $property = $reflection->getProperty('automatedReportsRepository');\n $property->setAccessible(true);\n /** @var AutomatedReportsRepository&\\PHPUnit\\Framework\\MockObject\\MockObject $mockRepo */\n $mockRepo = $property->getValue($this->service);\n\n $report = new AutomatedReport();\n $mockRepo->expects($this->once())\n ->method('findByUuid')\n ->willReturn($report);\n\n $partner = $this->createMock(Partner::class);\n $partner->method('isDefaultPartner')->willReturn(true);\n\n $result = $this->service->getReport('some-uuid', $partner);\n $this->assertSame($report, $result);\n }\n\n public function testGetReportWithNonDefaultPartnerAndMatchingPartnerIdReturnsReport(): void\n {\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $property = $reflection->getProperty('automatedReportsRepository');\n $property->setAccessible(true);\n /** @var AutomatedReportsRepository&\\PHPUnit\\Framework\\MockObject\\MockObject $mockRepo */\n $mockRepo = $property->getValue($this->service);\n\n $partnerId = 5;\n $team = new Team();\n $team->partner_id = $partnerId;\n\n $report = new AutomatedReport();\n $report->setRelation('team', $team);\n\n $mockRepo->expects($this->once())\n ->method('findByUuid')\n ->willReturn($report);\n\n $partner = $this->createMock(Partner::class);\n $partner->method('isDefaultPartner')->willReturn(false);\n $partner->method('getId')->willReturn($partnerId);\n\n $result = $this->service->getReport('some-uuid', $partner);\n $this->assertSame($report, $result);\n }\n\n public function testGetReportWithNonDefaultPartnerAndMismatchedPartnerIdThrows(): void\n {\n $reflection = new \\ReflectionClass(AutomatedReportsService::class);\n $property = $reflection->getProperty('automatedReportsRepository');\n $property->setAccessible(true);\n /** @var AutomatedReportsRepository&\\PHPUnit\\Framework\\MockObject\\MockObject $mockRepo */\n $mockRepo = $property->getValue($this->service);\n\n $team = new Team();\n $team->partner_id = 5;\n\n $report = new AutomatedReport();\n $report->setRelation('team', $team);\n\n $mockRepo->expects($this->once())\n ->method('findByUuid')\n ->willReturn($report);\n\n $partner = $this->createMock(Partner::class);\n $partner->method('isDefaultPartner')->willReturn(false);\n $partner->method('getId')->willReturn(2);\n\n $this->expectException(ModelNotFoundException::class);\n $this->service->getReport('some-uuid', $partner);\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,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-2323342501844778216
|
-1412888448243747095
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
16
104
73
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Services\Kiosk\AutomatedReports;
use Carbon\Carbon;
use Illuminate\Support\Carbon as IlluminateCarbon;
use Illuminate\Contracts\Bus\Dispatcher;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Relations\HasMany;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Jiminny\Component\AskAnything\AskAnythingPromptService;
use Jiminny\Component\AskAnything\Dtos\AskAnythingPromptDto;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Contracts\Repositories\PlaybookCategoryRepository;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Contracts\Repositories\UserRepository;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Exceptions\ModelNotFoundException;
use Illuminate\Support\Collection;
use Jiminny\Models\AskAnything\AskAnythingPrompt;
use Jiminny\Models\AskAnything\AskAnythingPromptTarget;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Group;
use Jiminny\Models\Partner;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Repositories\AskAnythingRepository;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Repositories\GroupRepository;
use Jiminny\Repositories\SearchRepository;
use Jiminny\Repositories\StageRepository;
use Jiminny\Services\Kiosk\AutomatedReports\ActivityTypeService;
use Jiminny\Services\Kiosk\AutomatedReports\AutomatedReportsService;
use Jiminny\Services\Kiosk\AutomatedReports\DealStagesService;
use Jiminny\Services\Kiosk\AutomatedReports\RecipientsService;
use Mockery;
use PHPUnit\Framework\Attributes\DataProvider;
use Tests\TestCase;
class AutomatedReportsServiceTest extends TestCase
{
private AutomatedReportsService $service;
protected function setUp(): void
{
parent::setUp();
// Create a real instance of the service without calling the constructor
$reflection = new \ReflectionClass(AutomatedReportsService::class);
$this->service = $reflection->newInstanceWithoutConstructor();
// Manually set the dependencies using reflection
$dependencies = [
'teamRepository' => TeamRepository::class,
'groupRepository' => GroupRepository::class,
'userRepository' => UserRepository::class,
'stageRepository' => StageRepository::class,
'dealStagesService' => DealStagesService::class,
'recipientsService' => RecipientsService::class,
'automatedReportsRepository' => AutomatedReportsRepository::class,
'webhookService' => Webhook::class,
'dispatcher' => Dispatcher::class,
'activityTypeService' => ActivityTypeService::class,
'playbookCategoryRepository' => PlaybookCategoryRepository::class,
'askAnythingPromptService' => AskAnythingPromptService::class,
'activitySearchRepository' => SearchRepository::class,
'askAnythingRepository' => AskAnythingRepository::class,
];
foreach ($dependencies as $propertyName => $class) {
$property = $reflection->getProperty($propertyName);
$property->setAccessible(true);
$property->setValue($this->service, $this->createMock($class));
}
}
protected function tearDown(): void
{
parent::tearDown();
Mockery::close();
}
private function getService(
$mockUserRepository = null,
$mockStageRepository = null,
$mockTeamRepository = null,
): AutomatedReportsService {
return new AutomatedReportsService(
($mockTeamRepository ?? $this->createMock(TeamRepository::class)),
$this->createMock(GroupRepository::class),
($mockUserRepository ?? $this->createMock(UserRepository::class)),
($mockStageRepository ?? $this->createMock(StageRepository::class)),
$this->createMock(DealStagesService::class),
$this->createMock(RecipientsService::class),
$this->createMock(AutomatedReportsRepository::class),
$this->createMock(Webhook::class),
$this->createMock(Dispatcher::class),
$this->createMock(ActivityTypeService::class),
$this->createMock(PlaybookCategoryRepository::class),
$this->createMock(AskAnythingPromptService::class),
$this->createMock(SearchRepository::class),
$this->createMock(AskAnythingRepository::class),
);
}
#[DataProvider('transformMediaTypesDataProvider')]
public function testTransformMediaTypes(array $mediaTypes, array $expected): void
{
$report = new AutomatedReport(['media_types' => $mediaTypes]);
$reflection = new \ReflectionClass(AutomatedReportsService::class);
$method = $reflection->getMethod('transformMediaTypes');
$result = $method->invoke($this->service, $report);
$this->assertEquals($expected, $result);
}
public function testGetMediaTypeFieldDataWithoutReport(): void
{
$result = $this->service->getMediaTypeFieldData(null);
$this->assertIsArray($result);
$this->assertArrayHasKey('value', $result);
$this->assertEmpty($result['value']);
$this->assertEquals('media_types', $result['id']);
}
public function testGetMediaTypeFieldDataWithReport(): void
{
$mediaTypes = ['pdf', 'podcast'];
$report = new AutomatedReport(['media_types' => $mediaTypes]);
$result = $this->service->getMediaTypeFieldData($report);
$expectedValue = [
['id' => 'pdf', 'name' => 'PDF'],
['id' => 'podcast', 'name' => 'Podcast'],
];
$this->assertIsArray($result);
$this->assertArrayHasKey('value', $result);
$this->assertEquals($expectedValue, $result['value']);
}
public static function transformMediaTypesDataProvider(): array
{
return [
'empty array' => [
'mediaTypes' => [],
'expected' => [],
],
'pdf only' => [
'mediaTypes' => ['pdf'],
'expected' => [
['id' => 'pdf', 'name' => 'PDF'],
],
],
'podcast only' => [
'mediaTypes' => ['podcast'],
'expected' => [
['id' => 'podcast', 'name' => 'Podcast'],
],
],
'both pdf and podcast' => [
'mediaTypes' => ['pdf', 'podcast'],
'expected' => [
['id' => 'pdf', 'name' => 'PDF'],
['id' => 'podcast', 'name' => 'Podcast'],
],
],
'with invalid type' => [
'mediaTypes' => ['pdf', 'invalid', 'podcast'],
'expected' => [
['id' => 'pdf', 'name' => 'PDF'],
['id' => 'podcast', 'name' => 'Podcast'],
],
],
];
}
#[DataProvider('hasCallTypeConferenceDataProvider')]
public function testHasCallTypeConference(array $callTypes, bool $expected): void
{
$report = $this->createMock(AutomatedReport::class);
$report->method('getCallTypes')->willReturn($callTypes);
$result = $this->service->hasCallTypeConference($report);
$this->assertEquals($expected, $result);
}
#[DataProvider('hasCallTypeDialerDataProvider')]
public function testHasCallTypeDialer(array $callTypes, bool $expected): void
{
$report = $this->createMock(AutomatedReport::class);
$report->method('getCallTypes')->willReturn($callTypes);
$result = $this->service->hasCallTypeDialer($report);
$this->assertEquals($expected, $result);
}
public static function hasCallTypeConferenceDataProvider(): array
{
return [
'has conference' => [
'callTypes' => ['conference', 'dialer'],
'expected' => true,
],
'does not have conference' => [
'callTypes' => ['dialer', 'other'],
'expected' => false,
],
'empty call types' => [
'callTypes' => [],
'expected' => false,
],
];
}
public static function hasCallTypeDialerDataProvider(): array
{
return [
'has dialer' => [
'callTypes' => ['conference', 'dialer'],
'expected' => true,
],
'does not have dialer' => [
'callTypes' => ['conference', 'other'],
'expected' => false,
],
'empty call types' => [
'callTypes' => [],
'expected' => false,
],
];
}
public function testTransformReportResultsWithEmptyCollection(): void
{
$emptyCollection = new Collection([]);
$result = $this->service->transformReportResults($emptyCollection);
$this->assertIsArray($result);
$this->assertEmpty($result);
}
public function testTransformReportResultsStructure(): void
{
// Create a mock AutomatedReportResult with minimal setup to test structure
$mockReportResult = $this->createMockReportResult();
$collection = new Collection([$mockReportResult]);
$result = $this->service->transformReportResults($collection);
$this->assertIsArray($result);
$this->assertCount(1, $result);
$transformedResult = $result[0];
// Verify all expected keys are present
$expectedKeys = [
'id', 'name', 'frequency', 'recipients',
'report_type', 'media_type', 'downloadUrl', 'viewUrl', 'generated_at',
];
foreach ($expectedKeys as $key) {
$this->assertArrayHasKey($key, $transformedResult);
}
// Verify structure of nested arrays
$this->assertIsArray($transformedResult['frequency']);
$this->assertArrayHasKey('id', $transformedResult['frequency']);
$this->assertArrayHasKey('name', $transformedResult['frequency']);
$this->assertIsArray($transformedResult['report_type']);
$this->assertArrayHasKey('id', $transformedResult['report_type']);
$this->assertArrayHasKey('name', $transformedResult['report_type']);
$this->assertIsArray($transformedResult['recipients']);
// Verify TODO fields are null as expected
$this->assertEquals(AutomatedReportsService::MEDIA_TYPE_PODCAST, $transformedResult['media_type']);
$this->assertEquals(route('ai-reports.audio.download', ['uuid' => 'test-uuid']), $transformedResult['downloadUrl']);
$this->assertEquals(route('ai-reports.audio.view', ['uuid' => 'test-uuid']), $transformedResult['viewUrl']);
}
public function testTransformReportResultsWithMultipleResults(): void
{
$mockReportResult1 = $this->createMockReportResult('result-uuid-1', 'exec_summary');
$mockReportResult2 = $this->createMockReportResult('result-uuid-2', 'coaching_profiles');
$collection = new Collection([$mockReportResult1, $mockReportResult2]);
$result = $this->service->transformReportResults($collection);
$this->assertIsArray($result);
$this->assertCount(2, $result);
// Verify different UUIDs
$this->assertEquals('result-uuid-1', $result[0]['id']);
$this->assertEquals('result-uuid-2', $result[1]['id']);
// Verify both results have the expected structure
foreach ($result as $transformedResult) {
$this->assertArrayHasKey('id', $transformedResult);
$this->assertArrayHasKey('name', $transformedResult);
$this->assertArrayHasKey('frequency', $transformedResult);
$this->assertArrayHasKey('recipients', $transformedResult);
$this->assertArrayHasKey('report_type', $transformedResult);
}
}
#[DataProvider('isUserRecipientOfReportDataProvider')]
public function testIsUserRecipientOfReport(int $userId, array $recipients, bool $expected): void
{
// Create mock User
$mockUser = $this->createMock(\Jiminny\Models\User::class);
$mockUser->method('getId')->willReturn($userId);
$mockUser->method('getGroupId')->willReturn(null);
// Create mock AutomatedReport
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getRecipients')->willReturn($recipients);
$mockReport->method('isAskJiminnyReport')->willReturn(false);
$mockReport->method('getGroups')->willReturn([]);
$result = $this->service->isUserRecipientOfReport($mockUser, $mockReport);
$this->assertEquals($expected, $result);
}
#[DataProvider('isUserRecipientOfAskJiminnyReportDataProvider')]
public function testIsUserRecipientOfAskJiminnyReportViaGroup(
int $userId,
?int $groupId,
array $recipients,
array $reportGroups,
bool $expected,
): void {
$mockUser = $this->createMock(\Jiminny\Models\User::class);
$mockUser->method('getId')->willReturn($userId);
$mockUser->method('getGroupId')->willReturn($groupId);
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getRecipients')->willReturn($recipients);
$mockReport->method('isAskJiminnyReport')->willReturn(true);
$mockReport->method('getGroups')->willReturn($reportGroups);
$this->assertSame($expected, $this->service->isUserRecipientOfReport($mockUser, $mockReport));
}
public function testIsUserRecipientOfNonAskJiminnyReportIgnoresGroups(): void
{
$mockUser = $this->createMock(\Jiminny\Models\User::class);
$mockUser->method('getId')->willReturn(123);
$mockUser->method('getGroupId')->willReturn(5);
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getRecipients')->willReturn(['users' => []]);
$mockReport->method('isAskJiminnyReport')->willReturn(false);
$mockReport->method('getGroups')->willReturn([5]);
$this->assertFalse($this->service->isUserRecipientOfReport($mockUser, $mockReport));
}
public static function isUserRecipientOfAskJiminnyReportDataProvider(): array
{
return [
'group member - ask jiminny' => [
'userId' => 123,
'groupId' => 7,
'recipients' => ['users' => []],
'reportGroups' => [7],
'expected' => true,
],
'group mismatch - ask jiminny' => [
'userId' => 123,
'groupId' => 9,
'recipients' => ['users' => []],
'reportGroups' => [7, 8],
'expected' => false,
],
'user with no group - ask jiminny' => [
'userId' => 123,
'groupId' => null,
'recipients' => ['users' => []],
'reportGroups' => [7],
'expected' => false,
],
'recipient users take precedence over group' => [
'userId' => 123,
'groupId' => null,
'recipients' => ['users' => [123]],
'reportGroups' => [],
'expected' => true,
],
];
}
public function testIsUserRecipientOfReportWithEmptyRecipients(): void
{
// Create mock User
$mockUser = $this->createMock(\Jiminny\Models\User::class);
$mockUser->method('getId')->willReturn(123);
// Create mock AutomatedReport with no recipients
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getRecipients')->willReturn([]);
$result = $this->service->isUserRecipientOfReport($mockUser, $mockReport);
$this->assertFalse($result);
}
public function testIsUserRecipientOfReportWithNoUsersKey(): void
{
// Create mock User
$mockUser = $this->createMock(\Jiminny\Models\User::class);
$mockUser->method('getId')->willReturn(123);
// Create mock AutomatedReport with recipients but no 'users' key
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getRecipients')->willReturn(['other_key' => [456, 789]]);
$result = $this->service->isUserRecipientOfReport($mockUser, $mockReport);
$this->assertFalse($result);
}
public static function isUserRecipientOfReportDataProvider(): array
{
return [
'user is recipient - single user' => [
'userId' => 123,
'recipients' => ['users' => [123]],
'expected' => true,
],
'user is recipient - multiple users' => [
'userId' => 456,
'recipients' => ['users' => [123, 456, 789]],
'expected' => true,
],
'user is not recipient - single user' => [
'userId' => 999,
'recipients' => ['users' => [123]],
'expected' => false,
],
'user is not recipient - multiple users' => [
'userId' => 999,
'recipients' => ['users' => [123, 456, 789]],
'expected' => false,
],
'user is recipient - string IDs converted to int' => [
'userId' => 123,
'recipients' => ['users' => ['123', '456']],
'expected' => true,
],
'user is not recipient - string IDs converted to int' => [
'userId' => 999,
'recipients' => ['users' => ['123', '456']],
'expected' => false,
],
'empty users array' => [
'userId' => 123,
'recipients' => ['users' => []],
'expected' => false,
],
];
}
private function createMockReportResult(string $uuid = 'test-uuid', string $reportType = 'exec_summary'): AutomatedReportResult
{
// Create mock AutomatedReport
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getFrequency')->willReturn('weekly');
$mockReport->method('getRecipients')->willReturn(['users' => [1, 2]]);
$mockReport->method('getGroups')->willReturn([10, 20]);
$mockReport->method('getType')->willReturn($reportType);
// Create mock Team
$mockTeam = $this->createMock(\Jiminny\Models\Team::class);
// Create mock Group
$mockGroup = $this->createMock(\Jiminny\Models\Group::class);
$mockGroup->method('getUuid')->willReturn('group-uuid-10');
$mockGroup->method('getName')->willReturn('Test Team');
$mockQueryBuilder = Mockery::mock();
$mockQueryBuilder->shouldReceive('where')->andReturnSelf();
$mockQueryBuilder->shouldReceive('first')->andReturn($mockGroup);
$dataRelation = Mockery::mock(HasMany::class);
$dataRelation->shouldReceive('where')->andReturn($mockQueryBuilder);
$dataRelation->shouldReceive('get')->andReturn(
new \Illuminate\Database\Eloquent\Collection([$mockGroup])
);
$mockTeam->method('groups')->willReturn($dataRelation);
$mockReport->method('getTeam')->willReturn($mockTeam);
// Create mock AutomatedReportResult
$mockReportResult = $this->createMock(AutomatedReportResult::class);
$mockReportResult->method('getUuid')->willReturn($uuid);
$mockReportResult->method('getGeneratedAt')->willReturn(
\Illuminate\Support\Carbon::parse('2024-01-15T10:30:00Z')
);
$mockReportResult->method('getReport')->willReturn($mockReport);
// Mock methods used in getReportFileName
$mockReportResult->method('getReportType')->willReturn($reportType);
$mockReportResult->method('getFromDate')->willReturn(
\Illuminate\Support\Carbon::parse('2024-01-08')
);
$mockReportResult->method('getToDate')->willReturn(
\Illuminate\Support\Carbon::parse('2024-01-15')
);
$mockReportResult->method('getGroups')->willReturn([10]);
$mockReportResult->method('getMediaType')->willReturn(AutomatedReportsService::MEDIA_TYPE_PODCAST);
return $mockReportResult;
}
#[DataProvider('getUsersUuidsDataProvider')]
public function testGetUsersUuids(array $recipients, array $mockUsers, array $expectedUuids): void
{
// Create mock UserRepository
$mockUserRepository = $this->createMock(UserRepository::class);
// Configure the mock to return specific users for specific IDs using a callback
$mockUserRepository->method('find')
->willReturnCallback(function ($userId) use ($mockUsers) {
if (! isset($mockUsers[$userId])) {
return null;
}
$userUuid = $mockUsers[$userId]['uuid'] ?? null;
if ($userUuid === null) {
return null;
}
$mockUser = $this->createMock(\Jiminny\Models\User::class);
$mockUser->method('getUuid')->willReturn((string) $userUuid);
return $mockUser;
});
// Create service with mocked UserRepository
$automatedReportsService = $this->getService(mockUserRepository: $mockUserRepository);
// Create mock AutomatedReport
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getRecipients')->willReturn($recipients);
$result = $automatedReportsService->getUsersUuids($mockReport);
$this->assertEquals($expectedUuids, $result);
}
public function testGetUsersUuidsWithEmptyRecipients(): void
{
// Create mock AutomatedReport with empty recipients
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getRecipients')->willReturn([]);
$result = $this->service->getUsersUuids($mockReport);
$this->assertEquals([], $result);
}
public function testGetUsersUuidsWithNoUsersKey(): void
{
// Create mock AutomatedReport with recipients but no 'users' key
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getRecipients')->willReturn(['other_key' => [1, 2, 3]]);
$result = $this->service->getUsersUuids($mockReport);
$this->assertEquals([], $result);
}
public function testGetUsersUuidsWithNonExistentUsers(): void
{
// Create mock UserRepository that returns null for all users
$mockUserRepository = $this->createMock(UserRepository::class);
$mockUserRepository->method('find')->willReturn(null);
// Create service with mocked UserRepository
$automatedReportsService = $this->getService(mockUserRepository: $mockUserRepository);
// Create mock AutomatedReport
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getRecipients')->willReturn(['users' => [1, 2, 3]]);
$result = $automatedReportsService->getUsersUuids($mockReport);
// Should return array with null values for non-existent users
$this->assertEquals([], $result);
}
public static function getUsersUuidsDataProvider(): array
{
return [
'single user found' => [
'recipients' => ['users' => [123]],
'mockUsers' => [
123 => ['id' => 123, 'uuid' => 'user-uuid-123'],
],
'expectedUuids' => ['user-uuid-123'],
],
'multiple users found' => [
'recipients' => ['users' => [123, 456, 789]],
'mockUsers' => [
123 => ['id' => 123, 'uuid' => 'user-uuid-123'],
456 => ['id' => 456, 'uuid' => 'user-uuid-456'],
789 => ['id' => 789, 'uuid' => 'user-uuid-789'],
],
'expectedUuids' => ['user-uuid-123', 'user-uuid-456', 'user-uuid-789'],
],
'mixed found and not found users' => [
'recipients' => ['users' => [123, 456, 789]],
'mockUsers' => [
123 => ['id' => 123, 'uuid' => 'user-uuid-123'],
// 456 not found in DB
789 => ['id' => 789, 'uuid' => 'user-uuid-789'],
],
'expectedUuids' => ['user-uuid-123', 'user-uuid-789'], // Updated to reflect that nulls are filtered out
],
'empty users array' => [
'recipients' => ['users' => []],
'mockUsers' => [],
'expectedUuids' => [],
],
'all users not found' => [
'recipients' => ['users' => [123, 456]],
'mockUsers' => [], // No users found
'expectedUuids' => [], // Updated to reflect that nulls are filtered out
],
];
}
#[DataProvider('getCurrentDealStagesUuidsDataProvider')]
public function testGetCurrentDealStagesUuids(array $currentDealStages, array $mockStages, array $expectedUuids): void
{
// Create mock StageRepository
$mockStageRepository = $this->createMock(StageRepository::class);
// Configure the mock to return specific stages for specific IDs using a callback
$mockStageRepository->method('find')
->willReturnCallback(function ($stageId) use ($mockStages) {
if (! isset($mockStages[$stageId])) {
return null;
}
$stageUuid = $mockStages[$stageId]['uuid'] ?? null;
if ($stageUuid === null) {
return null;
}
$mockStage = $this->createMock(\Jiminny\Models\Stage::class);
$mockStage->method('getUuid')->willReturn((string) $stageUuid);
return $mockStage;
});
// Create service with mocked StageRepository
$automatedReportsService = $this->getService(mockStageRepository: $mockStageRepository);
// Create mock AutomatedReport
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getCurrentDealStages')->willReturn($currentDealStages);
$result = $automatedReportsService->getCurrentDealStagesUuids($mockReport);
$this->assertEquals($expectedUuids, $result);
}
public function testGetCurrentDealStagesUuidsWithEmptyStages(): void
{
// Create mock AutomatedReport with empty current deal stages
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getCurrentDealStages')->willReturn([]);
$result = $this->service->getCurrentDealStagesUuids($mockReport);
$this->assertEquals([], $result);
}
public function testGetCurrentDealStagesUuidsWithNonExistentStages(): void
{
// Create mock StageRepository that returns null for all stages
$mockStageRepository = $this->createMock(StageRepository::class);
$mockStageRepository->method('find')->willReturn(null);
// Create service with mocked StageRepository
$automatedReportsService = $this->getService(mockStageRepository: $mockStageRepository);
// Create mock AutomatedReport
$mockReport = $this->createMock(AutomatedReport::class);
$mockReport->method('getCurrentDealStages')->willReturn([1, 2, 3]);
$result = $automatedReportsService->getCurrentDealStagesUuids($mockReport);
// Should return array with null values for non-existent stages
$this->assertEquals([], $result);
}
public static function getCurrentDealStagesUuidsDataProvider(): array
{
return [
'single stage found' => [
'currentDealStages' => [10],
'mockStages' => [
10 => ['id' => 10, 'uuid' => 'stage-uuid-10'],
],
'expectedUuids' => ['stage-uuid-10'],
],
'multiple stages found' => [
'currentDealStages' => [10, 20, 30],
'mockStages' => [
10 => ['id' => 10, 'uuid' => 'stage-uuid-10'],
20 => ['id' => 20, 'uuid' => 'stage-uuid-20'],
30 => ['id' => 30, 'uuid' => 'stage-uuid-30'],
],
'expectedUuids' => ['stage-uuid-10', 'stage-uuid-20', 'stage-uuid-30'],
],
'mixed found and not found stages' => [
'currentDealStages' => [10, 20, 30],
'mockStages' => [
10 => ['id' => 10, 'uuid' => 'stage-uuid-10'],
// 20 not found in DB
30 => ['id' => 30, 'uuid' => 'stage-uuid-30'],
],
'expectedUuids' => ['stage-uuid-10', 'stage-uuid-30'], // Updated to reflect that nulls are filtered out
],
'empty stages array' => [
'currentDealStages' => [],
'mockStages' => [],
'expectedUuids' => [],
],
'all stages not found' => [
'currentDealStages' => [10, 20],
'mockStages' => [], // No stages found
'expectedUuids' => [], // Updated to reflect that nulls are filtered out
],
];
}
#[DataProvider('getTeamGroupsDataProvider')]
public function testGetTeamGroups(string $teamUuid, ?array $mockTeamData, array $mockGroups, array $expectedResult): void
{
// Create mock TeamRepository
$mockTeamRepository = $this->createMock(TeamRepository::class);
if ($mockTeamData === null) {
// Team not found
$mockTeamRepository->method('idOrUuid')
->with($teamUuid)
->willReturn(null);
} else {
// Team found - create mock team with groups
$mockTeam = $this->createMock(\Jiminny\Models\Team::class);
// Create mock groups collection
$mockGroupsCollection = $this->createMock(\Illuminate\Database\Eloquent\Collection::class);
// Create mock Group objects
$groupObjects = [];
foreach ($mockGroups as $groupData) {
$mockGroup = $this->createMock(\Jiminny\Models\Group::class);
$mockGroup->method('getUuid')->willReturn($groupData['id']);
$mockGroup->method('getName')->willReturn($groupData['name']);
$groupObjects[] = $mockGroup;
}
// Mock the groups collection to return our mock groups
$mockGroupsCollection->method('getIterator')->willReturn(new \ArrayIterator($groupObjects));
// Mock the groups() relation
$mockGroupsRelation = $this->createMock(\Illuminate\Database\Eloquent\Relations\HasMany::class);
$mockGroupsRelation->method('get')->willReturn($mockGroupsCollection);
$mockTeam->method('groups')->willReturn($mockGroupsRelation);
$mockTeamRepository->method('idOrUuid')
->with($teamUuid)
->willReturn($mockTeam);
}
// Create service with mocked TeamRepository
$automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);
$result = $automatedReportsService->getTeamGroups($teamUuid);
$this->assertEquals($expectedResult, $result);
}
public function testGetTeamGroupsWithNonExistentTeam(): void
{
// Create mock TeamRepository that returns null (team not found)
$mockTeamRepository = $this->createMock(TeamRepository::class);
$mockTeamRepository->method('idOrUuid')->willReturn(null);
// Create service with mocked TeamRepository
$automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);
$result = $automatedReportsService->getTeamGroups('non-existent-team-uuid');
$this->assertEquals([], $result);
}
public function testGetTeamGroupsWithEmptyGroups(): void
{
// Create mock team with no groups
$mockTeam = $this->createMock(\Jiminny\Models\Team::class);
// Create empty groups collection
$mockGroupsCollection = $this->createMock(\Illuminate\Database\Eloquent\Collection::class);
$mockGroupsCollection->method('getIterator')->willReturn(new \ArrayIterator([]));
$mockGroupsRelation = $this->createMock(\Illuminate\Database\Eloquent\Relations\HasMany::class);
$mockGroupsRelation->method('get')->willReturn($mockGroupsCollection);
$mockTeam->method('groups')->willReturn($mockGroupsRelation);
// Create mock TeamRepository
$mockTeamRepository = $this->createMock(TeamRepository::class);
$mockTeamRepository->method('idOrUuid')->willReturn($mockTeam);
// Create service with mocked TeamRepository
$automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);
$result = $automatedReportsService->getTeamGroups('team-with-no-groups');
$this->assertEquals([], $result);
}
public static function getTeamGroupsDataProvider(): array
{
return [
'team with single group' => [
'teamUuid' => 'team-uuid-123',
'mockTeamData' => ['id' => 'team-uuid-123', 'name' => 'Test Team'],
'mockGroups' => [
['id' => 'group-uuid-1', 'name' => 'Sales Team'],
],
'expectedResult' => [
['id' => 'group-uuid-1', 'name' => 'Sales Team'],
],
],
'team with multiple groups' => [
'teamUuid' => 'team-uuid-456',
'mockTeamData' => ['id' => 'team-uuid-456', 'name' => 'Another Team'],
'mockGroups' => [
['id' => 'group-uuid-1', 'name' => 'Sales Team'],
['id' => 'group-uuid-2', 'name' => 'Marketing Team'],
['id' => 'group-uuid-3', 'name' => 'Support Team'],
],
'expectedResult' => [
['id' => 'group-uuid-1', 'name' => 'Sales Team'],
['id' => 'group-uuid-2', 'name' => 'Marketing Team'],
['id' => 'group-uuid-3', 'name' => 'Support Team'],
],
],
'team not found' => [
'teamUuid' => 'non-existent-uuid',
'mockTeamData' => null,
'mockGroups' => [],
'expectedResult' => [],
],
'team with no groups' => [
'teamUuid' => 'team-uuid-empty',
'mockTeamData' => ['id' => 'team-uuid-empty', 'name' => 'Empty Team'],
'mockGroups' => [],
'expectedResult' => [],
],
];
}
#[DataProvider('getTeamsDataProvider')]
public function testGetTeams(array $mockTeams, array $expectedResult): void
{
// Create mock TeamRepository
$mockTeamRepository = $this->createMock(TeamRepository::class);
// Create mock Team objects
$teamObjects = [];
foreach ($mockTeams as $teamData) {
$mockTeam = $this->createMock(\Jiminny\Models\Team::class);
$mockTeam->method('getUuid')->willReturn($teamData['id']);
$mockTeam->method('getName')->willReturn($teamData['name']);
$mockTeam->method('hasFeature')
->with(\Jiminny\Models\Feature\FeatureEnum::AUTOMATED_REPORTS)
->willReturn($teamData['hasAutomatedReports']);
$teamObjects[] = $mockTeam;
}
// Mock the repository to return a Collection (not array)
$mockTeamRepository->method('getTeamsForKiosk')
->with('active')
->willReturn(new Collection($teamObjects));
// Create service with mocked TeamRepository
$automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);
$result = $automatedReportsService->getTeams();
$this->assertEquals($expectedResult, $result);
}
public function testGetTeamsWithNoTeams(): void
{
// Create mock TeamRepository that returns empty Collection
$mockTeamRepository = $this->createMock(TeamRepository::class);
$mockTeamRepository->method('getTeamsForKiosk')->willReturn(new Collection([]));
// Create service with mocked TeamRepository
$automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);
$result = $automatedReportsService->getTeams();
$this->assertEquals([], $result);
}
public function testGetTeamsWithAllTeamsWithoutFeature(): void
{
// Create mock teams without AUTOMATED_REPORTS feature
$mockTeam1 = $this->createMock(\Jiminny\Models\Team::class);
$mockTeam1->method('hasFeature')
->with(\Jiminny\Models\Feature\FeatureEnum::AUTOMATED_REPORTS)
->willReturn(false);
$mockTeam2 = $this->createMock(\Jiminny\Models\Team::class);
$mockTeam2->method('hasFeature')
->with(\Jiminny\Models\Feature\FeatureEnum::AUTOMATED_REPORTS)
->willReturn(false);
// Create mock TeamRepository that returns Collection
$mockTeamRepository = $this->createMock(TeamRepository::class);
$mockTeamRepository->method('getTeamsForKiosk')->willReturn(new Collection([$mockTeam1, $mockTeam2]));
// Create service with mocked TeamRepository
$automatedReportsService = $this->getService(mockTeamRepository: $mockTeamRepository);
$result = $automatedReportsService->getTeams();
$this->assertEquals([], $result);
}
public function testGetTeamsForwardsPartnerToRepository(): void
{
$partner = $this->createMock(Partner::class);
$mockTeamRepository = $this->createMock(TeamRepository::class);
$mockTeamRepository->expects(self::once())
->method('getTeamsForKiosk')
->with(Team::STATUS_ACTIVE, $partner)
->willReturn(new Collection([]));
$service = $this->getService(mockTeamRepository: $mockTeamRepository);
$service->getTeams(partner: $partner);
}
public function testGetOrganizationFieldDataForwardsPartnerToRepository(): void
{
$partner = $this->createMock(Partner::class);
$mockTeamRepository = $this->createMock(TeamRepository::class);
$mockTeamRepository->expects(self::once())
->method('getTeamsForKiosk')
->with(Team::STATUS_ACTIVE, $partner)
->willReturn(new Collection([]));
$service = $this->getService(mockTeamRepository: $mockTeamRepository);
$service->getOrganizationFieldData(partner: $partner);
}
public function testGetTeamsGroupsOptionsForwardsPartnerToRepository(): void
{
$partner = $this->createMock(Partner::class);
$mockTeamRepository = $this->createMock(TeamRepository::class);
$mockTeamRepository->expects(self::once())
->method('getTeamsForKiosk')
->with(Team::STATUS_ACTIVE, $partner)
->willReturn(new Collection([]));
$service = $this->getService(mockTeamRepository: $mockTeamRepository);
$service->getTeamsGroupsOptions(partner: $partner);
}
public static function getTeamsDataProvider(): array
{
return [
'single team with feature' => [
'mockTeams' => [
[
'id' => 'team-uuid-1',
'name' => 'Sales Team',
'hasAutomatedReports' => true,
],
],
'expectedResult' => [
['id' => 'team-uuid-1', 'name' => 'Sales Team'],
],
],
'multiple teams with feature' => [
'mockTeams' => [
[
'id' => 'team-uuid-1',
'name' => 'Sales Team',
'hasAutomatedReports' => true,
],
[
'id' => 'team-uuid-2',
'name' => 'Marketing Team',
'hasAutomatedReports' => true,
],
[
'id' => 'team-uuid-3',
'name' => 'Support Team',
'hasAutomatedReports' => true,
],
],
'expectedResult' => [
['id' => 'team-uuid-1', 'name' => 'Sales Team'],
['id' => 'team-uuid-2', 'name' => 'Marketing Team'],
['id' => 'team-uuid-3', 'name' => 'Support Team'],
],
],
'mixed teams - some with feature, some without' => [
'mockTeams' => [
[
'id' => 'team-uuid-1',
'name' => 'Sales Team',
'hasAutomatedReports' => true,
],
[
'id' => 'team-uuid-2',
'name' => 'Marketing Team',
'hasAutomatedReports' => false,
],
[
'id' => 'team-uuid-3',
'name' => 'Support Team',
'hasAutomatedReports' => true,
],
],
'expectedResult' => [
['id' => 'team-uuid-1', 'name' => 'Sales Team'],
['id' => 'team-uuid-3', 'name' => 'Support Team'],
],
],
'all teams without feature' => [
'mockTeams' => [
[
'id' => 'team-uuid-1',
'name' => 'Sales Team',
'hasAutomatedReports' => false,
],
[
'id' => 'team-uuid-2',
'name' => 'Marketing Team',
'hasAutomatedReports' => false,
],
],
'expectedResult' => [],
],
'empty teams array' => [
'mockTeams' => [],
'expectedResult' => [],
],
];
}
#[DataProvider('deleteS3FilesDataProvider')]
public function testDeleteS3Files(
string $mediaType,
array $expectedFileExtensions,
array $existingFiles,
string $pathSuffix,
int $expectedDeletes
): void {
// Arrange
$teamUuid = 'team-uuid-123';
$reportUuid = 'report-uuid-456';
$basePath = sprintf('%s/reports/%s', $teamUuid, $reportUuid);
$team = Mockery::mock(Team::class);
$team->allows('getUuid')->andReturn($teamUuid);
$report = Mockery::mock(AutomatedReport::class);
$report->allows('getTeam')->andReturn($team);
$result = Mockery::mock(AutomatedReportResult::class);
$result->allows('getReport')->andReturn($report);
$result->allows('getUuid')->andReturn($reportUuid);
$result->allows('getMediaType')->andReturn($mediaType);
Storage::fake();
Log::shouldReceive('info')->times($expectedDeletes);
foreach ($existingFiles as $extension) {
$filePath = $basePath . $pathSuffix . '.' . $extension;
Storage::put($filePath, 'dummy content');
}
// Act
$this->service->deleteS3Files($result);
// Assert
foreach ($expectedFileExtensions as $extension) {
$filePath = $basePath . $pathSuffix . '.' . $extension;
if (in_array($extension, $existingFiles, true)) {
Storage::assertMissing($filePath);
} else {
// To be sure no unexpected files were created and deleted
Storage::assertMissing($filePath);
}
}
}
public static function deleteS3FilesDataProvider(): array
{
return [
'PDF report, all files exist' => [
'mediaType' => AutomatedReportsService::MEDIA_TYPE_PDF,
'expectedFileExtensions' => ['html', 'MD', 'pdf'],
'existingFiles' => ['html', 'MD', 'pdf'],
'pathSuffix' => '',
'expectedDeletes' => 3,
],
'PDF report, some files exist' => [
'mediaType' => AutomatedReportsService::MEDIA_TYPE_PDF,
'expectedFileExtensions' => ['html', 'MD', 'pdf'],
'existingFiles' => ['html', 'pdf'],
'pathSuffix' => '',
'expectedDeletes' => 2,
],
'PDF report, no files exist' => [
'mediaType' => AutomatedReportsService::MEDIA_TYPE_PDF,
'expectedFileExtensions' => ['html', 'MD', 'pdf'],
'existingFiles' => [],
'pathSuffix' => '',
'expectedDeletes' => 0,
],
'Podcast report, all files exist' => [
'mediaType' => AutomatedReportsService::MEDIA_TYPE_PODCAST,
'expectedFileExtensions' => ['json', 'mp3', 'ssml'],
'existingFiles' => ['json', 'mp3', 'ssml'],
'pathSuffix' => '_podcast',
'expectedDeletes' => 3,
],
'Podcast report, some files exist' => [
'mediaType' => AutomatedReportsService::MEDIA_TYPE_PODCAST,
'expectedFileExtensions' => ['json', 'mp3', 'ssml'],
'existingFiles' => ['mp3'],
'pathSuffix' => '_podcast',
'expectedDeletes' => 1,
],
'Podcast report, no files exist' => [
'mediaType' => AutomatedReportsService::MEDIA_TYPE_PODCAST,
'expectedFileExtensions' => ['json', 'mp3', 'ssml'],
'existingFiles' => [],
'pathSuffix' => '_podcast',
'expectedDeletes' => 0,
],
'Other media type, should do nothing' => [
'mediaType' => 'some_other_type',
'expectedFileExtensions' => [],
'existingFiles' => [],
'pathSuffix' => '',
'expectedDeletes' => 0,
],
];
}
public function testDeleteReportsResultsInRetentionPeriodWithLogging(): void
{
// Create mocks for the test
$automatedReportsService = Mockery::mock(AutomatedReportsService::class);
$team = Mockery::mock(Team::class);
$team->shouldReceive('getId')->andReturn(123);
$from = now()->subDays(30);
$to = now();
$source = 'test-source';
// Expect the method to be called with specific parameters
$automatedReportsService->shouldReceive('deleteReportsResultsInRetentionPeriodWithLogging')
->once()
->with(
$team,
Mockery::on(function ($arg) use ($from) {
return $arg->timestamp === $from->timestamp;
}),
Mockery::on(function ($arg) use ($to) {
return $arg->timestamp === $to->timestamp;
}),
$source
)
->andReturn(5);
// Call the method and verify the result
$result = $automatedReportsService->deleteReportsResultsInRetentionPeriodWithLogging(
$team,
$from,
$to,
$source
);
$this->assertEquals(5, $result);
}
#[DataProvider('sanitizeFileNameDataProvider')]
public function testSanitizeFileName(string $input, string $expected): void
{
$result = $this->service->sanitizeFileName($input);
$this->assertEquals($expected, $result);
}
public static function sanitizeFileNameDataProvider(): array
{
return [
'no special characters' => [
'input' => 'Exec Summary - Sep 2025 - Business Development Team',
'expected' => 'Exec Summary - Sep 2025 - Business Development Team',
],
'forward slash in team name' => [
'input' => 'Exec Summary - Sep 2025 - ND/IRV',
'expected' => 'Exec Summary - Sep 2025 - ND-IRV',
],
'backslash in team name' => [
'input' => 'Exec Summary - Sep 2025 - ND\IRV',
'expected' => 'Exec Summary - Sep 2025 - ND-IRV',
],
'multiple forward slashes' => [
'input' => 'Report - Team A/B/C',
'expected' => 'Report - Team A-B-C',
],
'multiple backslashes' => [
'input' => 'Report - Team A\B\C',
'expected...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57905
|
2036
|
24
|
2026-05-19T11:15:04.571350+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189304571_m1.jpg...
|
PhpStorm
|
faVsco.js – AutomatedReportsServiceTest.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 45 m100% C7Tue 19 May 14:15:04ED→Describe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
4125371927092023818
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 45 m100% C7Tue 19 May 14:15:04ED→Describe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
57903
|
NULL
|
NULL
|
NULL
|
|
57904
|
2037
|
32
|
2026-05-19T11:15:02.116101+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189302116_m2.jpg...
|
PhpStorm
|
faVsco.js – AutomatedReportsServiceTest.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions...
|
[{"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},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.098071806,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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.8194814,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskAnythingPromptServiceTest","depth":6,"bounds":{"left":0.83477396,"top":0.019952115,"width":0.080784574,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"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},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
4974519233973743475
|
-4022622654610547319
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
PhostormINavicarecodeFV faVsco.js°9 JY-20676-delete-report-related-objectsroledey> • OpportunitySyncStrategy• • ProspectSearchStrategy• M ServiceTraits© AskAnythingPromptService.php© ClientTest.phpC) DecorateActivitylest.pnpC DeleteObjectsTraitTest.php© FieldDefinitionsTest.phpC GetActivityFieldNameTest.phpPayloadBuilderTest.php@ QueryBuilderTest.phpC) QueryHandlerTest.php© QuerylteratorTest.php© QuervResultsTests.php© AskJiminnyReportsController.phg2667 V52678 Vl2710 %(c) service lest.onoC SvncBatchRedisServiceTest.php© CachedCrmServiceDecoratorTest.phr 260©) CrmActivitvServicelest.onoc) crmobiectsResolveriiest.onoc DefaultProsnectSearchStrateavTest.cc EmailHelperTest.oho2879 Dc) FieldValueConverterTest.ohoc LavoutManaderTest.oho© MigrateProviderServiceTest.phpci OnnortunitvActivitvMatcherTect nhn© OpportunitySyncStrategyResolverTes© ProspectSearchStrategyFactoryTest.pC ProviderPeaistrvTect nhnl© RecordSelectorTest.php@t DocolvoCamnanvNemoPvEmeilTreitT, 2889©) TimePeriodlteratorTest.php© UpdateCrmDataResolverTest.php> C Internalv @ Kioskv @ AutomatedReports© ActivitvTvpeServiceTest.php© AskJiminnyReportActivitvServiceT, 20%© AskJiminnyReportServiceTest.php@ AutomatedReportsCallbackServiceC AutomatedReportsServiceActivitie.C) AutomatedRenortsServiceExtende@ AutomatedReportsServiceFieldDat 298)(C) AutomatedRenortsServiceFormatti@ AutomatedReportsServiceGetActivC AutomatedRenortsServiceGetPlavt( AutomatedRenortcServiceRenortCch AutomatedRenortsServiceValidateCh AutomatedRenortcServiceValidatic© Auton©) AskAnythingPromptServiceTest.php© Search.phppublic function testGetMediaTypeMetadataUnknown(): void{...}public function testGetTeamIdsWithReportsResults(): void{...}public function testGetTeamReports: void{...}public function testGetReportResults: void{...}public function testDeleteReportsResultsInRetentionPeriodWithNoQueryResults: void{...}public function testUpdateAskJiminnyReportStatusNotAskJiminny0: void{...}public function testUpdateAskJiminnyReportStatusThrowsWhenEnablingWithMissingRef ApncetRejectoIClassName: AutomatedReport::class)isAskJiminnvReport')KReport->expects(Sthis->once))->wll Returnt valu'undate'):$property = $reflection->getProperty( nameCnnonentv->cetAccoccihle/accessible: tnue$property->setValue(Sthis->service, $mockRepo);$this->expectException(InvalidArgumentException::class):$this->expectExceptionMessage('This report is missing a saved search or prompt.'):$this->service->updateAskJiminnyReportStatus($mockReport.public function testUpdateAskJiminnvReportStatusDoesNotValidateWhenDisablingO: void{...}public function testGetAskJiminnvReportFiltersO: void{...}public function testGetAskJiminnvReportFormDataWithoutReportO: void{...}Jv Accept File &+X Reject File txa+ 7 of 7 files →nublic function testGetAskJiminnvPenortFormDataWithRenortD• voidf=custom.log= laravel.log#SF liiminnv@localhostlX4 HS_local [jiminny@localhost]A console [STAGING]CoachinaFeedhackCoachl.Icerin.nhn=194195=186=188 0190=192=1931981=201_208209HI I220221=,..Plavaroundactivities where 1d = 422003- # 00U04000000B6FoMACISELECT ar.id, ar.uuid, ar.media type, ar.status, a.typeSp0M automated nenont neculte anJOIN automated_reports a ON a.id = ar.report idWHERE a.type = 'ask jiminny'LIMIT 10;SELECT * FROM automated reports where id = 71;SELECT * FROM automated report results where report id = 71;UPDATE automated_reports set playbook categories = NULL where id = 68:SELECT * FROM automated_report_ results where id = 275:SELECT * FROM automated reports order by id desc›SELECT * FROMautomated report results order by id desc:select * from activity searches where user id = 143:SELECTautomated renort results' * FROM 'automated renort resultsiINNER JOIN 'automated renortsiautomated renort results' "renort id' = 'automated renorts' 'idiautomated renort results' 'aenerated at' IS NOT NULLautomated renort results' sent at' IS NOT NULIautomated nenonts' "toam id' = 1SELECT * EPOM automated nenonte whene id = 47-SELECT * FROM automated_reports where id = 42;SELECT * FROM users WHERE id = 143; # group 28colort + fnom tonme wbono id - 71/7.and status = 'completed' and actual start time >= 12025-12-01'•select * from leads:& console [PROD]# console [euySo jiminny vm 021 A1 A18 V2 Y6 ^hell"suppont Dally • In 40m100% 5• Tue 19 May 14:15:01AskAnythingPromptServiceTest vCascadeAsk Jiminny Report M+0 ..• AutomatedReportsServiceTest.php+13 -17Review Items AddressedCritical — N41 Queries (fixed)Saved searches - ActivityController.php:1100 now eager-loads via ->withCount ('automatedReports') , and SearchTransformer.oho: 48 reads from automated reports countPrompts - moved loadCount ('automatedReports') into AskAnythingRepository.php:94-100 (single batched countquery for the wholelist). The AskAnythingPrompt: :getHasReports() accessor now prefers automated_reports_countwhen present and Talls back to existso otherwise preserves correctness in other call sies and tests).Mocerate - Business locic moved to serviceAutomatedReportsService.php:1240-1252 now contains the guard and throws InvalidArgumentException . The controllerAsk.iminnvReportsController.pho: 126-166) is back to a thin try/catch with an added InvalidArgumentExcention → 422handler (matches the pattern already used in createAskJiminnyReport and updateAskJiminnyReport).Moderate — lests added• testUpdateAskJiminnvReportStatusthrowswhenEnablingWithMissingReferences — verifies the new validationithrows and update() is never called.• testlndateAskliminnvRenortStatusDoesNotValGidatelhenDisablUing — verifies disabling bvnasses the validationdid not add controller tests per vour "no unit tests for controllers" rule: the service- leve coverage exercises the sameloaic.Miinor — created rerurnS has reports: falseAskAnvthinaPromntService.ohn: 106 now nasses talse exolicitlv. Undated testCreateAskAnvthingPromotwithTwollsers to matchMinor — onBeforedelete onlvon on demandlNot changed in this round - flagged for confirmation. Currently only on_demand prompts can be wired to Ask Jiminnyreports the getAsk.iminnvReportFilters service exolicitly fetches AskAnvthingPromotTarget::on demand ). so thefrontend guard is correctly scoped. Worth a code comment, but no behavioral change needed.ann/Httn/Trancformerc/M SoarchTrancformer.nhnllers/API/ ActivityController.php +1 -1aoo/Models/AskAnvthina/lmAskAnvthinaPromot.ohp +4/1. AskAnvthingPromotServiceTest.php+25-2ts/ AutomatedReportsServiceTest.php +47app/Component/AskAnything/@ AskAnythingPromptService.php +7 -2Ask anvthina 884-L)<> Code Claude Qnus 4.7 Medium* Reiect alliiAccent alliWN Windsurf Toams 2870-80 UTF.8Po 4 spaces...
|
57902
|
NULL
|
NULL
|
NULL
|
|
57903
|
2036
|
23
|
2026-05-19T11:14:58.532832+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189298532_m1.jpg...
|
PhpStorm
|
faVsco.js – AutomatedReportsService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 46 m100% C7Tue 19 May 14:14:57ED→Describe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
1562990535142279770
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 46 m100% C7Tue 19 May 14:14:57ED→Describe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57902
|
2037
|
31
|
2026-05-19T11:14:56.722085+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189296722_m2.jpg...
|
PhpStorm
|
faVsco.js – AutomatedReportsServiceTest.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormINavicarecodeFV faVsco.js°9 JY-20676-delet PhostormINavicarecodeFV faVsco.js°9 JY-20676-delete-report-related-objeroledeywopportunitymatcher> @ OpportunitySyncStrategy• @ ProspectSearchStrategy> D ServiceTraits© ClientTest.phpC DecorateActivityTest.php© DeleteObjectsTraitTest.php© FieldDefinitionsTest.pho© GetActivityFieldNameTest.php@ PavloadBuilderTest.phpQueryBuilderTest.phpc) @uervHandlertest.pho© QuerylteratorTest.phpc) @uervResultstests.oho© AskAnythingPromptService.php© AskAnythingPromptDto.php© AskJiminnyReportsController.phg26662667 V526722678 %2710 %2743 %(c) ServiceTiest.ohoC SvncBatchRedisServiceTest.oho© CachedCrmServiceDecoratorTest.php 2810 g© CrmActivityServiceTest.phpc) CrmConfiaurationSettinasServiceTest 2e/7 0CrmObjectsResolverTest.php© DefaultProspectSearchStrategyTest.p 2879 D9 EmailHelperTest.phpc FieldValueConverterl est.one© LayoutManagerTest.php© MigrateProviderServiceTest.php© OpportunityActivityMatcherTest.php© OpportunitySyncStrategyResolverTes© ProspectCacheTest.php© ProspectSearchStrategyFactoryTest.I 28© ProviderRegistryTest.php© RecordSelectorTest.php© ResolveCompanyNameByEmailTraitT€ 2896© TimePerioditeratorTest.phpC UpdateCrmDataResolverTest.php> M Internalv MKioskv M AutomatedReportsC) ActivitvivoeServiceTest.oho© Ask JiminnvReportActivitvServiceT, 290%C) Ask.JiminnvReoortServiceTest.oho 290g@ AutomatedReportsCallbackService 2900c AutomatedRenortsServiceActivitia: nood© AutomatedReportsServiceExtende 2991©) AutomatedReportsServiceGetPlayt 29%ch AutomatedRenortcServiceRenortG(ei AutamntodDonortcCorvicoVolidatolzor)C AutomatedReportsServiceValidatic 3035© Auton©) AskAnythingPromptServiceTest.php© Search.phppublic function testGetMediaTypeMetadataUnknown(): void{...}public function testGetTeamIdsWithReportsResults(): void{...}public function testGetTeamReports: voidf...}public function testGetReportResults: voidf...Hpublic function testDeleteReportsResultsInRetentionPeriodNoReports(): void{...public function testDeleteReportsResultsInRetentionPeriodWithNoQueryResults: void{...}public function testUpdateAskJiminnyReportStatusNotAskJiminny0: void{...}public function testUpdateAskJiminnyReportStatusThrowsWhenEnablingWithMissingRef Accept RetectdClassName: AutomatedReport::class)isAskJiminnvReport')KReport->expects(Sthis->once))->wll Returnt valu'undate'):$property = $reflection->getProperty( nameCnnonentv->cetAccoccihle/accessible: tnue$property->setValue($this->service, $mockRepo);$this->expectException(InvalidArgumentException::class)$this->expectExceptionMessage('This report is missing a saved search or prompt.'):$this->service->updateAskJiminnyReportStatus($mockReport.public function testUpdateAskJiminnvReportStatusDoesNotValidateWhenDisablingO: void{...}public function testGetAskJiminnvReportFiltersO: void{...}public function testGetAskJiminnvReportFormDataWithoutReportO: void{...}+v Accept File 3-X Reject File txa+ 7 of 7 files →nublic function testGetAskJiminnvPenortFormDataWithRenortD• voidfJ-ahiects // View null reauect (57 minutes aao)=custom.log= laravel.log4 HS_local [jiminny@localhost]A console [STAGING]CoachinaFeedhackCoachl.Icerin.nhn=194=188 g>280190=192— 193)196.1981= 201= 20129я.209Д215HI I219220221=,..Plavaroundselect * fromactivities where 1d = 422003- # 00U04000000B6FnMACISELECT ar.id, ar.uuid, ar.media type, ar.status, a.typeSp0M automated nenont neculte anJOIN automated_ reports a ON a.id = ar.report idWHERE a.type = 'ask jiminny'LIMIT 10;SELECT * FROM automated reports where id = 71;SELECT * FROM automated report results where report id = 71;UPDATE automated_reports set playbook categories = NULL where id = 68:SELECT * FROM automated report_ results where id = 275SELECT * FROM automated reports order by id desc›SELECT * FROMautomated_reportresults order by 1d desc:select * from activity searches where user id = 143:SELECTautomated renort results' * FROM 'automated renort resultsiINNER JOIN 'automated renortsiautomated renort results' "renort id' = 'automated renorts' 'idiautomated renort results' 'aenerated at' IS NOT NULLautomated renort results' 'sent at' IS NOT NULIautomated nenonts' "toam id' = 1SELECT * EPOM automated nenonte whene id = 47-SELECT * FROM automated_reports where id = 42;SELECT * FROM users WHERE id = 143; # group 28colost + fnom tonme whono id - 71/7.select * from crm_confiqurations where id = 500:SELECT * FROM social accounts WHERE sociable_id = 1695:select * from activities where crm_configuration id = 39and recording state = 'recorded' and duration > 60and status = 'completed' and actual start time >= 12025-12-01'•SELECT * FROM activities WHERE uuid to bin('458cf915-6914-4000-b083-568763262956') = uuidiselect * from leads:Socket fail to connect to host:address=(host=localhost) (port=3306)(tvpe=primarv). Connection refused& console [PROD]# console [euySo jiminny vm 021 A1 A18 V2 Y6 ^hell"supoont Dally • In 40 m100% 5• Tue 19 May 14:14:56AskAnythingPromptServiceTest vCascadeAsk Jiminny Report M+0 ..• AutomatedReportsServiceTest.php+13 -17Review Items AddressedCritical — N41 Queries (fixed)Saved searches - ActivityController.php:1100 now eager-loads via ->withCount ('automatedReports') , and SearchTransformer.oho: 48 reads from automated reports countPrompts - moved loadCount ('automatedReports') into AskAnythingRepository.php:94-100 (single batched countquery for the wholelist). The AskAnythingPrompt: :getHasReports() accessor now prefers automated_reports_countwhen present and Talls back to existso otherwise preserves correctness in other call sies and tests).Mocerate - Business locic moved to serviceAutomatedReportsService.php:1240-1252 now contains the guard and throws InvalidArgumentException . The controllerAsk.iminnvReportsController.pho: 126-166) is back to a thin try/catch with an added InvalidArgumentExcention → 422handler (matches the pattern already used in createAskJiminnyReport and updateAskJiminnyReport).Moderate — lests added• testUpdateAskJiminnvReportStatusthrowswhenEnablingWithMissingReferences — verifies the new validationithrows and update() is never called.• testlndateAskliminnvRenortStatusDoesNotValGidatelhenDisablUing — verifies disabling bvnasses the validationdid not add controller tests per vour "no unit tests for controllers" rule: the service- leve coverage exercises the sameloaic.Miinor — created rerurnS has reports: falseAskAnvthinaPromntService.ohn: 106 now nasses talse exolicitlv. Undated testCreateAskAnvthingPromotwithTwollsers to matchMinor — onBeforedelete onlvon on demandlNot changed in this round - flagged for confirmation. Currently only on_demand prompts can be wired to Ask Jiminnyreports the getAsk.iminnvReportFilters service exolicitly fetches AskAnvthingPromotTarget::on demand ). so thefrontend guard is correctly scoped. Worth a code comment, but no behavioral change needed.ann/Httn/Trancformerc/M SoarchTrancformer.nhnllers/API/ ActivityController.php +1 -1aoo/Models/AskAnvthina/lmAskAnvthinaPromot.ohp +4/1. AskAnvthingPromotServiceTest.php+25-2ts/ AutomatedReportsServiceTest.php +47app/Component/AskAnything/@ AskAnythingPromptService.php +7 -2Ask anvthina 884-L)<> Code Claude Qnus 4.7 MediumReiect alllAccent alliWN Windsurf Toams 2771•6 UTF.8Po 4 spaces...
|
NULL
|
4979998674451589734
|
NULL
|
visual_change
|
ocr
|
NULL
|
PhostormINavicarecodeFV faVsco.js°9 JY-20676-delet PhostormINavicarecodeFV faVsco.js°9 JY-20676-delete-report-related-objeroledeywopportunitymatcher> @ OpportunitySyncStrategy• @ ProspectSearchStrategy> D ServiceTraits© ClientTest.phpC DecorateActivityTest.php© DeleteObjectsTraitTest.php© FieldDefinitionsTest.pho© GetActivityFieldNameTest.php@ PavloadBuilderTest.phpQueryBuilderTest.phpc) @uervHandlertest.pho© QuerylteratorTest.phpc) @uervResultstests.oho© AskAnythingPromptService.php© AskAnythingPromptDto.php© AskJiminnyReportsController.phg26662667 V526722678 %2710 %2743 %(c) ServiceTiest.ohoC SvncBatchRedisServiceTest.oho© CachedCrmServiceDecoratorTest.php 2810 g© CrmActivityServiceTest.phpc) CrmConfiaurationSettinasServiceTest 2e/7 0CrmObjectsResolverTest.php© DefaultProspectSearchStrategyTest.p 2879 D9 EmailHelperTest.phpc FieldValueConverterl est.one© LayoutManagerTest.php© MigrateProviderServiceTest.php© OpportunityActivityMatcherTest.php© OpportunitySyncStrategyResolverTes© ProspectCacheTest.php© ProspectSearchStrategyFactoryTest.I 28© ProviderRegistryTest.php© RecordSelectorTest.php© ResolveCompanyNameByEmailTraitT€ 2896© TimePerioditeratorTest.phpC UpdateCrmDataResolverTest.php> M Internalv MKioskv M AutomatedReportsC) ActivitvivoeServiceTest.oho© Ask JiminnvReportActivitvServiceT, 290%C) Ask.JiminnvReoortServiceTest.oho 290g@ AutomatedReportsCallbackService 2900c AutomatedRenortsServiceActivitia: nood© AutomatedReportsServiceExtende 2991©) AutomatedReportsServiceGetPlayt 29%ch AutomatedRenortcServiceRenortG(ei AutamntodDonortcCorvicoVolidatolzor)C AutomatedReportsServiceValidatic 3035© Auton©) AskAnythingPromptServiceTest.php© Search.phppublic function testGetMediaTypeMetadataUnknown(): void{...}public function testGetTeamIdsWithReportsResults(): void{...}public function testGetTeamReports: voidf...}public function testGetReportResults: voidf...Hpublic function testDeleteReportsResultsInRetentionPeriodNoReports(): void{...public function testDeleteReportsResultsInRetentionPeriodWithNoQueryResults: void{...}public function testUpdateAskJiminnyReportStatusNotAskJiminny0: void{...}public function testUpdateAskJiminnyReportStatusThrowsWhenEnablingWithMissingRef Accept RetectdClassName: AutomatedReport::class)isAskJiminnvReport')KReport->expects(Sthis->once))->wll Returnt valu'undate'):$property = $reflection->getProperty( nameCnnonentv->cetAccoccihle/accessible: tnue$property->setValue($this->service, $mockRepo);$this->expectException(InvalidArgumentException::class)$this->expectExceptionMessage('This report is missing a saved search or prompt.'):$this->service->updateAskJiminnyReportStatus($mockReport.public function testUpdateAskJiminnvReportStatusDoesNotValidateWhenDisablingO: void{...}public function testGetAskJiminnvReportFiltersO: void{...}public function testGetAskJiminnvReportFormDataWithoutReportO: void{...}+v Accept File 3-X Reject File txa+ 7 of 7 files →nublic function testGetAskJiminnvPenortFormDataWithRenortD• voidfJ-ahiects // View null reauect (57 minutes aao)=custom.log= laravel.log4 HS_local [jiminny@localhost]A console [STAGING]CoachinaFeedhackCoachl.Icerin.nhn=194=188 g>280190=192— 193)196.1981= 201= 20129я.209Д215HI I219220221=,..Plavaroundselect * fromactivities where 1d = 422003- # 00U04000000B6FnMACISELECT ar.id, ar.uuid, ar.media type, ar.status, a.typeSp0M automated nenont neculte anJOIN automated_ reports a ON a.id = ar.report idWHERE a.type = 'ask jiminny'LIMIT 10;SELECT * FROM automated reports where id = 71;SELECT * FROM automated report results where report id = 71;UPDATE automated_reports set playbook categories = NULL where id = 68:SELECT * FROM automated report_ results where id = 275SELECT * FROM automated reports order by id desc›SELECT * FROMautomated_reportresults order by 1d desc:select * from activity searches where user id = 143:SELECTautomated renort results' * FROM 'automated renort resultsiINNER JOIN 'automated renortsiautomated renort results' "renort id' = 'automated renorts' 'idiautomated renort results' 'aenerated at' IS NOT NULLautomated renort results' 'sent at' IS NOT NULIautomated nenonts' "toam id' = 1SELECT * EPOM automated nenonte whene id = 47-SELECT * FROM automated_reports where id = 42;SELECT * FROM users WHERE id = 143; # group 28colost + fnom tonme whono id - 71/7.select * from crm_confiqurations where id = 500:SELECT * FROM social accounts WHERE sociable_id = 1695:select * from activities where crm_configuration id = 39and recording state = 'recorded' and duration > 60and status = 'completed' and actual start time >= 12025-12-01'•SELECT * FROM activities WHERE uuid to bin('458cf915-6914-4000-b083-568763262956') = uuidiselect * from leads:Socket fail to connect to host:address=(host=localhost) (port=3306)(tvpe=primarv). Connection refused& console [PROD]# console [euySo jiminny vm 021 A1 A18 V2 Y6 ^hell"supoont Dally • In 40 m100% 5• Tue 19 May 14:14:56AskAnythingPromptServiceTest vCascadeAsk Jiminny Report M+0 ..• AutomatedReportsServiceTest.php+13 -17Review Items AddressedCritical — N41 Queries (fixed)Saved searches - ActivityController.php:1100 now eager-loads via ->withCount ('automatedReports') , and SearchTransformer.oho: 48 reads from automated reports countPrompts - moved loadCount ('automatedReports') into AskAnythingRepository.php:94-100 (single batched countquery for the wholelist). The AskAnythingPrompt: :getHasReports() accessor now prefers automated_reports_countwhen present and Talls back to existso otherwise preserves correctness in other call sies and tests).Mocerate - Business locic moved to serviceAutomatedReportsService.php:1240-1252 now contains the guard and throws InvalidArgumentException . The controllerAsk.iminnvReportsController.pho: 126-166) is back to a thin try/catch with an added InvalidArgumentExcention → 422handler (matches the pattern already used in createAskJiminnyReport and updateAskJiminnyReport).Moderate — lests added• testUpdateAskJiminnvReportStatusthrowswhenEnablingWithMissingReferences — verifies the new validationithrows and update() is never called.• testlndateAskliminnvRenortStatusDoesNotValGidatelhenDisablUing — verifies disabling bvnasses the validationdid not add controller tests per vour "no unit tests for controllers" rule: the service- leve coverage exercises the sameloaic.Miinor — created rerurnS has reports: falseAskAnvthinaPromntService.ohn: 106 now nasses talse exolicitlv. Undated testCreateAskAnvthingPromotwithTwollsers to matchMinor — onBeforedelete onlvon on demandlNot changed in this round - flagged for confirmation. Currently only on_demand prompts can be wired to Ask Jiminnyreports the getAsk.iminnvReportFilters service exolicitly fetches AskAnvthingPromotTarget::on demand ). so thefrontend guard is correctly scoped. Worth a code comment, but no behavioral change needed.ann/Httn/Trancformerc/M SoarchTrancformer.nhnllers/API/ ActivityController.php +1 -1aoo/Models/AskAnvthina/lmAskAnvthinaPromot.ohp +4/1. AskAnvthingPromotServiceTest.php+25-2ts/ AutomatedReportsServiceTest.php +47app/Component/AskAnything/@ AskAnythingPromptService.php +7 -2Ask anvthina 884-L)<> Code Claude Qnus 4.7 MediumReiect alllAccent alliWN Windsurf Toams 2771•6 UTF.8Po 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57901
|
2036
|
22
|
2026-05-19T11:14:52.105997+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189292105_m1.jpg...
|
PhpStorm
|
faVsco.js – AutomatedReportsServiceTest.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 46 m100% C7Tue 19 May 14:14:51ED→Describe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
5342039687352646011
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 46 m100% C7Tue 19 May 14:14:51ED→Describe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
57899
|
NULL
|
NULL
|
NULL
|
|
57900
|
2037
|
30
|
2026-05-19T11:14:50.007078+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189290007_m2.jpg...
|
PhpStorm
|
faVsco.js – AskAnythingRepository.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'...
|
[{"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},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.098071806,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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.8194814,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskAnythingPromptServiceTest","depth":6,"bounds":{"left":0.83477396,"top":0.019952115,"width":0.080784574,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-3826067055318559026
|
-8565424269558293119
|
visual_change
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
PhostormVIewINavicarecodeFV faVsco.js°9 JY-20676-delete-report-related-objectsroledey© AskAnythingController.php© AskAnythingPromptService.php© AutomatedReportsServiceTest.php© EncryptionServiceProvider.php© EventServiceProvider.php© HubspotJournalServiceProvider.php© HubspotWebhookServiceProvider.php© AskAnythingPromptDto.php~/jiminny/app/app/Repositories/AskAnythingRepository.php© AskJiminnyReportsController.php© AutomatedReportsService.php© Search.phpclass ASkAnyth1ngRepos1tory©) Jiminnyservicerrovider.ong© PlanhatServiceProvider.phpc Proonethandlerservicerrovider.onoc Pusnerservicerrovider.ono(C) @ueueLoqServiceProvider.ohp(C) ResponseMacroServiceProvider.oho© RouteServiceProvider.phpc) SsoServiceProvider.oho(C) Uu ServiceProvider.ohoC) ViewerGuardServiceProvider.ohoD Queuev RevositoriesMAiAutoScoringM Calendarv Merm© AccountRepository.php(e) ContactRepository.onp(c) ContactRolerepository.ono© CrmConfigurationRepository.php© CrmEntityRepository.php© FieldDataRepository.php© FieldRepository.php© LayoutEntityRepository.phpLavoutkepositorv.onec) OpportunityRepository.php© ProfileRepository.phpC) RecordTvperieldValuesRepositorv.php© StageRepositorv.phoc) suncbatchrenositorv.ono>M Geography(C) ActiveStreamsRevositorv.oho© ActivityCommentRepository.php(C) ActivitvLoaRenositorv.oho© ActivitvMessageRepositorv.ohp(C) ActivitvMomentRenositorv.ohnl© ActivityProviderRepository.php(C) ActivitvRenositorv.nhn@ ActivitvSearchFilterRepository.php"C) ActivitvShareRenositorv nhn© ActivityUploadSettingRepository.php(C) A:PromntRenositorv nhn(0 AckAnvthinaDonocitory nhn© AutomatedReportsRepository.php© CallImportRepository.phppublic function findSharedPromotBvUser(int Spromptld. User Suser): 2UserAskAnvthingPrompt{...}7 usagespublic function findSharedPromptByUserGroup(int $promptid, User Suser): ?UserAskAnythingPromptt...,18*dreturn Collection<AskAnuthinaPromot›public function findPromptsByUserAndTarget(User $user, AskAnythingPromptTarget $target): Collectior 193$userGroupId = Suser->getGroupIdO:$users0wnedPrompts = UserAskAnythingPrompt::with( relations: 'prompt')->where(static function (Squery) use (Suser, $userGroupId): void {...})operator: false)'prompt', function (Builder Squery) use (Starget) {...})->orderByRaw( sql: 'ISNULL("'order"), 'order''prompt id' ASC')->getO->map(function (UserAskAnythingPrompt SuserPrompt) {...})// Remove those prompts that are hidden for the current userSusers0wnedPromptsFiltered = Susers0wnedPrompts->filter(function (AskAnythingPrompt $userPrompt 205sdetauLtNonChangedPrompts = ASKAnythingPrompt::where( 'target", starget)->whereDoesntHave('userPromots', function (Sauery) use (Suser) {...})->getosreturn SdefaultNonChangedPrompts->merge(Susers0wnedPromptsFiltered):Accept Reject$allPrompts = $defaultNonChangedPrompts->merge(Susers0wnedPromptsFiltered):if ($allPrompts->isNotEmptyO) {$allPrompts->loadCount("automatedReports'D:return saluprompts* dparam arrau<user> sshareuserspublic function1 ediepomtliAccept File 8 +-X Reject File 4%€+ 6 of 7 files →=custom.log= laravel.log4 SF jiminny@localhost] x4 HS_local [jiminny@localhost]A console [STAGING]184188 01911192196197199- 200201203207208209215220221— 225© CoachingFeedbackCoachUserln.phpTx: AutovPlavaroundselect * from activities where id = 422003; # 00U0400000pB6fpMACSELECT ar.id, ar.uuid, ar.mediatype, ar.status, a.typeFROM automated_report_results arJOIN automated_reports a ON a.id = ar.report idWHERE a.type = 'ask jiminny'LIMIT 10;SELECT * FROM automated reports where id = 71;SELECT * FROM automated report results where report id = 71;UPDATE automated reports set playbook categories = NULL where id = 68:SELECT * FROM automated_report_ results where id = 275:SELECT * FROM automated_reports order by 1d desc;SELECT * FROMIautomated_reportresults order by 1d desc:select * from activity_searches where user_ id = 143:SELECTINNER JOIN 'automated renortsautomated renort results * FRiM 'automated remort resultsiautomated remort results', renort id' =automated reoorts'.'1diautomated renort results' generated at' IS NOT NUILLIautomated renort results' 'sent at' IS NOT NULIautomated_reports.team_id = 1AND JSON_CONTAINS( automated_reports'."recipients*, 143, '$."users"')SELECT * FROM automated_reports where id = 67:SELECT * FROM automated_reports where id = 42;SELECT * FROM users WHERE id = 143; # group 28select * from teams where id = 3143:select * from crm confiqurations where id = 500:select * from users where name = 'Integration Account': # 1695SELECT * FROMsocial accounts WHERE sociable_ id = 1695:select * from activities where crm configuration id = 39and recording state = 'recorded' and duration > 60and status = 'completed' and actual start time >= 12025-12-01'•SELECT * FROM activities WHERE uuid to bin('458cf915-6914-4000-b083-568763262956') = uuidiselect * from leads:SELECT * FROM activities WHERE uuid to bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid: # 422003SELECT * FROM activities WHEREid IN (16,422003);Socket fail to connect to host:address=(host=localhost) (port=3306)(tvpe=primarv). Connection refusedhell"supoont Dally • In 40 m100% 5• Tue 19 May 14:14:49AskAnythingPromptServiceTest v& console [PROD]# console [euyCascadeAsk Jiminny Report M+0 ..So jiminny v021 A1 A18 V2 V6 ^• AutomatedReportsServiceTest.php+13 -17Review Items AddressedCritical — N41 Queries (fixed)Saved searches - ActivityController.php:1100 now eager-loads via ->withCount('automatedReports') , and SearchTransformer.oho: 48 reads from automated reports countPrompts - moved loadCount ('automatedReports') into AskAnythingRepository.php:94-100 (single batched countquery for the wholelist). The AskAnythingPrompt: :getHasReports() accessor now prefers automated_reports_countwhen present and Talls back to existso otherwise preserves correctness in other call sies and tests).Mocerate - Business locic moved to serviceAutomatedReportsService.php:1240-1252 now contains the guard and throws InvalidArgumentException . The controllerAsk.iminnvReportsController.pho: 126-166) is back to a thin try/catch with an added InvalidArgumentExcention → 422handler (matches the pattern already used in createAskJiminnyReport and updateAskJiminnyReport).Moderate — lests added• testUpdateAskJiminnvReportStatusthrowswhenEnablingWithMissingReferences — verifies the new validationithrows and update() is never called.• testlndateAskliminnvRenortStatusDoesNotValGidatelhenDisablUing — verifies disabling bvnasses the validationdid not add controller tests per vour "no unit tests for controllers" rule: the service- leve coverage exercises the sameloaic.Miinor — created rerurnS has reports: falseAskAnvthinaPromntService.ohn: 106 now nasses talse exolicitlv. Undated testCreateAskAnvthingPromotwithTwollsers to matchMinor — onBeforedelete onlvon on demandlNot changed in this round - flagged for confirmation. Currently only on_demand prompts can be wired to Ask Jiminnyreports the getAsk.iminnvReportFilters service exolicitly fetches AskAnvthingPromotTarget::on demand ). so thefrontend guard is correctly scoped. Worth a code comment, but no behavioral change needed.ann/Httn/Trancformerc/M SoarchTrancformer.nhnllers/API/ ActivityController.php +1 -1aoo/Models/AskAnvthina/lmAskAnvthinaPromot.ohp +4/1. AskAnvthingPromotServiceTest.php+25-2ts/ AutomatedReportsServiceTest.php +47app/Component/AskAnything/@ AskAnythingPromptService.php +7-2Ask anvthina 884-L)<> Code Claude Qnus 4.7 Medium* Reiect alliiAccent allWN Windsurf Teams107-24UTE.8Po 4 spaces...
|
57898
|
NULL
|
NULL
|
NULL
|
|
57899
|
2036
|
21
|
2026-05-19T11:14:48.170868+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189288170_m1.jpg...
|
PhpStorm
|
faVsco.js – AskAnythingRepository.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 46 m100% C7Tue 19 May 14:14:47ED→Describe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
6065880086733995107
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 46 m100% C7Tue 19 May 14:14:47ED→Describe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57898
|
2037
|
29
|
2026-05-19T11:14:45.587058+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189285587_m2.jpg...
|
PhpStorm
|
faVsco.js – AskAnythingPromptService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormViewINavicarecodeLaravelKeractorWindowmelp PhostormViewINavicarecodeLaravelKeractorWindowmelpFV faVsco.js?9 JY-20676-delete-report-related-objectsroledeyCActivityController.ong© SearchTransformer.php X php api.php© AskAnythingController.php© CoachingSectionFeedbacksTransformer© CoachingSectionsTransformer.php© CoachingSectionTransformer.php© CommentTransformerAbstract.php© AskAnythingPromptService.php >© AutomatedReportsServiceTest.phpoconnection transtormer.onpcontdellranstormer.one© CrmTemplateFieldTransformer.phpc crmiemplatelranstormer.onp© CrmTransformer.phpDatalranstormer.onpc DealstageIranstormer.pnpc) reaturelranstormer.pnpc) rieldIranstormer.onoc) rielcvalue lranstormer.onoC) ForecastTranstormer.ohpc) GroupDealRiskTvoeTranstormer.oho© GroupTransformer.php©Intearationtiranstormer.oho© InvitationTransformer.ohpc) ,oo tetranstormer.ono© LanquageDialectTransformer.ohp© LayoutEntityTransformer.php©LayoutTransformer.phpC) LeadTransformer.oho@ MessageTransformer.oho© MomentTransformer.php© NoteTransformer.php© NotificationTransformer.php© OnDemandActivitiesTransformer.php© OpportunityCommentTransformer.php© OpportunityTransformer.php(c) Particinantranstormer.ong(e) DartnerTranstormer.ong© PermissionTransformer.php© PlaybackPageTransformer.php© PlaybookTransformer.php© PlaybookTreeTransformer.phpPlavlistActivitvTransformer.phpPlavlistSharesTransformer.php@ PlavlistTransformer.phpc)Prosoectsfranstormer.onoC) RecordTivoeTransformer.ohoC) RoleTransformer.ohoC) SconeGrouotiransformer.ohoC) ScorecardRuleTiransformer.ohoC) ScorecardRuleTriagerTransformer.oho(c) Scorecardtiransformer nhnl(C) Saccion Transformer nhn(C) StadeTransformer nhn© AskAnythingPromptDtc~/jiminny/app/app/Component/AskAnything/AskAnythingPromptService.php© AskJiminnyReportsConk?phpnamespace Jiminny Http Transtormers:›use ...class Searchtransformer extends TransformerAbstract23625protected arrav Savailableincludes =protected array $defaultIncludes =private User $consumer:pUbLic Tunccion__construct(privare readonly Aculvitysearch saculvlcysearch,privace readonly nuacelranstormer snuccelranstorner,private readonly Loggerintertace Slogger.D{...}public function withConsumer(User Suser): selfsthas->consumer = suser:return Sthis:public function transformSearch Ssearch): arrav.return"id' = Ssearch->id string.'namel => Ssearch->aetNameOl.'filters' => $this->getFilters($search),'has_reports' => $search->automatedReports()-›exists(),'has reports' => ((int) (Ssearch->automated reports count ?? 0)) > 0.public function includeNudaes(Search Ssearch): Fractal\Resource\Collectionf...}public function getFilters(Search Ssearch): arrav{...?lX Reject File txg+ 2 of 7 files →© Search.phpAccent Reject=custom.log= laravel.log4 SF jiminny@localhost] x4 HS_local [jiminny@localhost]& console [PROD]# console [euyA console [STAGING]C) CoachinaFeedhackCoachl.Icerin.nhn .209213215219220Tx: AutovPlavaroundSo jiminny vselect * from activities where 1d = 422003• # 00U04000000B6FMACIm 021 A1 A18 V2 Y6 ^SELECT ar.id, ar.uuid, ar.media type, ar.status, a.typeSp0M automated nenont neculte anJOIN automated_reports a ON a.id = ar.report idWHERE a.type = 'ask jiminny'LIMIT 10;SELECT * FROM automated_reports where id = 71:SELECT * FROM automated report results where report id = 71;UPDATE automated_reports set playbook categories = NULL where id = 68:SELECT * FROM automated report_ results where id = 275SELECT * FROM automated reports order by id desc›SELECT * FROMautomated_reportresults order by 1d desc:select * from activity searches where user id = 143:SELECTautomated renort results' * FROM 'automated renort resultsiINNER JOIN 'automated renortsiautomated renort results' "renort id' = 'automated renorts' 'idiautomated renort results' 'aenerated at' IS NoT NuLlautomated renort results' 'sent at' IS NOT NULIAND ISON CONTATNS('automated nenonte' "neciniente'. 147 Id lucengll)SELECT * EPOM automated nenonte whene id = 47-SELECT * FROM automated_reports where id = 42;SELECT * FROM users WHERE id = 143; # group 28colost + fnom tonme whono id - 71/7.select * from crm_confiqurations where id = 500:select * from users where name = 'Integration Account': # 1695SELECT * FROM social accounts WHERE sociable_id = 1695:select * from activities where crm_configuration id = 39and recording state = 'recorded' and duration > 60and status = 'completed' and actual stant time >= 12025-12-01'.SELECT * FROM activities WHERE uuid to bin(•458cf915-6914-4000-b083-568763262956') = uuidiselect * from leads:SELECT * FROM activities WHERE uuid to bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid: # 422003SFLECT + EPOM activitiec WHEPE id TN (16. 422003).Socket fail to connect to host:address=(host=localhost) (port=3306)(tvpe=primarv). Connection refusedhall"supoont Dally • In 40 m100% 5• Tue 19 May 14:14:45AskAnythingPromptServiceTest vCascadeAsk Jiminny Report M+0 ..• AutomatedReportsServiceTest.php+13 -17Review Items AddressedCritical — N41 Queries (fixed)Saved searches - ActivityController.php:1100 now eager-loads via ->withCount ('automatedReports') , and SearchTransformer.oho: 48 reads from automated reports countPrompts - moved loadCount ('automatedReports') into AskAnythingRepository.php:94-100 (single batched countquery for the wholelist). The AskAnythingPrompt: :getHasReports() accessor now prefers automated_reports_countwhen present and Talls back to existso otherwise preserves correctness in other call sies and tests).Mocerate - Business locic moved to serviceAutomatedReportsService.php:1240-1252 now contains the guard and throws InvalidArgumentException . The controllerAsk.iminnvReportsController.pho: 126-166) is back to a thin try/catch with an added InvalidArgumentExcention → 422handler (matches the pattern already used in createAskJiminnyReport and updateAskJiminnyReport).Moderate — lests added• testUpdateAskJiminnvReportStatusthrowswhenEnablingWithMissingReferences — verifies the new validationithrows and update() is never called.• testlndateAskliminnvRenortStatusDoesNotValGidatelhenDisablUing — verifies disabling bvnasses the validationdid not add controller tests per vour "no unit tests for controllers" rule: the service- leve coverage exercises the sameloaic.Miinor — created rerurnS has reports: falseAskAnvthinaPromntService.ohn: 106 now nasses talse exolicitlv. Undated testCreateAskAnvthingPromotwithTwollsers to matchMinor — onBeforedelete onlvon on demandlNot changed in this round - flagged for confirmation. Currently only on_demand prompts can be wired to Ask Jiminnyreports the getAsk.iminnvReportFilters service exolicitly fetches AskAnvthingPromotTarget::on demand ). so thefrontend guard is correctly scoped. Worth a code comment, but no behavioral change needed.ann/Httn/Trancformerc/M SoarchTrancformer.nhnllers/API/ ActivityController.php +1 -1aoo/Models/AskAnvthina/lmAskAnvthinaPromot.ohp +4/1. AskAnvthingPromotServiceTest.php+25-2ts/ AutomatedReportsServiceTest.php +47app/Component/AskAnything/@ AskAnythingPromptService.php +7-2Ask anvthina 884-L)<> Code Claude Qnus 4.7 MediumReiect allAccent alliW Windsurf Teamc1-1.UTE.8Po 4 spaces...
|
NULL
|
-4225189718868304847
|
NULL
|
click
|
ocr
|
NULL
|
PhostormViewINavicarecodeLaravelKeractorWindowmelp PhostormViewINavicarecodeLaravelKeractorWindowmelpFV faVsco.js?9 JY-20676-delete-report-related-objectsroledeyCActivityController.ong© SearchTransformer.php X php api.php© AskAnythingController.php© CoachingSectionFeedbacksTransformer© CoachingSectionsTransformer.php© CoachingSectionTransformer.php© CommentTransformerAbstract.php© AskAnythingPromptService.php >© AutomatedReportsServiceTest.phpoconnection transtormer.onpcontdellranstormer.one© CrmTemplateFieldTransformer.phpc crmiemplatelranstormer.onp© CrmTransformer.phpDatalranstormer.onpc DealstageIranstormer.pnpc) reaturelranstormer.pnpc) rieldIranstormer.onoc) rielcvalue lranstormer.onoC) ForecastTranstormer.ohpc) GroupDealRiskTvoeTranstormer.oho© GroupTransformer.php©Intearationtiranstormer.oho© InvitationTransformer.ohpc) ,oo tetranstormer.ono© LanquageDialectTransformer.ohp© LayoutEntityTransformer.php©LayoutTransformer.phpC) LeadTransformer.oho@ MessageTransformer.oho© MomentTransformer.php© NoteTransformer.php© NotificationTransformer.php© OnDemandActivitiesTransformer.php© OpportunityCommentTransformer.php© OpportunityTransformer.php(c) Particinantranstormer.ong(e) DartnerTranstormer.ong© PermissionTransformer.php© PlaybackPageTransformer.php© PlaybookTransformer.php© PlaybookTreeTransformer.phpPlavlistActivitvTransformer.phpPlavlistSharesTransformer.php@ PlavlistTransformer.phpc)Prosoectsfranstormer.onoC) RecordTivoeTransformer.ohoC) RoleTransformer.ohoC) SconeGrouotiransformer.ohoC) ScorecardRuleTiransformer.ohoC) ScorecardRuleTriagerTransformer.oho(c) Scorecardtiransformer nhnl(C) Saccion Transformer nhn(C) StadeTransformer nhn© AskAnythingPromptDtc~/jiminny/app/app/Component/AskAnything/AskAnythingPromptService.php© AskJiminnyReportsConk?phpnamespace Jiminny Http Transtormers:›use ...class Searchtransformer extends TransformerAbstract23625protected arrav Savailableincludes =protected array $defaultIncludes =private User $consumer:pUbLic Tunccion__construct(privare readonly Aculvitysearch saculvlcysearch,privace readonly nuacelranstormer snuccelranstorner,private readonly Loggerintertace Slogger.D{...}public function withConsumer(User Suser): selfsthas->consumer = suser:return Sthis:public function transformSearch Ssearch): arrav.return"id' = Ssearch->id string.'namel => Ssearch->aetNameOl.'filters' => $this->getFilters($search),'has_reports' => $search->automatedReports()-›exists(),'has reports' => ((int) (Ssearch->automated reports count ?? 0)) > 0.public function includeNudaes(Search Ssearch): Fractal\Resource\Collectionf...}public function getFilters(Search Ssearch): arrav{...?lX Reject File txg+ 2 of 7 files →© Search.phpAccent Reject=custom.log= laravel.log4 SF jiminny@localhost] x4 HS_local [jiminny@localhost]& console [PROD]# console [euyA console [STAGING]C) CoachinaFeedhackCoachl.Icerin.nhn .209213215219220Tx: AutovPlavaroundSo jiminny vselect * from activities where 1d = 422003• # 00U04000000B6FMACIm 021 A1 A18 V2 Y6 ^SELECT ar.id, ar.uuid, ar.media type, ar.status, a.typeSp0M automated nenont neculte anJOIN automated_reports a ON a.id = ar.report idWHERE a.type = 'ask jiminny'LIMIT 10;SELECT * FROM automated_reports where id = 71:SELECT * FROM automated report results where report id = 71;UPDATE automated_reports set playbook categories = NULL where id = 68:SELECT * FROM automated report_ results where id = 275SELECT * FROM automated reports order by id desc›SELECT * FROMautomated_reportresults order by 1d desc:select * from activity searches where user id = 143:SELECTautomated renort results' * FROM 'automated renort resultsiINNER JOIN 'automated renortsiautomated renort results' "renort id' = 'automated renorts' 'idiautomated renort results' 'aenerated at' IS NoT NuLlautomated renort results' 'sent at' IS NOT NULIAND ISON CONTATNS('automated nenonte' "neciniente'. 147 Id lucengll)SELECT * EPOM automated nenonte whene id = 47-SELECT * FROM automated_reports where id = 42;SELECT * FROM users WHERE id = 143; # group 28colost + fnom tonme whono id - 71/7.select * from crm_confiqurations where id = 500:select * from users where name = 'Integration Account': # 1695SELECT * FROM social accounts WHERE sociable_id = 1695:select * from activities where crm_configuration id = 39and recording state = 'recorded' and duration > 60and status = 'completed' and actual stant time >= 12025-12-01'.SELECT * FROM activities WHERE uuid to bin(•458cf915-6914-4000-b083-568763262956') = uuidiselect * from leads:SELECT * FROM activities WHERE uuid to bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid: # 422003SFLECT + EPOM activitiec WHEPE id TN (16. 422003).Socket fail to connect to host:address=(host=localhost) (port=3306)(tvpe=primarv). Connection refusedhall"supoont Dally • In 40 m100% 5• Tue 19 May 14:14:45AskAnythingPromptServiceTest vCascadeAsk Jiminny Report M+0 ..• AutomatedReportsServiceTest.php+13 -17Review Items AddressedCritical — N41 Queries (fixed)Saved searches - ActivityController.php:1100 now eager-loads via ->withCount ('automatedReports') , and SearchTransformer.oho: 48 reads from automated reports countPrompts - moved loadCount ('automatedReports') into AskAnythingRepository.php:94-100 (single batched countquery for the wholelist). The AskAnythingPrompt: :getHasReports() accessor now prefers automated_reports_countwhen present and Talls back to existso otherwise preserves correctness in other call sies and tests).Mocerate - Business locic moved to serviceAutomatedReportsService.php:1240-1252 now contains the guard and throws InvalidArgumentException . The controllerAsk.iminnvReportsController.pho: 126-166) is back to a thin try/catch with an added InvalidArgumentExcention → 422handler (matches the pattern already used in createAskJiminnyReport and updateAskJiminnyReport).Moderate — lests added• testUpdateAskJiminnvReportStatusthrowswhenEnablingWithMissingReferences — verifies the new validationithrows and update() is never called.• testlndateAskliminnvRenortStatusDoesNotValGidatelhenDisablUing — verifies disabling bvnasses the validationdid not add controller tests per vour "no unit tests for controllers" rule: the service- leve coverage exercises the sameloaic.Miinor — created rerurnS has reports: falseAskAnvthinaPromntService.ohn: 106 now nasses talse exolicitlv. Undated testCreateAskAnvthingPromotwithTwollsers to matchMinor — onBeforedelete onlvon on demandlNot changed in this round - flagged for confirmation. Currently only on_demand prompts can be wired to Ask Jiminnyreports the getAsk.iminnvReportFilters service exolicitly fetches AskAnvthingPromotTarget::on demand ). so thefrontend guard is correctly scoped. Worth a code comment, but no behavioral change needed.ann/Httn/Trancformerc/M SoarchTrancformer.nhnllers/API/ ActivityController.php +1 -1aoo/Models/AskAnvthina/lmAskAnvthinaPromot.ohp +4/1. AskAnvthingPromotServiceTest.php+25-2ts/ AutomatedReportsServiceTest.php +47app/Component/AskAnything/@ AskAnythingPromptService.php +7-2Ask anvthina 884-L)<> Code Claude Qnus 4.7 MediumReiect allAccent alliW Windsurf Teamc1-1.UTE.8Po 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57897
|
2036
|
20
|
2026-05-19T11:14:45.619850+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189285619_m1.jpg...
|
PhpStorm
|
faVsco.js – AskAnythingPromptService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 46 m100% C7Tue 19 May 14:14:45ED→QDescribe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
-4591976918575062233
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 46 m100% C7Tue 19 May 14:14:45ED→QDescribe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
57896
|
NULL
|
NULL
|
NULL
|
|
57896
|
2036
|
19
|
2026-05-19T11:14:40.091736+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189280091_m1.jpg...
|
PhpStorm
|
faVsco.js – ActivityController.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 46 m100% C7Tue 19 May 14:14:39ED→QDescribe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
-2761543934783336683
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 46 m100% C7Tue 19 May 14:14:39ED→QDescribe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57895
|
2037
|
28
|
2026-05-19T11:14:39.211671+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189279211_m2.jpg...
|
PhpStorm
|
faVsco.js – AskAnythingPrompt.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
1
Previous Highlighted Error
Next Highlighted Error...
|
[{"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},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.098071806,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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.8194814,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskAnythingPromptServiceTest","depth":6,"bounds":{"left":0.83477396,"top":0.019952115,"width":0.080784574,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-1547108372712718892
|
-3772797120701805632
|
visual_change
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
1
Previous Highlighted Error
Next Highlighted Error
PhostormVIewINavicarecodeTOOISWindowFV faVsco.js°9 JY-20676-delete-report-related-objectsProiect vC ActivityController.ong© SearchTransformer.phpphp api.php© AskAnythingController.phpD Ai• @ AskAnything© AskAnythingPrompt.php© AskAnythingPromptService.php© AutomatedReportsServiceTest.phpe AsKAnytningPromptlarget.onpc useraskAnythingPrompt.onpucalenda0 Connectionw contracts0 Crmc) BusinessProcess.ohpc) contiquration.phpc) ContactRole.ohpc) Fieldono© FieldData.phpC) FieldValue.ohoC) Lavout ohoC)LavoutEntitv.oho© Log.phpc) Profile nhn© RecordType.php© SyncBatch.php1M GlasticSearchD Feature_ UpporunityD ParticipantD PlaybackThemeD Playlist0 Webhookc) Account.pho© Activity.php© Address.php(c) AlPrompt.php(c) Automated ReportResult.ono(C) CoachinaFeedback.oho(C) CoachinaFeedbackVisiollitv.ohv(C) CoachinaSection.oho(C) CoachingSectioncriterion.ohv@ CoachinaSectionGriterionFeedback.ohn© AskAnythingPromptDto.php© AskJiminnyReportsController.php© AutomatedReportsService.php©) AskAnythingPromptServiceTest.phpMN&BEỐclass ASKAnythingPrompt extends Model"title","concent",owner.10',protected Svisible ="tatle',32 011protected function castso: arrav-...public function owner(): Relations \BelongsTot...public function get0wnerO: ?Usert...no usagespublic function userPrompts: Relations \HasMany(...}public function automatedReports: Relations \HasMany{...}public function getUuid(): string{...}public function getidO: intf...}lpublic function getOwnerIdO: ?int{...}9 usagespublic function aetTarget(: AskAnvthingPromptTarget!...}* Promot is considered default when it has no ownen* dreturn bool(C) CoachinaSectionFeedback nhn(@. CommentAbstract nhn1Commentinterface.nhnnublic function islefaul+Promnto- hoold...?(C) Contact nhnlC) Device nhn |public function getTitle: string{...}© EmailMessage.php© GenericAiPrompt.php@ Group.php© Inbox.phppublic function getContent: string{...Accept File &~X Reject File 4%€+ 3 of 7 files →© Search.php=custom.log= laravel.log4 SF jiminny@localhost] x4 HS_local [jiminny@localhost]# concole ISTAGinG1C) CoachinaFeedhackCoachl.Icerin.nhn188 0190192194195)196197198199200201_ 202203205294207299.209215220Plavaroundselect * from activities where 1d = 422003• # 00U04000000B6FMACISELECT ar.id, ar.uuid, ar.media type, ar.status, a.typeSp0M automated nenont neculte anJOIN automated_reports a ON a.id = ar.report idWHERE a.type = 'ask jiminny'ITMTT 10-SELECT * FROM automated_reports where id = 71:SELECT * FROM automated report results where report id = 71;UPDATE automated_reports set playbook categories = NULL where id = 68:SELECT * FROM automated_report_ results where id = 275:SELECT * FROM automated reports order by id desc›SELECT * FROMautomated_reportresults order by 1d desc:select * from activity searches where user id = 143:SELECTautomated renort results' * FROM 'automated renort resultsiINNER JOIN 'automated renortsiautomated renort results' "renort id' = 'automated renorts' 'idiautomated renort results' 'aenerated at' IS NoT NuLlautomated renort results' sent at' IS NOT NULIautomated nenonts' "toam id' = 1SELECT * EPOM automated nenonte whene id = 47-SELECT * FROM automated_reports where id = 42;SELECT * FROM users WHERE id = 143; # group 28select * from crm_confiqurations where id = 500:select * from users where name = 'Integration Account': # 1695CCLEeT + CDOMcosiol aosounte MuEpE conjohlo id - 1405.select * from activities where crm_configuration id = 39and recording state = 'recorded' and duration > 60and status = 'completed' and actual start time >= 12025-12-01'•SELECT * FROM activities WHERE uuid to bin(•458cf915-6914-4000-b083-568763262956') = uuidiselect * from leads:SELECT * FROM activities WHERE uuid to bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid: # 422003SFLECT + EPOM activitiec WHEPE id TN (16. 422003).Socket fail to connect to host:address=(host=localhost) (port=3306)(tvpe=primarv). Connection refusedhell"supoont Dally • In 40 m100% 5• Tue 19 May 14:14:38AskAnythingPromptServiceTest v& console [PROD]# console [euyCascadeAsk Jiminny Report M+0 ..So jiminny vm 021 A1 A18 V2 Y6 ^• AutomatedReportsServiceTest.php+13 -17Review Items AddressedCritical — N41 Queries (fixed)Saved searches - ActivityController.php:1100 now eager-loads via ->withCount ('automatedReports') , and SearchTransformer.oho: 48 reads from automated reports countPrompts - moved loadCount ('automatedReports') into AskAnythingRepository.php:94-100 (single batched countquery for the wholelist). The AskAnythingPrompt: :getHasReports() accessor now prefers automated_reports_countwhen present and Talls back to existso otherwise preserves correctness in other call sies and tests).Mocerate - Business locic moved to serviceAutomatedReportsService.php:1240-1252 now contains the guard and throws InvalidArgumentException . The controllerAsk.iminnvReportsController.pho: 126-166) is back to a thin try/catch with an added InvalidArgumentExcention → 422handler (matches the pattern already used in createAskJiminnyReport and updateAskJiminnyReport).Moderate — lests added• testUpdateAskJiminnvReportStatusthrowswhenEnablingWithMissingReferences — verifies the new validationithrows and update() is never called.• testlndateAskliminnvRenortStatusDoesNotValGidatelhenDisablUing — verifies disabling bvnasses the validationdid not add controller tests per vour "no unit tests for controllers" rule: the service- leve coverage exercises the sameloaic.Miinor — created rerurnS has reports: falseAskAnvthinaPromntService.ohn: 106 now nasses talse exolicitlv. Undated testCreateAskAnvthingPromotwithTwollsers to matchMinor — onBeforedelete onlvon on demandlNot changed in this round - flagged for confirmation. Currently only on_demand prompts can be wired to Ask Jiminnyreports the getAsk.iminnvReportFilters service exolicitly fetches AskAnvthingPromotTarget::on demand ). so thefrontend guard is correctly scoped. Worth a code comment, but no behavioral change needed.ann/Httn/Trancformerc/M SoarchTrancformer.nhnllers/API/ ActivityController.php +1 -1aoo/Models/AskAnvthina/lmAskAnvthinaPromot.ohp +4/1. AskAnvthingPromotServiceTest.php+25-2ts/ AutomatedReportsServiceTest.php +47app/Component/AskAnything/@ AskAnythingPromptService.php +7-2Ask anvthina 884-L)<> Code Claude Qnus 4.7 MediumReiect alllAccent alliWN Windsurf Teamc104-1UTE.8io 4 spaces...
|
57894
|
NULL
|
NULL
|
NULL
|
|
57894
|
2037
|
27
|
2026-05-19T11:14:33.133076+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189273133_m2.jpg...
|
PhpStorm
|
faVsco.js – AskAnythingPrompt.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Models\AskAnything;
use Illuminate\Database\Eloquent\Relations;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Model;
use Jiminny\Models\User;
use Jiminny\Traits\RequiresUUID;
class AskAnythingPrompt extends Model
{
use RequiresUUID;
protected $table = 'ask_anything_prompts';
protected $fillable = [
'title',
'content',
'target',
'owner_id',
];
protected $visible = [
'title',
'content',
'owner_id',
];
protected function casts(): array
{
return [
'title' => 'string',
'content' => 'string',
'target' => AskAnythingPromptTarget::class,
'owner_id' => 'integer',
];
}
public function owner(): Relations\BelongsTo
{
return $this->belongsTo(User::class);
}
public function getOwner(): ?User
{
return $this->getAttribute('owner');
}
public function userPrompts(): Relations\HasMany
{
return $this->hasMany(UserAskAnythingPrompt::class, 'prompt_id');
}
public function automatedReports(): Relations\HasMany
{
return $this->hasMany(AutomatedReport::class, 'ask_anything_prompt_id');
}
public function getUuid(): string
{
return $this->getAttribute('id_string');
}
public function getId(): int
{
return $this->getAttribute('id');
}
public function getOwnerId(): ?int
{
return $this->getAttribute('owner_id');
}
public function getTarget(): AskAnythingPromptTarget
{
return $this->getAttribute('target');
}
/**
* Prompt is considered default when it has no owner
*
* @return bool
*/
public function isDefaultPrompt(): bool
{
return $this->getOwnerId() === null;
}
public function getTitle(): string
{
return $this->getAttribute('title');
}
public function getContent(): string
{
return $this->getAttribute('content');
}
public function getHasReports(): bool
{
if (array_key_exists('automated_reports_count', $this->getAttributes())) {
return ((int) $this->getAttribute('automated_reports_count')) > 0;
}
return $this->automatedReports()->exists();
}
}
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
21
1
18
2
6
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 sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id
where u.team_id = 1;
SELECT * FROM social_accounts WHERE sociable_id = 1635;
SELECT * FROM users WHERE id = 1635;
select * from teams where id = 1;
select * from users where team_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 activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;
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 automated_reports where id = 71;
SELECT * FROM automated_report_results where report_id = 71;
UPDATE automated_reports set playbook_categories = NULL 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 `automated_report_results`.* FROM `automated_report_results`
INNER JOIN `automated_reports`
ON `automated_report_results`.`report_id` = `automated_reports`.`id`
WHERE 1=1
AND `automated_report_results`.`generated_at` IS NOT NULL
# AND `automated_report_results`.`sent_at` IS NOT NULL
AND `automated_reports`.`team_id` = 1
AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$."users"')
;
SELECT * FROM automated_reports where id = 67;
SELECT * FROM automated_reports where id = 42;
SELECT * FROM users WHERE id = 143; # group 28
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;
select * from leads;
SELECT * FROM activities WHERE uuid_to_bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid; # 422003
SELECT * FROM activities WHERE id IN (16,422003);
SELECT * FROM activities where status = 'failed';
SELECT * FROM tracks WHERE activity_id = 422003;
SELECT
a.*
FROM activities a
JOIN users u ON a.user_id = u.id
WHERE
a.status = 'completed'
AND uuid_to_bin('641f1acb-16b8-42d1-8726-df52979dad0e') = u.uuid
AND a.deleted_at IS NULL
AND EXISTS (
SELECT 1 FROM tracks t
WHERE t.activity_id = a.id
AND t.type IN ('audio', 'video')
)
ORDER BY a.actual_start_time DESC
LIMIT 25;
select * from teams where id = 19;
select * from crm_configurations where provider = 'pipedrive';
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 = 19 and sa.provider = 'pipedrive';
SELECT * FROM social_accounts WHERE id = 1116;
UPDATE social_accounts SET provider_user_token = 'v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA',
provider_refresh_token = '5034113:[TELEGRAM_TOKEN]b2bfc',
expires = 1779091997,
state = 'connected'
WHERE id = 1116;
"provider_user_token": "v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA",
"provider_refresh_token": "5034113:[TELEGRAM_TOKEN]b2bfc",
"expires": 1779091997,
Socket fail to connect to host:address=(host=localhost)(port=3306)(type=primary). Connection refused
Project
Project
New File or Directory…
Expand Selected...
|
[{"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},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.098071806,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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.8194814,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskAnythingPromptServiceTest","depth":6,"bounds":{"left":0.83477396,"top":0.019952115,"width":0.080784574,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"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},"on_screen":false,"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\\Models\\AskAnything;\n\nuse Illuminate\\Database\\Eloquent\\Relations;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Model;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Traits\\RequiresUUID;\n\nclass AskAnythingPrompt extends Model\n{\n use RequiresUUID;\n\n protected $table = 'ask_anything_prompts';\n\n protected $fillable = [\n 'title',\n 'content',\n 'target',\n 'owner_id',\n ];\n\n protected $visible = [\n 'title',\n 'content',\n 'owner_id',\n ];\n\n protected function casts(): array\n {\n return [\n 'title' => 'string',\n 'content' => 'string',\n 'target' => AskAnythingPromptTarget::class,\n 'owner_id' => 'integer',\n ];\n }\n\n public function owner(): Relations\\BelongsTo\n {\n return $this->belongsTo(User::class);\n }\n\n public function getOwner(): ?User\n {\n return $this->getAttribute('owner');\n }\n\n public function userPrompts(): Relations\\HasMany\n {\n return $this->hasMany(UserAskAnythingPrompt::class, 'prompt_id');\n }\n\n public function automatedReports(): Relations\\HasMany\n {\n return $this->hasMany(AutomatedReport::class, 'ask_anything_prompt_id');\n }\n\n public function getUuid(): string\n {\n return $this->getAttribute('id_string');\n }\n\n public function getId(): int\n {\n return $this->getAttribute('id');\n }\n\n public function getOwnerId(): ?int\n {\n return $this->getAttribute('owner_id');\n }\n\n public function getTarget(): AskAnythingPromptTarget\n {\n return $this->getAttribute('target');\n }\n\n /**\n * Prompt is considered default when it has no owner\n *\n * @return bool\n */\n public function isDefaultPrompt(): bool\n {\n return $this->getOwnerId() === null;\n }\n\n public function getTitle(): string\n {\n return $this->getAttribute('title');\n }\n\n public function getContent(): string\n {\n return $this->getAttribute('content');\n }\n\n public function getHasReports(): bool\n {\n if (array_key_exists('automated_reports_count', $this->getAttributes())) {\n return ((int) $this->getAttribute('automated_reports_count')) > 0;\n }\n\n return $this->automatedReports()->exists();\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Models\\AskAnything;\n\nuse Illuminate\\Database\\Eloquent\\Relations;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\Model;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Traits\\RequiresUUID;\n\nclass AskAnythingPrompt extends Model\n{\n use RequiresUUID;\n\n protected $table = 'ask_anything_prompts';\n\n protected $fillable = [\n 'title',\n 'content',\n 'target',\n 'owner_id',\n ];\n\n protected $visible = [\n 'title',\n 'content',\n 'owner_id',\n ];\n\n protected function casts(): array\n {\n return [\n 'title' => 'string',\n 'content' => 'string',\n 'target' => AskAnythingPromptTarget::class,\n 'owner_id' => 'integer',\n ];\n }\n\n public function owner(): Relations\\BelongsTo\n {\n return $this->belongsTo(User::class);\n }\n\n public function getOwner(): ?User\n {\n return $this->getAttribute('owner');\n }\n\n public function userPrompts(): Relations\\HasMany\n {\n return $this->hasMany(UserAskAnythingPrompt::class, 'prompt_id');\n }\n\n public function automatedReports(): Relations\\HasMany\n {\n return $this->hasMany(AutomatedReport::class, 'ask_anything_prompt_id');\n }\n\n public function getUuid(): string\n {\n return $this->getAttribute('id_string');\n }\n\n public function getId(): int\n {\n return $this->getAttribute('id');\n }\n\n public function getOwnerId(): ?int\n {\n return $this->getAttribute('owner_id');\n }\n\n public function getTarget(): AskAnythingPromptTarget\n {\n return $this->getAttribute('target');\n }\n\n /**\n * Prompt is considered default when it has no owner\n *\n * @return bool\n */\n public function isDefaultPrompt(): bool\n {\n return $this->getOwnerId() === null;\n }\n\n public function getTitle(): string\n {\n return $this->getAttribute('title');\n }\n\n public function getContent(): string\n {\n return $this->getAttribute('content');\n }\n\n public function getHasReports(): bool\n {\n if (array_key_exists('automated_reports_count', $this->getAttributes())) {\n return ((int) $this->getAttribute('automated_reports_count')) > 0;\n }\n\n return $this->automatedReports()->exists();\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.42785904,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.43650267,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.4474734,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.45611703,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.46476063,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.47573137,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.4867021,"top":0.09896249,"width":0.024268618,"height":0.01915403},"on_screen":true,"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.51329786,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"bounds":{"left":0.5242686,"top":0.09896249,"width":0.029587766,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"bounds":{"left":0.70611703,"top":0.09896249,"width":0.02825798,"height":0.01915403},"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"21","depth":4,"bounds":{"left":0.66921544,"top":0.123703115,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.68085104,"top":0.123703115,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"18","depth":4,"bounds":{"left":0.69015956,"top":0.123703115,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.7017952,"top":0.123703115,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.7117686,"top":0.123703115,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.72140956,"top":0.12210695,"width":0.00731383,"height":0.018355945},"on_screen":true,"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.7287234,"top":0.12210695,"width":0.006981383,"height":0.018355945},"on_screen":true,"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\n\nselect sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id\nwhere u.team_id = 1;\nSELECT * FROM social_accounts WHERE sociable_id = 1635;\nSELECT * FROM users WHERE id = 1635;\n\nselect * from teams where id = 1;\nselect * from users where team_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 activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;\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\nSELECT * FROM automated_reports where id = 71;\nSELECT * FROM automated_report_results where report_id = 71;\nUPDATE automated_reports set playbook_categories = NULL 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 `automated_report_results`.* FROM `automated_report_results`\nINNER JOIN `automated_reports`\n ON `automated_report_results`.`report_id` = `automated_reports`.`id`\nWHERE 1=1\n AND `automated_report_results`.`generated_at` IS NOT NULL\n# AND `automated_report_results`.`sent_at` IS NOT NULL\n AND `automated_reports`.`team_id` = 1\n AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$.\"users\"')\n;\n\nSELECT * FROM automated_reports where id = 67;\nSELECT * FROM automated_reports where id = 42;\nSELECT * FROM users WHERE id = 143; # group 28\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;\n\nselect * from leads;\n\nSELECT * FROM activities WHERE uuid_to_bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid; # 422003\nSELECT * FROM activities WHERE id IN (16,422003);\nSELECT * FROM activities where status = 'failed';\n\nSELECT * FROM tracks WHERE activity_id = 422003;\n\nSELECT\n a.*\nFROM activities a\nJOIN users u ON a.user_id = u.id\nWHERE\n a.status = 'completed'\n AND uuid_to_bin('641f1acb-16b8-42d1-8726-df52979dad0e') = u.uuid\n AND a.deleted_at IS NULL\n AND EXISTS (\n SELECT 1 FROM tracks t\n WHERE t.activity_id = a.id\n AND t.type IN ('audio', 'video')\n )\nORDER BY a.actual_start_time DESC\nLIMIT 25;\n\nselect * from teams where id = 19;\nselect * from crm_configurations where provider = 'pipedrive';\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 = 19 and sa.provider = 'pipedrive';\n\nSELECT * FROM social_accounts WHERE id = 1116;\n\nUPDATE social_accounts SET provider_user_token = 'v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA',\nprovider_refresh_token = '5034113:19555731:87c14258f0c813d02767ee975f6044d46b6b2bfc',\nexpires = 1779091997,\nstate = 'connected'\nWHERE id = 1116;\n\n \"provider_user_token\": \"v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA\",\n \"provider_refresh_token\": \"5034113:19555731:87c14258f0c813d02767ee975f6044d46b6b2bfc\",\n \"expires\": 1779091997,","depth":4,"on_screen":true,"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\n\nselect sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id\nwhere u.team_id = 1;\nSELECT * FROM social_accounts WHERE sociable_id = 1635;\nSELECT * FROM users WHERE id = 1635;\n\nselect * from teams where id = 1;\nselect * from users where team_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 activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;\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\nSELECT * FROM automated_reports where id = 71;\nSELECT * FROM automated_report_results where report_id = 71;\nUPDATE automated_reports set playbook_categories = NULL 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 `automated_report_results`.* FROM `automated_report_results`\nINNER JOIN `automated_reports`\n ON `automated_report_results`.`report_id` = `automated_reports`.`id`\nWHERE 1=1\n AND `automated_report_results`.`generated_at` IS NOT NULL\n# AND `automated_report_results`.`sent_at` IS NOT NULL\n AND `automated_reports`.`team_id` = 1\n AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$.\"users\"')\n;\n\nSELECT * FROM automated_reports where id = 67;\nSELECT * FROM automated_reports where id = 42;\nSELECT * FROM users WHERE id = 143; # group 28\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;\n\nselect * from leads;\n\nSELECT * FROM activities WHERE uuid_to_bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid; # 422003\nSELECT * FROM activities WHERE id IN (16,422003);\nSELECT * FROM activities where status = 'failed';\n\nSELECT * FROM tracks WHERE activity_id = 422003;\n\nSELECT\n a.*\nFROM activities a\nJOIN users u ON a.user_id = u.id\nWHERE\n a.status = 'completed'\n AND uuid_to_bin('641f1acb-16b8-42d1-8726-df52979dad0e') = u.uuid\n AND a.deleted_at IS NULL\n AND EXISTS (\n SELECT 1 FROM tracks t\n WHERE t.activity_id = a.id\n AND t.type IN ('audio', 'video')\n )\nORDER BY a.actual_start_time DESC\nLIMIT 25;\n\nselect * from teams where id = 19;\nselect * from crm_configurations where provider = 'pipedrive';\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 = 19 and sa.provider = 'pipedrive';\n\nSELECT * FROM social_accounts WHERE id = 1116;\n\nUPDATE social_accounts SET provider_user_token = 'v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA',\nprovider_refresh_token = '5034113:19555731:87c14258f0c813d02767ee975f6044d46b6b2bfc',\nexpires = 1779091997,\nstate = 'connected'\nWHERE id = 1116;\n\n \"provider_user_token\": \"v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA\",\n \"provider_refresh_token\": \"5034113:19555731:87c14258f0c813d02767ee975f6044d46b6b2bfc\",\n \"expires\": 1779091997,","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"Socket fail to connect to host:address=(host=localhost)(port=3306)(type=primary). Connection refused","depth":3,"bounds":{"left":0.42652926,"top":0.9577015,"width":0.29321808,"height":0.013567438},"on_screen":true,"value":"Socket fail to connect to host:address=(host=localhost)(port=3306)(type=primary). Connection refused","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
8713043229250015872
|
6830303734474610253
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Models\AskAnything;
use Illuminate\Database\Eloquent\Relations;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\Model;
use Jiminny\Models\User;
use Jiminny\Traits\RequiresUUID;
class AskAnythingPrompt extends Model
{
use RequiresUUID;
protected $table = 'ask_anything_prompts';
protected $fillable = [
'title',
'content',
'target',
'owner_id',
];
protected $visible = [
'title',
'content',
'owner_id',
];
protected function casts(): array
{
return [
'title' => 'string',
'content' => 'string',
'target' => AskAnythingPromptTarget::class,
'owner_id' => 'integer',
];
}
public function owner(): Relations\BelongsTo
{
return $this->belongsTo(User::class);
}
public function getOwner(): ?User
{
return $this->getAttribute('owner');
}
public function userPrompts(): Relations\HasMany
{
return $this->hasMany(UserAskAnythingPrompt::class, 'prompt_id');
}
public function automatedReports(): Relations\HasMany
{
return $this->hasMany(AutomatedReport::class, 'ask_anything_prompt_id');
}
public function getUuid(): string
{
return $this->getAttribute('id_string');
}
public function getId(): int
{
return $this->getAttribute('id');
}
public function getOwnerId(): ?int
{
return $this->getAttribute('owner_id');
}
public function getTarget(): AskAnythingPromptTarget
{
return $this->getAttribute('target');
}
/**
* Prompt is considered default when it has no owner
*
* @return bool
*/
public function isDefaultPrompt(): bool
{
return $this->getOwnerId() === null;
}
public function getTitle(): string
{
return $this->getAttribute('title');
}
public function getContent(): string
{
return $this->getAttribute('content');
}
public function getHasReports(): bool
{
if (array_key_exists('automated_reports_count', $this->getAttributes())) {
return ((int) $this->getAttribute('automated_reports_count')) > 0;
}
return $this->automatedReports()->exists();
}
}
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
21
1
18
2
6
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 sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id
where u.team_id = 1;
SELECT * FROM social_accounts WHERE sociable_id = 1635;
SELECT * FROM users WHERE id = 1635;
select * from teams where id = 1;
select * from users where team_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 activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;
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 automated_reports where id = 71;
SELECT * FROM automated_report_results where report_id = 71;
UPDATE automated_reports set playbook_categories = NULL 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 `automated_report_results`.* FROM `automated_report_results`
INNER JOIN `automated_reports`
ON `automated_report_results`.`report_id` = `automated_reports`.`id`
WHERE 1=1
AND `automated_report_results`.`generated_at` IS NOT NULL
# AND `automated_report_results`.`sent_at` IS NOT NULL
AND `automated_reports`.`team_id` = 1
AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$."users"')
;
SELECT * FROM automated_reports where id = 67;
SELECT * FROM automated_reports where id = 42;
SELECT * FROM users WHERE id = 143; # group 28
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;
select * from leads;
SELECT * FROM activities WHERE uuid_to_bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid; # 422003
SELECT * FROM activities WHERE id IN (16,422003);
SELECT * FROM activities where status = 'failed';
SELECT * FROM tracks WHERE activity_id = 422003;
SELECT
a.*
FROM activities a
JOIN users u ON a.user_id = u.id
WHERE
a.status = 'completed'
AND uuid_to_bin('641f1acb-16b8-42d1-8726-df52979dad0e') = u.uuid
AND a.deleted_at IS NULL
AND EXISTS (
SELECT 1 FROM tracks t
WHERE t.activity_id = a.id
AND t.type IN ('audio', 'video')
)
ORDER BY a.actual_start_time DESC
LIMIT 25;
select * from teams where id = 19;
select * from crm_configurations where provider = 'pipedrive';
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 = 19 and sa.provider = 'pipedrive';
SELECT * FROM social_accounts WHERE id = 1116;
UPDATE social_accounts SET provider_user_token = 'v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA',
provider_refresh_token = '5034113:[TELEGRAM_TOKEN]b2bfc',
expires = 1779091997,
state = 'connected'
WHERE id = 1116;
"provider_user_token": "v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA",
"provider_refresh_token": "5034113:[TELEGRAM_TOKEN]b2bfc",
"expires": 1779091997,
Socket fail to connect to host:address=(host=localhost)(port=3306)(type=primary). Connection refused
Project
Project
New File or Directory…
Expand Selected...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57893
|
2037
|
26
|
2026-05-19T11:14:29.365528+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189269365_m2.jpg...
|
PhpStorm
|
faVsco.js – AskAnythingPrompt.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormViewINavicarecodeFV faVsco.js°9 JY-20676-d PhostormViewINavicarecodeFV faVsco.js°9 JY-20676-delete-report-related-objProiect vTeamRetentionPolicyFeatureTest.php0 ThemeTopicUpdateFeatureTest.phpUserOnboardFeatureTest.phpCa Integration0) Services© AskAnythingPromptService.php© AutomatedReportsServiceTest.phpC AsKJiminnyкep1gPromptServiceTest.php X © Search.php?DStuosv M UnitActions• Component> Actionltemsclass ASKAnyth1ngPromptServ1celest extends Testcasepublic function testGetAskAnythingPrompts(): void->W1LLReturnSuser)^Activitv• ActivitvAnalvticsM ActivitvSearchMAlActivitviivneM AiAutomationD AiCallScoring• DJ AskAnything©) AskAnythingPromptServiceTest.php© HistoryServiceTest.php)M Ack liminnyAil>C BillingManagementC7 CoachingFeedback>C Country07 CustomerApiC7 DatadodC7 DateTime>C DealinsightsM DealRisksZasticsearch→ EncodingEncrvotionDESFeatureFlaas0 FFMpeg• KevPointsD Kioskm LanquageDetectionMediaPipelineM MeetinaBotMobileSettingsm NotificationNudge> @ ParagraphBreakerM DarticinantSneochM DartitionodCookieC7 PlaybackPageC) PlaylistCa ProphetM DrankotA;•MSCIMyMMutotord$promptuwnedbyUser->expects(sthis->once))->method con.'uuid-1st-prompt'):SoromotOwnedBvUser->exoects(Sthis->onceO)lSoromotOwnedBvUser->expects(Sthis->onceO)l->wnll Returnd valt"Test nromnti):Snromnt0wnedRvllsen->exnectc/Sthis->onceonl->method constraintSnromn+0wnedRvllsen->eynects/Sthis->onceonl->method constraintaetiwnenTd')->willReturn( value: 1)$prompt0wnedByUser->expects(Sthis->onceO)->method( constraint:'getHasReports')$defaultPromptOrderedByUser = Sthis->createMock( oricaccName• AckAnvthinaDnomnt..rlacc).$defaultPromptOrderedByUser->expects(Sthis->onceO)->method constraint'getOwner')->willReturn( value: null)SdefaultPromptOrderedByUser-›expects (Sthis-›once)->willReturnc value$defaultPromotOrderedBvUser->expects(Sthis->once()207208209->methodc constraint211$defaultPrompt0rderedBvUser->expects(Sthis->once())213)"What was the overall sentiment of the customen during the call?!):215$defaultPromptOrderedByUser->expects($this->once())216"aetHasRenonts')-›willReturn( value: false);217$prompt0wnedByUserAndSharedWithGroup = $this->createMock( originalClassNanAskAnythingPrompt: :clas219$promptOwnedByUserAndSharedWithGroup->expects($this->exactly( count: 2))220'getOwner')Snnomn+0wnedRvllcor/ndShanodWithGnoun-soynentc/ethic.soncor))'getUuid')-swillPotunn( value• tuuid-Ond-nnomntt)•Snnomn+0wnedRvllconAndShanodW4thGnoun-sovnontc/ethic.soncor)11%mlowewattsud11 DotunnX Repet Filg oжa+ 4 of 7 files →=custom.log= laravel.log4 SF jiminny@localhost] x4 HS_local [jiminny@localhost]A console [STAGING]C) CoachinaFeedhackCoachl.Icerin.nhnPlavaroundselect * from activities where 1d = 422003• # 00U04000000B6FMACISELECT ar.id, ar.uuid, ar.media type, ar.status, a.typeSp0M automated nenont neculte anJOIN automated_reports a ON a.id = ar.report idWHERE a.type = 'ask jiminny'LIMIT 10:188 0190SELECT * FROM automated_reports where id = 71:SELECT * FROM automated report results where report id = 71:UPDATE automated reports set playbook categories = NULL where id = 68:SELECT * FROM automated report_ results where id = 275192193194195)SELECT * FROM automated reports order by id desc›SELECT * FROMautomated_reportresults order by 1d desc:select * from activity_searches where user_id = 143;1196SELECTautomated renort results * FRiM 'automated remort resultsiINNER JOIN 'automated renortsiautomated renort results' "renort id' = 'automated renorts' 'idiautomated renort results' 'aenerated at' IS NOT NuLIautomated renort results' 'sent at' IS NOT NULIautomated nenonts' "toam id' = 1AND ISON CONTATNS('automated nenonte' "neciniente'. 147 Id lucengll)SELECT * EPOM automated nenonte whene id = 47-SELECT * FROM automated_reports where id = 42;SELECT * FROM users WHERE id = 143; # group 28select * from crm_confiqurations where id = 500:select * from users where name = 'Integration Account': # 1695SELECT * FROMsocial accounts WHERE sociable_ id = 1695:select * from activities where crm_ configuration_ id = 39and recording state = 'recorded' and duration > 60and status = 'completed' and actual start time >= 12025-12-01'•SELECT * FROM activities WHERE uuid to bin(•458cf915-6914-4000-b083-568763262956') = uuidiselect * from leads:SELECT * FROM activities WHERE uuid to bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid: # 422003SELECT * FROM activities WHERE id IN (16,422003):Socket fail to connect to host:address=(host=localhost) (port=3306)(tvpe=primarv). Connection refusedhell"supoont Dally • In 40 m100% 5• Tue 19 May 14:14:29AskAnythingPromptServiceTest v& console [PROD]# console [euyCascadeAsk Jiminny Report M+0 ..So jiminny vm 021 A1 A18 V2 Y6 ^• AutomatedReportsServiceTest.php+13 -17Review Items AddressedCritical — N41 Queries (fixed)Saved searches - ActivityController.php:1100 now eager-loads via ->withCount ('automatedReports') , and SearchTransformer.oho: 48 reads from automated reports countPrompts - moved loadCount ('automatedReports') into AskAnythingRepository.php:94-100 (single batched countquery for the wholelist). The AskAnythingPrompt: :getHasReports() accessor now prefers automated_reports_countwhen present and Talls back to existso otherwise preserves correctness in other call sies and tests).Mocerate - Business locic moved to serviceAutomatedReportsService.php:1240-1252 now contains the guard and throws InvalidArgumentException . The controllerAsk.iminnvReportsController.pho: 126-166) is back to a thin try/catch with an added InvalidArgumentExcention → 422handler (matches the pattern already used in createAskJiminnyReport and updateAskJiminnyReport).Moderate — lests added• testUpdateAskJiminnvReportStatusthrowswhenEnablingWithMissingReferences — verifies the new validationithrows and update() is never called.• testlndateAskliminnvRenortStatusDoesNotValGidatelhenDisablUing — verifies disabling bvnasses the validationdid not add controller tests per vour "no unit tests for controllers" rule: the service- leve coverage exercises the sameloaic.Miinor — created rerurnS has reports: falseAskAnvthinaPromntService.ohn: 106 now nasses talse exolicitlv. Undated testCreateAskAnvthingPromotwithTwollsers to matchMinor — onBeforedelete onlvon on demandlNot changed in this round - flagged for confirmation. Currently only on_demand prompts can be wired to Ask Jiminnyreports the getAsk.iminnvReportFilters service exolicitly fetches AskAnvthingPromotTarget::on demand ). so thefrontend guard is correctly scoped. Worth a code comment, but no behavioral change needed.ann/Httn/Trancformerc/M SoarchTrancformer.nhnllers/API/ ActivityController.php +1 -1aoo/Models/AskAnvthina/m AskAnvthinaPromot.ohv +4/1. AskAnvthingPromotServiceTest.php+25-2ts/ AutomatedReportsServiceTest.php +47app/Component/AskAnything/@ AskAnythingPromptService.php +7-2Ask anvthina 884-L)<> Code Claude Qnus 4.7 MediumReiect alllAccent alliWN Windsurf Toams 66-1UTF.8Po 4 spaces...
|
NULL
|
-6300060790767213429
|
NULL
|
click
|
ocr
|
NULL
|
PhostormViewINavicarecodeFV faVsco.js°9 JY-20676-d PhostormViewINavicarecodeFV faVsco.js°9 JY-20676-delete-report-related-objProiect vTeamRetentionPolicyFeatureTest.php0 ThemeTopicUpdateFeatureTest.phpUserOnboardFeatureTest.phpCa Integration0) Services© AskAnythingPromptService.php© AutomatedReportsServiceTest.phpC AsKJiminnyкep1gPromptServiceTest.php X © Search.php?DStuosv M UnitActions• Component> Actionltemsclass ASKAnyth1ngPromptServ1celest extends Testcasepublic function testGetAskAnythingPrompts(): void->W1LLReturnSuser)^Activitv• ActivitvAnalvticsM ActivitvSearchMAlActivitviivneM AiAutomationD AiCallScoring• DJ AskAnything©) AskAnythingPromptServiceTest.php© HistoryServiceTest.php)M Ack liminnyAil>C BillingManagementC7 CoachingFeedback>C Country07 CustomerApiC7 DatadodC7 DateTime>C DealinsightsM DealRisksZasticsearch→ EncodingEncrvotionDESFeatureFlaas0 FFMpeg• KevPointsD Kioskm LanquageDetectionMediaPipelineM MeetinaBotMobileSettingsm NotificationNudge> @ ParagraphBreakerM DarticinantSneochM DartitionodCookieC7 PlaybackPageC) PlaylistCa ProphetM DrankotA;•MSCIMyMMutotord$promptuwnedbyUser->expects(sthis->once))->method con.'uuid-1st-prompt'):SoromotOwnedBvUser->exoects(Sthis->onceO)lSoromotOwnedBvUser->expects(Sthis->onceO)l->wnll Returnd valt"Test nromnti):Snromnt0wnedRvllsen->exnectc/Sthis->onceonl->method constraintSnromn+0wnedRvllsen->eynects/Sthis->onceonl->method constraintaetiwnenTd')->willReturn( value: 1)$prompt0wnedByUser->expects(Sthis->onceO)->method( constraint:'getHasReports')$defaultPromptOrderedByUser = Sthis->createMock( oricaccName• AckAnvthinaDnomnt..rlacc).$defaultPromptOrderedByUser->expects(Sthis->onceO)->method constraint'getOwner')->willReturn( value: null)SdefaultPromptOrderedByUser-›expects (Sthis-›once)->willReturnc value$defaultPromotOrderedBvUser->expects(Sthis->once()207208209->methodc constraint211$defaultPrompt0rderedBvUser->expects(Sthis->once())213)"What was the overall sentiment of the customen during the call?!):215$defaultPromptOrderedByUser->expects($this->once())216"aetHasRenonts')-›willReturn( value: false);217$prompt0wnedByUserAndSharedWithGroup = $this->createMock( originalClassNanAskAnythingPrompt: :clas219$promptOwnedByUserAndSharedWithGroup->expects($this->exactly( count: 2))220'getOwner')Snnomn+0wnedRvllcor/ndShanodWithGnoun-soynentc/ethic.soncor))'getUuid')-swillPotunn( value• tuuid-Ond-nnomntt)•Snnomn+0wnedRvllconAndShanodW4thGnoun-sovnontc/ethic.soncor)11%mlowewattsud11 DotunnX Repet Filg oжa+ 4 of 7 files →=custom.log= laravel.log4 SF jiminny@localhost] x4 HS_local [jiminny@localhost]A console [STAGING]C) CoachinaFeedhackCoachl.Icerin.nhnPlavaroundselect * from activities where 1d = 422003• # 00U04000000B6FMACISELECT ar.id, ar.uuid, ar.media type, ar.status, a.typeSp0M automated nenont neculte anJOIN automated_reports a ON a.id = ar.report idWHERE a.type = 'ask jiminny'LIMIT 10:188 0190SELECT * FROM automated_reports where id = 71:SELECT * FROM automated report results where report id = 71:UPDATE automated reports set playbook categories = NULL where id = 68:SELECT * FROM automated report_ results where id = 275192193194195)SELECT * FROM automated reports order by id desc›SELECT * FROMautomated_reportresults order by 1d desc:select * from activity_searches where user_id = 143;1196SELECTautomated renort results * FRiM 'automated remort resultsiINNER JOIN 'automated renortsiautomated renort results' "renort id' = 'automated renorts' 'idiautomated renort results' 'aenerated at' IS NOT NuLIautomated renort results' 'sent at' IS NOT NULIautomated nenonts' "toam id' = 1AND ISON CONTATNS('automated nenonte' "neciniente'. 147 Id lucengll)SELECT * EPOM automated nenonte whene id = 47-SELECT * FROM automated_reports where id = 42;SELECT * FROM users WHERE id = 143; # group 28select * from crm_confiqurations where id = 500:select * from users where name = 'Integration Account': # 1695SELECT * FROMsocial accounts WHERE sociable_ id = 1695:select * from activities where crm_ configuration_ id = 39and recording state = 'recorded' and duration > 60and status = 'completed' and actual start time >= 12025-12-01'•SELECT * FROM activities WHERE uuid to bin(•458cf915-6914-4000-b083-568763262956') = uuidiselect * from leads:SELECT * FROM activities WHERE uuid to bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid: # 422003SELECT * FROM activities WHERE id IN (16,422003):Socket fail to connect to host:address=(host=localhost) (port=3306)(tvpe=primarv). Connection refusedhell"supoont Dally • In 40 m100% 5• Tue 19 May 14:14:29AskAnythingPromptServiceTest v& console [PROD]# console [euyCascadeAsk Jiminny Report M+0 ..So jiminny vm 021 A1 A18 V2 Y6 ^• AutomatedReportsServiceTest.php+13 -17Review Items AddressedCritical — N41 Queries (fixed)Saved searches - ActivityController.php:1100 now eager-loads via ->withCount ('automatedReports') , and SearchTransformer.oho: 48 reads from automated reports countPrompts - moved loadCount ('automatedReports') into AskAnythingRepository.php:94-100 (single batched countquery for the wholelist). The AskAnythingPrompt: :getHasReports() accessor now prefers automated_reports_countwhen present and Talls back to existso otherwise preserves correctness in other call sies and tests).Mocerate - Business locic moved to serviceAutomatedReportsService.php:1240-1252 now contains the guard and throws InvalidArgumentException . The controllerAsk.iminnvReportsController.pho: 126-166) is back to a thin try/catch with an added InvalidArgumentExcention → 422handler (matches the pattern already used in createAskJiminnyReport and updateAskJiminnyReport).Moderate — lests added• testUpdateAskJiminnvReportStatusthrowswhenEnablingWithMissingReferences — verifies the new validationithrows and update() is never called.• testlndateAskliminnvRenortStatusDoesNotValGidatelhenDisablUing — verifies disabling bvnasses the validationdid not add controller tests per vour "no unit tests for controllers" rule: the service- leve coverage exercises the sameloaic.Miinor — created rerurnS has reports: falseAskAnvthinaPromntService.ohn: 106 now nasses talse exolicitlv. Undated testCreateAskAnvthingPromotwithTwollsers to matchMinor — onBeforedelete onlvon on demandlNot changed in this round - flagged for confirmation. Currently only on_demand prompts can be wired to Ask Jiminnyreports the getAsk.iminnvReportFilters service exolicitly fetches AskAnvthingPromotTarget::on demand ). so thefrontend guard is correctly scoped. Worth a code comment, but no behavioral change needed.ann/Httn/Trancformerc/M SoarchTrancformer.nhnllers/API/ ActivityController.php +1 -1aoo/Models/AskAnvthina/m AskAnvthinaPromot.ohv +4/1. AskAnvthingPromotServiceTest.php+25-2ts/ AutomatedReportsServiceTest.php +47app/Component/AskAnything/@ AskAnythingPromptService.php +7-2Ask anvthina 884-L)<> Code Claude Qnus 4.7 MediumReiect alllAccent alliWN Windsurf Toams 66-1UTF.8Po 4 spaces...
|
57891
|
NULL
|
NULL
|
NULL
|
|
57892
|
2036
|
18
|
2026-05-19T11:14:29.365498+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189269365_m1.jpg...
|
PhpStorm
|
faVsco.js – AskAnythingPrompt.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 46 m100% C7Tue 19 May 14:14:28ED→Describe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
3188569292788766550
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 46 m100% C7Tue 19 May 14:14:28ED→Describe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
57889
|
NULL
|
NULL
|
NULL
|
|
57891
|
2037
|
25
|
2026-05-19T11:14:28.128505+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189268128_m2.jpg...
|
PhpStorm
|
faVsco.js – AskAnythingPromptServiceTest.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
6
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Component\AskAnything;
use Illuminate\Database\Eloquent\Collection;
use Jiminny\Component\AskAnything\AskAnythingPromptService;
use Jiminny\Component\AskAnything\Dtos\AskAnythingPromptDto;
use Jiminny\Contracts\Repositories\GroupRepositoryInterface;
use Jiminny\Models\AskAnything\AskAnythingPrompt;
use Jiminny\Models\AskAnything\AskAnythingPromptTarget;
use Jiminny\Models\AskAnything\UserAskAnythingPrompt;
use Jiminny\Models\Group;
use Jiminny\Models\User;
use Jiminny\Repositories\AskAnythingRepository;
use Jiminny\Repositories\UserRepository;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
use Tests\Unit\Traits\TestPrivateMethod;
class AskAnythingPromptServiceTest extends TestCase
{
use TestPrivateMethod;
private AskAnythingPromptService $askAnythingPromptService;
private AskAnythingRepository&MockObject $askAnythingRepository;
private UserRepository&MockObject $userRepository;
private GroupRepositoryInterface&MockObject $groupRepository;
protected function setUp(): void
{
$this->askAnythingRepository = $this->createMock(AskAnythingRepository::class);
$this->userRepository = $this->createMock(UserRepository::class);
$this->groupRepository = $this->createMock(GroupRepositoryInterface::class);
$this->askAnythingPromptService = new AskAnythingPromptService(
$this->askAnythingRepository,
$this->userRepository,
$this->groupRepository
);
}
public function testGetAskAnythingPrompts(): void
{
$user = $this->createMock(User::class);
$user->expects($this->any())
->method('getId')
->willReturn(1);
$user->expects($this->any())
->method('getUuid')
->willReturn('1');
$defaultPrompt = $this->createMock(AskAnythingPrompt::class);
$defaultPrompt->expects($this->once())
->method('getOwner')
->willReturn(null);
$defaultPrompt->expects($this->once())
->method('getUuid')
->willReturn('default-uuid');
$defaultPrompt->expects($this->once())
->method('getTitle')
->willReturn('Sentiment');
$defaultPrompt->expects($this->once())
->method('getContent')
->willReturn('What was the overall sentiment of the customer during the call?');
$defaultPrompt->expects($this->once())
->method('getHasReports')
->willReturn(false);
$promptOwnedByUser = $this->createMock(AskAnythingPrompt::class);
$promptOwnedByUser->expects($this->exactly(2))
->method('getOwner')
->willReturn($user);
$promptOwnedByUser->expects($this->once())
->method('getUuid')
->willReturn('uuid-1st-prompt');
$promptOwnedByUser->expects($this->once())
->method('getTitle')
->willReturn('First users prompt');
$promptOwnedByUser->expects($this->once())
->method('getContent')
->willReturn('Test prompt');
$promptOwnedByUser->expects($this->once())
->method('getId')
->willReturn(99);
$promptOwnedByUser->expects($this->once())
->method('getOwnerId')
->willReturn(1);
$promptOwnedByUser->expects($this->once())
->method('getHasReports')
->willReturn(true);
$defaultPromptOrderedByUser = $this->createMock(AskAnythingPrompt::class);
$defaultPromptOrderedByUser->expects($this->once())
->method('getOwner')
->willReturn(null);
$defaultPromptOrderedByUser->expects($this->once())
->method('getUuid')
->willReturn('default-uuid');
$defaultPromptOrderedByUser->expects($this->once())
->method('getTitle')
->willReturn('Sentiment');
$defaultPromptOrderedByUser->expects($this->once())
->method('getContent')
->willReturn('What was the overall sentiment of the customer during the call?');
$defaultPromptOrderedByUser->expects($this->once())
->method('getHasReports')
->willReturn(false);
$promptOwnedByUserAndSharedWithGroup = $this->createMock(AskAnythingPrompt::class);
$promptOwnedByUserAndSharedWithGroup->expects($this->exactly(2))
->method('getOwner')
->willReturn($user);
$promptOwnedByUserAndSharedWithGroup->expects($this->once())
->method('getUuid')
->willReturn('uuid-2nd-prompt');
$promptOwnedByUserAndSharedWithGroup->expects($this->once())
->method('getTitle')
->willReturn('Prompt shared with group');
$promptOwnedByUserAndSharedWithGroup->expects($this->once())
->method('getContent')
->willReturn('Test prompt that is shared with group');
$promptOwnedByUserAndSharedWithGroup->expects($this->once())
->method('getId')
->willReturn(109);
$promptOwnedByUserAndSharedWithGroup->expects($this->once())
->method('getOwnerId')
->willReturn(1);
$promptOwnedByUserAndSharedWithGroup->expects($this->once())
->method('getHasReports')
->willReturn(false);
$group = $this->createMock(Group::class);
$group->expects($this->once())
->method('getUuid')
->willReturn('uuid-of-the-group');
$sharedWithGroup = $this->createMock(UserAskAnythingPrompt::class);
$sharedWithGroup->expects($this->once())
->method('getUser')
->willReturn(null);
$sharedWithGroup->expects($this->once())
->method('getGroup')
->willReturn($group);
$this->askAnythingRepository->expects($this->exactly(2))
->method('findSharedUsersAndGroupsByPromptId')
->willReturnMap([
[99, new Collection([])],
[109, new Collection([$sharedWithGroup])],
]);
$prompts = [$defaultPrompt, $promptOwnedByUser, $defaultPromptOrderedByUser, $promptOwnedByUserAndSharedWithGroup];
$this->askAnythingRepository->expects($this->once())
->method('findPromptsByUserAndTarget')
->willReturn(new Collection($prompts));
$expectedDto1 = new AskAnythingPromptDto(
'default-uuid',
'Sentiment',
'What was the overall sentiment of the customer during the call?',
AskAnythingPromptTarget::call,
null,
null,
null,
false,
);
$expectedDto2 = new AskAnythingPromptDto(
'uuid-1st-prompt',
'First users prompt',
'Test prompt',
AskAnythingPromptTarget::call,
'1',
[],
[],
true,
);
$expectedDto3 = new AskAnythingPromptDto(
'default-uuid',
'Sentiment',
'What was the overall sentiment of the customer during the call?',
AskAnythingPromptTarget::call,
null,
null,
null,
false,
);
$expectedDto4 = new AskAnythingPromptDto(
'uuid-2nd-prompt',
'Prompt shared with group',
'Test prompt that is shared with group',
AskAnythingPromptTarget::call,
'1',
[],
['uuid-of-the-group'],
false,
);
$dtos = $this->askAnythingPromptService->get($user, AskAnythingPromptTarget::call);
$this->assertEquals([$expectedDto1, $expectedDto2, $expectedDto3, $expectedDto4], $dtos);
}
public function testEditAskAnythingPrompt(): void
{
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('isDefaultPrompt')
->willReturn(false);
$prompt->expects($this->once())
->method('getOwnerId')
->willReturn(123);
$prompt->expects($this->never())
->method('getTarget')
->willReturn(AskAnythingPromptTarget::call);
$user = $this->createMock(User::class);
$user->expects($this->once())
->method('getId')
->willReturn(123);
$user->expects($this->once())
->method('getUuid')
->willReturn('owner-uuid');
$title = 'new title';
$content = 'new content';
$shareUsers = ['us-1'];
$shareGroups = ['gr-1', 'gr-2'];
$shareUser = $this->createMock(User::class);
$this->userRepository->expects($this->once())
->method('findByUuid')
->with('us-1')
->willReturn($shareUser);
$shareGroup1 = $this->createMock(Group::class);
$shareGroup2 = $this->createMock(Group::class);
$this->groupRepository->expects($this->exactly(2))
->method('findByUuid')
->willReturnMap([
['gr-1', $shareGroup1],
['gr-2', $shareGroup2],
]);
$editPrompt = $this->createMock(AskAnythingPrompt::class);
$editPrompt->expects($this->once())
->method('getTitle')
->willReturn($title);
$editPrompt->expects($this->once())
->method('getContent')
->willReturn($content);
$editPrompt->expects($this->once())
->method('getTarget')
->willReturn(AskAnythingPromptTarget::call);
$editPrompt->expects($this->once())
->method('getUuid')
->willReturn('uuid-1st-prompt');
$this->askAnythingRepository->expects($this->once())
->method('editPrompt')
->with($prompt, $title, $content, [$shareUser], [$shareGroup1, $shareGroup2])
->willReturn($editPrompt);
$expectedDto = new AskAnythingPromptDto(
'uuid-1st-prompt',
$title,
$content,
AskAnythingPromptTarget::call,
'owner-uuid',
$shareUsers,
$shareGroups
);
$editDto = $this->askAnythingPromptService->edit($prompt, $user, $title, $content, $shareUsers, $shareGroups);
$this->assertEquals($expectedDto, $editDto);
}
public function testHideDefaultAndCreateAskAnythingPrompt(): void
{
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('isDefaultPrompt')
->willReturn(true);
$prompt->expects($this->once())
->method('getTarget')
->willReturn(AskAnythingPromptTarget::call);
$user = $this->createMock(User::class);
$user->expects($this->once())
->method('getUuid')
->willReturn('new-owner-uuid');
$title = 'title';
$content = 'content';
$shareUsers = ['us-1'];
$shareGroups = [];
$shareUser = $this->createMock(User::class);
$this->userRepository->expects($this->once())
->method('findByUuid')
->with('us-1')
->willReturn($shareUser);
$this->groupRepository->expects($this->never())
->method('findByUuid');
$newPrompt = $this->createMock(AskAnythingPrompt::class);
$newPrompt->expects($this->once())
->method('getTarget')
->willReturn(AskAnythingPromptTarget::call);
$newPrompt->expects($this->once())
->method('getUuid')
->willReturn('uuid-1st-prompt');
$newPrompt->expects($this->once())
->method('getTitle')
->willReturn($title);
$newPrompt->expects($this->once())
->method('getContent')
->willReturn($content);
$this->askAnythingRepository->expects($this->once())
->method('hidePromptForUser');
$this->askAnythingRepository->expects($this->once())
->method('createPrompt')
->willReturn($newPrompt);
$expectedDto = new AskAnythingPromptDto(
'uuid-1st-prompt',
$title,
$content,
AskAnythingPromptTarget::call,
'new-owner-uuid',
$shareUsers,
$shareGroups
);
$actualDto = $this->askAnythingPromptService->edit($prompt, $user, $title, $content, $shareUsers, $shareGroups);
$this->assertEquals($expectedDto, $actualDto);
}
public function testDeleteAskAnythingPrompt(): void
{
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('isDefaultPrompt')
->willReturn(false);
$prompt->expects($this->any())
->method('getId')
->willReturn(1);
$prompt->expects($this->once())
->method('getOwnerId')
->willReturn(1);
// Use Mockery for the relationship mock (more flexible)
$relationMock = \Mockery::mock(\Illuminate\Database\Eloquent\Relations\HasMany::class);
$relationMock->shouldReceive('withTrashed')
->once()
->andReturnSelf();
$relationMock->shouldReceive('update')
->once()
->with(['ask_anything_prompt_id' => null, 'status' => false]);
$prompt->expects($this->once())
->method('automatedReports')
->willReturn($relationMock);
$user = $this->createMock(User::class);
$user->expects($this->once())
->method('getId')
->willReturn(1);
$userPrompt = $this->createMock(UserAskAnythingPrompt::class);
$this->askAnythingRepository->expects($this->once())
->method('findSharedPromptByUser')
->with(1, $user)
->willReturn($userPrompt);
$userPrompt->expects($this->once())
->method('delete');
$this->askAnythingRepository->expects($this->any())
->method('findSharedUsersAndGroupsByPromptId')
->with(1)
->willReturn(new Collection([]));
$this->askAnythingRepository->expects($this->once())
->method('deletePrompt');
$this->askAnythingPromptService->delete($prompt, $user);
}
public function testDeleteAskAnythingPromptWithRelations(): void
{
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('isDefaultPrompt')
->willReturn(false);
$prompt->expects($this->any())
->method('getId')
->willReturn(1);
$prompt->expects($this->once())
->method('getOwnerId')
->willReturn(1);
$user = $this->createMock(User::class);
$user->expects($this->any())
->method('getId')
->willReturn(1);
$userPrompt = $this->createMock(UserAskAnythingPrompt::class);
$this->askAnythingRepository->expects($this->once())
->method('findSharedPromptByUser')
->with(1, $user)
->willReturn($userPrompt);
$userPrompt->expects($this->once())
->method('delete');
$this->askAnythingRepository->expects($this->exactly(3))
->method('findSharedUsersAndGroupsByPromptId')
->willReturnMap([
[1, new Collection([$userPrompt])],
[1, new Collection([])],
]);
$this->askAnythingRepository->expects($this->never())
->method('deletePrompt');
$this->askAnythingPromptService->delete($prompt, $user);
}
public function testHideDefaultAskAnythingPrompt(): void
{
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('isDefaultPrompt')
->willReturn(true);
$user = $this->createMock(User::class);
$this->askAnythingRepository->expects($this->once())
->method('hidePromptForUser');
$this->askAnythingPromptService->delete($prompt, $user);
}
public function testHideSharedWithUserAskAnythingPrompt(): void
{
$userPrompt = $this->createMock(UserAskAnythingPrompt::class);
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('isDefaultPrompt')
->willReturn(false);
$prompt->expects($this->once())
->method('getOwnerId')
->willReturn(1);
$prompt->expects($this->exactly(3))
->method('getId')
->willReturn(33);
$relationMock = \Mockery::mock(\Illuminate\Database\Eloquent\Relations\HasMany::class);
$relationMock->shouldReceive('withTrashed')
->once()
->andReturnSelf();
$relationMock->shouldReceive('update')
->once()
->with(['ask_anything_prompt_id' => null, 'status' => false]);
$prompt->expects($this->once())
->method('automatedReports')
->willReturn($relationMock);
$user = $this->createMock(User::class);
$user->expects($this->once())
->method('getId')
->willReturn(2);
$this->askAnythingRepository->expects($this->once())
->method('findSharedPromptByUser')
->with(33, $user)
->willReturn($userPrompt);
$this->askAnythingRepository->expects($this->once())
->method('findSharedPromptByUserGroup')
->with(33, $user)
->willReturn(null);
$userPrompt->expects($this->once())
->method('delete');
$this->askAnythingRepository->expects($this->once())
->method('findSharedUsersAndGroupsByPromptId')
->with(33)
->willReturn(new Collection([]));
$this->askAnythingPromptService->delete($prompt, $user);
}
public function testHideSharedWithUserAndGroupAskAnythingPrompt(): void
{
$userPrompt = $this->createMock(UserAskAnythingPrompt::class);
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('isDefaultPrompt')
->willReturn(false);
$prompt->expects($this->once())
->method('getOwnerId')
->willReturn(1);
$prompt->expects($this->exactly(2))
->method('getId')
->willReturn(33);
$user = $this->createMock(User::class);
$user->expects($this->once())
->method('getId')
->willReturn(2);
$this->askAnythingRepository->expects($this->once())
->method('findSharedPromptByUser')
->with(33, $user)
->willReturn($userPrompt);
$this->askAnythingRepository->expects($this->once())
->method('findSharedPromptByUserGroup')
->with(33, $user)
->willReturn($userPrompt);
$userPrompt->expects($this->never())
->method('delete');
$this->askAnythingRepository->expects($this->once())
->method('hidePromptForUser')
->with($prompt, $user);
$this->askAnythingPromptService->delete($prompt, $user);
}
public function testHideSharedWithGroupAskAnythingPrompt(): void
{
$userPrompt = $this->createMock(UserAskAnythingPrompt::class);
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('isDefaultPrompt')
->willReturn(false);
$prompt->expects($this->once())
->method('getOwnerId')
->willReturn(1);
$prompt->expects($this->exactly(2))
->method('getId')
->willReturn(33);
$user = $this->createMock(User::class);
$user->expects($this->once())
->method('getId')
->willReturn(2);
$this->askAnythingRepository->expects($this->once())
->method('findSharedPromptByUser')
->with(33, $user)
->willReturn(null);
$this->askAnythingRepository->expects($this->once())
->method('findSharedPromptByUserGroup')
->with(33, $user)
->willReturn($userPrompt);
$userPrompt->expects($this->never())
->method('delete');
$this->askAnythingRepository->expects($this->once())
->method('hidePromptForUser')
->with($prompt, $user);
$this->askAnythingPromptService->delete($prompt, $user);
}
public function testDeleteWithNoSharesAndNotOwner(): void
{
$userPrompt = $this->createMock(UserAskAnythingPrompt::class);
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('isDefaultPrompt')
->willReturn(false);
$prompt->expects($this->once())
->method('getOwnerId')
->willReturn(1);
$prompt->expects($this->exactly(2))
->method('getId')
->willReturn(33);
$user = $this->createMock(User::class);
$user->expects($this->once())
->method('getId')
->willReturn(2);
$this->askAnythingRepository->expects($this->once())
->method('findSharedPromptByUser')
->with(33, $user)
->willReturn(null);
$this->askAnythingRepository->expects($this->once())
->method('findSharedPromptByUserGroup')
->with(33, $user)
->willReturn(null);
$userPrompt->expects($this->never())
->method('delete');
$this->askAnythingRepository->expects($this->never())
->method('hidePromptForUser');
$this->expectException(\InvalidArgumentException::class);
$this->askAnythingPromptService->delete($prompt, $user);
}
public function testReorderAskAnythingPrompts(): void
{
$prompts = ['id1', 'id2', 'id3'];
$prompt1 = $this->createMock(AskAnythingPrompt::class);
$prompt2 = $this->createMock(AskAnythingPrompt::class);
$prompt3 = $this->createMock(AskAnythingPrompt::class);
$user = $this->createMock(User::class);
$this->askAnythingRepository->expects($this->exactly(3))
->method('getPromptByUuid')
->willReturnMap([
['id1', $prompt1],
['id2', $prompt2],
['id3', $prompt3],
]);
$this->askAnythingRepository->expects($this->exactly(3))
->method('orderPromptForUser')
->willReturnMap([
[[$prompt1, $user, 1]],
[[$prompt2, $user, 2]],
[[$prompt3, $user, 3]],
]);
$this->askAnythingPromptService->reorder($user, $prompts);
}
public function testCreateAskAnythingPromptWithTwoUsers(): void
{
$user = $this->createMock(User::class);
$user->expects($this->once())
->method('getUuid')
->willReturn('uuid-of-the-user');
$shareUser1 = $this->createMock(User::class);
$shareUser2 = $this->createMock(User::class);
$title = 'Test title';
$content = 'Test content';
$target = AskAnythingPromptTarget::call;
$shareUsers = ['us-1', 'us-2'];
$shareGroups = [];
$this->userRepository->expects($this->exactly(2))
->method('findByUuid')
->willReturnMap([
['us-1', $shareUser1],
['us-2', $shareUser2],
]);
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('getUuid')
->willReturn('prompt-1-uuid');
$prompt->expects($this->once())
->method('getTitle')
->willReturn($title);
$prompt->expects($this->once())
->method('getContent')
->willReturn($content);
$this->askAnythingRepository->expects($this->once())
->method('createPrompt')
->with(
$user,
$target,
$title,
$content,
[$shareUser1, $shareUser2],
[],
)
->willReturn($prompt);
$expectedPromptDto = new AskAnythingPromptDto(
'prompt-1-uuid',
$title,
$content,
$target,
'uuid-of-the-user',
$shareUsers,
$shareGroups,
false,
);
$actualPromptDto = $this->askAnythingPromptService->create(
$user,
$title,
$content,
$target,
$shareUsers,
$shareGroups
);
$this->assertEquals($expectedPromptDto, $actualPromptDto);
}
public function testRecreatePromptsForUserRelations(): void
{
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('getId')
->willReturn(1);
$prompt->expects($this->once())
->method('getTarget')
->willReturn(AskAnythingPromptTarget::call);
$prompt->expects($this->once())
->method('getTitle')
->willReturn('Test title');
$prompt->expects($this->once())
->method('getContent')
->willReturn('Test content');
$sharedPrompt = $this->createMock(UserAskAnythingPrompt::class);
$sharedUser = $this->createMock(User::class);
$sharedUser->expects($this->once())
->method('isStatusActive')
->willReturn(true);
$sharedUser->expects($this->once())
->method('getId')
->willReturn(1);
$sharedPrompt->expects($this->once())
->method('getUser')
->willReturn($sharedUser);
$sharedPrompt->expects($this->exactly(2))
->method('isRemoved')
->willReturn(false);
$sharedPrompt->expects($this->once())
->method('delete');
$this->askAnythingRepository->expects($this->once())
->method('findSharedUsersAndGroupsByPromptId')
->with(1)
->willReturn(new Collection([$sharedPrompt]));
$this->askAnythingRepository->expects($this->once())
->method('createPrompt');
$data = $this->invokePrivateMethod('recreatePromptsForUserRelations', $this->askAnythingPromptService, [$prompt]);
$this->assertEquals([[1], []], $data);
}
}
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
21
1
18
2
6
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 sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id
where u.team_id = 1;
SELECT * FROM social_accounts WHERE sociable_id = 1635;
SELECT * FROM users WHERE id = 1635;
select * from teams where id = 1;
select * from users where team_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 activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;
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 automated_reports where id = 71;
SELECT * FROM automated_report_results where report_id = 71;
UPDATE automated_reports set playbook_categories = NULL 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 `automated_report_results`.* FROM `automated_report_results`
INNER JOIN `automated_reports`
ON `automated_report_results`.`report_id` = `automated_reports`.`id`
WHERE 1=1
AND `automated_report_results`.`generated_at` IS NOT NULL
# AND `automated_report_results`.`sent_at` IS NOT NULL
AND `automated_reports`.`team_id` = 1
AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$."users"')
;
SELECT * FROM automated_reports where id = 67;
SELECT * FROM automated_reports where id = 42;
SELECT * FROM users WHERE id = 143; # group 28
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;
select * from leads;
SELECT * FROM activities WHERE uuid_to_bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid; # 422003
SELECT * FROM activities WHERE id IN (16,422003);
SELECT * FROM activities where status = 'failed';
SELECT * FROM tracks WHERE activity_id = 422003;
SELECT
a.*
FROM activities a
JOIN users u ON a.user_id = u.id
WHERE
a.status = 'completed'
AND uuid_to_bin('641f1acb-16b8-42d1-8726-df52979dad0e') = u.uuid
AND a.deleted_at IS NULL
AND EXISTS (
SELECT 1 FROM tracks t
WHERE t.activity_id = a.id
AND t.type IN ('audio', 'video')
)
ORDER BY a.actual_start_time DESC
LIMIT 25;
select * from teams where id = 19;
select * from crm_configurations where provider = 'pipedrive';
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 = 19 and sa.provider = 'pipedrive';
SELECT * FROM social_accounts WHERE id = 1116;
UPDATE social_accounts SET provider_user_token = 'v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA',
provider_refresh_token = '5034113:[TELEGRAM_TOKEN]b2bfc',
expires = 1779091997,
state = 'connected'
WHERE id = 1116;
"provider_user_token": "v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA",
"provider_refresh_token": "5034113:[TELEGRAM_TOKEN]b2bfc",
"expires": 1779091997,
Socket fail to connect to host:address=(host=localhost)(port=3306)(type=primary). Connection refused
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},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.098071806,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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.8194814,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskAnythingPromptServiceTest","depth":6,"bounds":{"left":0.83477396,"top":0.019952115,"width":0.080784574,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"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},"on_screen":false,"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\\Component\\AskAnything;\n\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Jiminny\\Component\\AskAnything\\AskAnythingPromptService;\nuse Jiminny\\Component\\AskAnything\\Dtos\\AskAnythingPromptDto;\nuse Jiminny\\Contracts\\Repositories\\GroupRepositoryInterface;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPrompt;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPromptTarget;\nuse Jiminny\\Models\\AskAnything\\UserAskAnythingPrompt;\nuse Jiminny\\Models\\Group;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AskAnythingRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\nuse Tests\\Unit\\Traits\\TestPrivateMethod;\n\nclass AskAnythingPromptServiceTest extends TestCase\n{\n use TestPrivateMethod;\n\n private AskAnythingPromptService $askAnythingPromptService;\n private AskAnythingRepository&MockObject $askAnythingRepository;\n private UserRepository&MockObject $userRepository;\n private GroupRepositoryInterface&MockObject $groupRepository;\n\n protected function setUp(): void\n {\n $this->askAnythingRepository = $this->createMock(AskAnythingRepository::class);\n $this->userRepository = $this->createMock(UserRepository::class);\n $this->groupRepository = $this->createMock(GroupRepositoryInterface::class);\n\n $this->askAnythingPromptService = new AskAnythingPromptService(\n $this->askAnythingRepository,\n $this->userRepository,\n $this->groupRepository\n );\n }\n\n public function testGetAskAnythingPrompts(): void\n {\n $user = $this->createMock(User::class);\n $user->expects($this->any())\n ->method('getId')\n ->willReturn(1);\n $user->expects($this->any())\n ->method('getUuid')\n ->willReturn('1');\n $defaultPrompt = $this->createMock(AskAnythingPrompt::class);\n $defaultPrompt->expects($this->once())\n ->method('getOwner')\n ->willReturn(null);\n $defaultPrompt->expects($this->once())\n ->method('getUuid')\n ->willReturn('default-uuid');\n $defaultPrompt->expects($this->once())\n ->method('getTitle')\n ->willReturn('Sentiment');\n $defaultPrompt->expects($this->once())\n ->method('getContent')\n ->willReturn('What was the overall sentiment of the customer during the call?');\n $defaultPrompt->expects($this->once())\n ->method('getHasReports')\n ->willReturn(false);\n $promptOwnedByUser = $this->createMock(AskAnythingPrompt::class);\n $promptOwnedByUser->expects($this->exactly(2))\n ->method('getOwner')\n ->willReturn($user);\n $promptOwnedByUser->expects($this->once())\n ->method('getUuid')\n ->willReturn('uuid-1st-prompt');\n $promptOwnedByUser->expects($this->once())\n ->method('getTitle')\n ->willReturn('First users prompt');\n $promptOwnedByUser->expects($this->once())\n ->method('getContent')\n ->willReturn('Test prompt');\n $promptOwnedByUser->expects($this->once())\n ->method('getId')\n ->willReturn(99);\n $promptOwnedByUser->expects($this->once())\n ->method('getOwnerId')\n ->willReturn(1);\n $promptOwnedByUser->expects($this->once())\n ->method('getHasReports')\n ->willReturn(true);\n $defaultPromptOrderedByUser = $this->createMock(AskAnythingPrompt::class);\n $defaultPromptOrderedByUser->expects($this->once())\n ->method('getOwner')\n ->willReturn(null);\n $defaultPromptOrderedByUser->expects($this->once())\n ->method('getUuid')\n ->willReturn('default-uuid');\n $defaultPromptOrderedByUser->expects($this->once())\n ->method('getTitle')\n ->willReturn('Sentiment');\n $defaultPromptOrderedByUser->expects($this->once())\n ->method('getContent')\n ->willReturn('What was the overall sentiment of the customer during the call?');\n $defaultPromptOrderedByUser->expects($this->once())\n ->method('getHasReports')\n ->willReturn(false);\n $promptOwnedByUserAndSharedWithGroup = $this->createMock(AskAnythingPrompt::class);\n $promptOwnedByUserAndSharedWithGroup->expects($this->exactly(2))\n ->method('getOwner')\n ->willReturn($user);\n $promptOwnedByUserAndSharedWithGroup->expects($this->once())\n ->method('getUuid')\n ->willReturn('uuid-2nd-prompt');\n $promptOwnedByUserAndSharedWithGroup->expects($this->once())\n ->method('getTitle')\n ->willReturn('Prompt shared with group');\n $promptOwnedByUserAndSharedWithGroup->expects($this->once())\n ->method('getContent')\n ->willReturn('Test prompt that is shared with group');\n $promptOwnedByUserAndSharedWithGroup->expects($this->once())\n ->method('getId')\n ->willReturn(109);\n $promptOwnedByUserAndSharedWithGroup->expects($this->once())\n ->method('getOwnerId')\n ->willReturn(1);\n $promptOwnedByUserAndSharedWithGroup->expects($this->once())\n ->method('getHasReports')\n ->willReturn(false);\n\n $group = $this->createMock(Group::class);\n $group->expects($this->once())\n ->method('getUuid')\n ->willReturn('uuid-of-the-group');\n $sharedWithGroup = $this->createMock(UserAskAnythingPrompt::class);\n $sharedWithGroup->expects($this->once())\n ->method('getUser')\n ->willReturn(null);\n $sharedWithGroup->expects($this->once())\n ->method('getGroup')\n ->willReturn($group);\n\n $this->askAnythingRepository->expects($this->exactly(2))\n ->method('findSharedUsersAndGroupsByPromptId')\n ->willReturnMap([\n [99, new Collection([])],\n [109, new Collection([$sharedWithGroup])],\n ]);\n\n $prompts = [$defaultPrompt, $promptOwnedByUser, $defaultPromptOrderedByUser, $promptOwnedByUserAndSharedWithGroup];\n $this->askAnythingRepository->expects($this->once())\n ->method('findPromptsByUserAndTarget')\n ->willReturn(new Collection($prompts));\n\n $expectedDto1 = new AskAnythingPromptDto(\n 'default-uuid',\n 'Sentiment',\n 'What was the overall sentiment of the customer during the call?',\n AskAnythingPromptTarget::call,\n null,\n null,\n null,\n false,\n );\n $expectedDto2 = new AskAnythingPromptDto(\n 'uuid-1st-prompt',\n 'First users prompt',\n 'Test prompt',\n AskAnythingPromptTarget::call,\n '1',\n [],\n [],\n true,\n );\n $expectedDto3 = new AskAnythingPromptDto(\n 'default-uuid',\n 'Sentiment',\n 'What was the overall sentiment of the customer during the call?',\n AskAnythingPromptTarget::call,\n null,\n null,\n null,\n false,\n );\n $expectedDto4 = new AskAnythingPromptDto(\n 'uuid-2nd-prompt',\n 'Prompt shared with group',\n 'Test prompt that is shared with group',\n AskAnythingPromptTarget::call,\n '1',\n [],\n ['uuid-of-the-group'],\n false,\n );\n $dtos = $this->askAnythingPromptService->get($user, AskAnythingPromptTarget::call);\n\n $this->assertEquals([$expectedDto1, $expectedDto2, $expectedDto3, $expectedDto4], $dtos);\n }\n\n public function testEditAskAnythingPrompt(): void\n {\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('isDefaultPrompt')\n ->willReturn(false);\n $prompt->expects($this->once())\n ->method('getOwnerId')\n ->willReturn(123);\n $prompt->expects($this->never())\n ->method('getTarget')\n ->willReturn(AskAnythingPromptTarget::call);\n $user = $this->createMock(User::class);\n $user->expects($this->once())\n ->method('getId')\n ->willReturn(123);\n $user->expects($this->once())\n ->method('getUuid')\n ->willReturn('owner-uuid');\n\n $title = 'new title';\n $content = 'new content';\n $shareUsers = ['us-1'];\n $shareGroups = ['gr-1', 'gr-2'];\n\n $shareUser = $this->createMock(User::class);\n $this->userRepository->expects($this->once())\n ->method('findByUuid')\n ->with('us-1')\n ->willReturn($shareUser);\n $shareGroup1 = $this->createMock(Group::class);\n $shareGroup2 = $this->createMock(Group::class);\n $this->groupRepository->expects($this->exactly(2))\n ->method('findByUuid')\n ->willReturnMap([\n ['gr-1', $shareGroup1],\n ['gr-2', $shareGroup2],\n ]);\n\n $editPrompt = $this->createMock(AskAnythingPrompt::class);\n $editPrompt->expects($this->once())\n ->method('getTitle')\n ->willReturn($title);\n $editPrompt->expects($this->once())\n ->method('getContent')\n ->willReturn($content);\n $editPrompt->expects($this->once())\n ->method('getTarget')\n ->willReturn(AskAnythingPromptTarget::call);\n $editPrompt->expects($this->once())\n ->method('getUuid')\n ->willReturn('uuid-1st-prompt');\n $this->askAnythingRepository->expects($this->once())\n ->method('editPrompt')\n ->with($prompt, $title, $content, [$shareUser], [$shareGroup1, $shareGroup2])\n ->willReturn($editPrompt);\n\n $expectedDto = new AskAnythingPromptDto(\n 'uuid-1st-prompt',\n $title,\n $content,\n AskAnythingPromptTarget::call,\n 'owner-uuid',\n $shareUsers,\n $shareGroups\n );\n $editDto = $this->askAnythingPromptService->edit($prompt, $user, $title, $content, $shareUsers, $shareGroups);\n\n $this->assertEquals($expectedDto, $editDto);\n }\n\n public function testHideDefaultAndCreateAskAnythingPrompt(): void\n {\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('isDefaultPrompt')\n ->willReturn(true);\n $prompt->expects($this->once())\n ->method('getTarget')\n ->willReturn(AskAnythingPromptTarget::call);\n $user = $this->createMock(User::class);\n $user->expects($this->once())\n ->method('getUuid')\n ->willReturn('new-owner-uuid');\n $title = 'title';\n $content = 'content';\n $shareUsers = ['us-1'];\n $shareGroups = [];\n $shareUser = $this->createMock(User::class);\n $this->userRepository->expects($this->once())\n ->method('findByUuid')\n ->with('us-1')\n ->willReturn($shareUser);\n $this->groupRepository->expects($this->never())\n ->method('findByUuid');\n\n $newPrompt = $this->createMock(AskAnythingPrompt::class);\n $newPrompt->expects($this->once())\n ->method('getTarget')\n ->willReturn(AskAnythingPromptTarget::call);\n $newPrompt->expects($this->once())\n ->method('getUuid')\n ->willReturn('uuid-1st-prompt');\n $newPrompt->expects($this->once())\n ->method('getTitle')\n ->willReturn($title);\n $newPrompt->expects($this->once())\n ->method('getContent')\n ->willReturn($content);\n\n $this->askAnythingRepository->expects($this->once())\n ->method('hidePromptForUser');\n $this->askAnythingRepository->expects($this->once())\n ->method('createPrompt')\n ->willReturn($newPrompt);\n\n $expectedDto = new AskAnythingPromptDto(\n 'uuid-1st-prompt',\n $title,\n $content,\n AskAnythingPromptTarget::call,\n 'new-owner-uuid',\n $shareUsers,\n $shareGroups\n );\n\n $actualDto = $this->askAnythingPromptService->edit($prompt, $user, $title, $content, $shareUsers, $shareGroups);\n\n $this->assertEquals($expectedDto, $actualDto);\n }\n\n public function testDeleteAskAnythingPrompt(): void\n {\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('isDefaultPrompt')\n ->willReturn(false);\n $prompt->expects($this->any())\n ->method('getId')\n ->willReturn(1);\n $prompt->expects($this->once())\n ->method('getOwnerId')\n ->willReturn(1);\n\n // Use Mockery for the relationship mock (more flexible)\n $relationMock = \\Mockery::mock(\\Illuminate\\Database\\Eloquent\\Relations\\HasMany::class);\n $relationMock->shouldReceive('withTrashed')\n ->once()\n ->andReturnSelf();\n $relationMock->shouldReceive('update')\n ->once()\n ->with(['ask_anything_prompt_id' => null, 'status' => false]);\n\n $prompt->expects($this->once())\n ->method('automatedReports')\n ->willReturn($relationMock);\n\n $user = $this->createMock(User::class);\n $user->expects($this->once())\n ->method('getId')\n ->willReturn(1);\n $userPrompt = $this->createMock(UserAskAnythingPrompt::class);\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedPromptByUser')\n ->with(1, $user)\n ->willReturn($userPrompt);\n $userPrompt->expects($this->once())\n ->method('delete');\n $this->askAnythingRepository->expects($this->any())\n ->method('findSharedUsersAndGroupsByPromptId')\n ->with(1)\n ->willReturn(new Collection([]));\n $this->askAnythingRepository->expects($this->once())\n ->method('deletePrompt');\n $this->askAnythingPromptService->delete($prompt, $user);\n }\n\n public function testDeleteAskAnythingPromptWithRelations(): void\n {\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('isDefaultPrompt')\n ->willReturn(false);\n $prompt->expects($this->any())\n ->method('getId')\n ->willReturn(1);\n $prompt->expects($this->once())\n ->method('getOwnerId')\n ->willReturn(1);\n $user = $this->createMock(User::class);\n $user->expects($this->any())\n ->method('getId')\n ->willReturn(1);\n $userPrompt = $this->createMock(UserAskAnythingPrompt::class);\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedPromptByUser')\n ->with(1, $user)\n ->willReturn($userPrompt);\n $userPrompt->expects($this->once())\n ->method('delete');\n $this->askAnythingRepository->expects($this->exactly(3))\n ->method('findSharedUsersAndGroupsByPromptId')\n ->willReturnMap([\n [1, new Collection([$userPrompt])],\n [1, new Collection([])],\n ]);\n $this->askAnythingRepository->expects($this->never())\n ->method('deletePrompt');\n $this->askAnythingPromptService->delete($prompt, $user);\n }\n\n public function testHideDefaultAskAnythingPrompt(): void\n {\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('isDefaultPrompt')\n ->willReturn(true);\n $user = $this->createMock(User::class);\n $this->askAnythingRepository->expects($this->once())\n ->method('hidePromptForUser');\n $this->askAnythingPromptService->delete($prompt, $user);\n }\n\n public function testHideSharedWithUserAskAnythingPrompt(): void\n {\n $userPrompt = $this->createMock(UserAskAnythingPrompt::class);\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('isDefaultPrompt')\n ->willReturn(false);\n $prompt->expects($this->once())\n ->method('getOwnerId')\n ->willReturn(1);\n $prompt->expects($this->exactly(3))\n ->method('getId')\n ->willReturn(33);\n\n $relationMock = \\Mockery::mock(\\Illuminate\\Database\\Eloquent\\Relations\\HasMany::class);\n $relationMock->shouldReceive('withTrashed')\n ->once()\n ->andReturnSelf();\n $relationMock->shouldReceive('update')\n ->once()\n ->with(['ask_anything_prompt_id' => null, 'status' => false]);\n $prompt->expects($this->once())\n ->method('automatedReports')\n ->willReturn($relationMock);\n\n $user = $this->createMock(User::class);\n $user->expects($this->once())\n ->method('getId')\n ->willReturn(2);\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedPromptByUser')\n ->with(33, $user)\n ->willReturn($userPrompt);\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedPromptByUserGroup')\n ->with(33, $user)\n ->willReturn(null);\n $userPrompt->expects($this->once())\n ->method('delete');\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedUsersAndGroupsByPromptId')\n ->with(33)\n ->willReturn(new Collection([]));\n\n $this->askAnythingPromptService->delete($prompt, $user);\n }\n\n public function testHideSharedWithUserAndGroupAskAnythingPrompt(): void\n {\n $userPrompt = $this->createMock(UserAskAnythingPrompt::class);\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('isDefaultPrompt')\n ->willReturn(false);\n $prompt->expects($this->once())\n ->method('getOwnerId')\n ->willReturn(1);\n $prompt->expects($this->exactly(2))\n ->method('getId')\n ->willReturn(33);\n $user = $this->createMock(User::class);\n $user->expects($this->once())\n ->method('getId')\n ->willReturn(2);\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedPromptByUser')\n ->with(33, $user)\n ->willReturn($userPrompt);\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedPromptByUserGroup')\n ->with(33, $user)\n ->willReturn($userPrompt);\n $userPrompt->expects($this->never())\n ->method('delete');\n $this->askAnythingRepository->expects($this->once())\n ->method('hidePromptForUser')\n ->with($prompt, $user);\n\n $this->askAnythingPromptService->delete($prompt, $user);\n }\n\n public function testHideSharedWithGroupAskAnythingPrompt(): void\n {\n $userPrompt = $this->createMock(UserAskAnythingPrompt::class);\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('isDefaultPrompt')\n ->willReturn(false);\n $prompt->expects($this->once())\n ->method('getOwnerId')\n ->willReturn(1);\n $prompt->expects($this->exactly(2))\n ->method('getId')\n ->willReturn(33);\n $user = $this->createMock(User::class);\n $user->expects($this->once())\n ->method('getId')\n ->willReturn(2);\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedPromptByUser')\n ->with(33, $user)\n ->willReturn(null);\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedPromptByUserGroup')\n ->with(33, $user)\n ->willReturn($userPrompt);\n $userPrompt->expects($this->never())\n ->method('delete');\n $this->askAnythingRepository->expects($this->once())\n ->method('hidePromptForUser')\n ->with($prompt, $user);\n\n $this->askAnythingPromptService->delete($prompt, $user);\n }\n\n public function testDeleteWithNoSharesAndNotOwner(): void\n {\n $userPrompt = $this->createMock(UserAskAnythingPrompt::class);\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('isDefaultPrompt')\n ->willReturn(false);\n $prompt->expects($this->once())\n ->method('getOwnerId')\n ->willReturn(1);\n $prompt->expects($this->exactly(2))\n ->method('getId')\n ->willReturn(33);\n $user = $this->createMock(User::class);\n $user->expects($this->once())\n ->method('getId')\n ->willReturn(2);\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedPromptByUser')\n ->with(33, $user)\n ->willReturn(null);\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedPromptByUserGroup')\n ->with(33, $user)\n ->willReturn(null);\n $userPrompt->expects($this->never())\n ->method('delete');\n $this->askAnythingRepository->expects($this->never())\n ->method('hidePromptForUser');\n\n $this->expectException(\\InvalidArgumentException::class);\n\n $this->askAnythingPromptService->delete($prompt, $user);\n }\n\n public function testReorderAskAnythingPrompts(): void\n {\n $prompts = ['id1', 'id2', 'id3'];\n $prompt1 = $this->createMock(AskAnythingPrompt::class);\n $prompt2 = $this->createMock(AskAnythingPrompt::class);\n $prompt3 = $this->createMock(AskAnythingPrompt::class);\n $user = $this->createMock(User::class);\n $this->askAnythingRepository->expects($this->exactly(3))\n ->method('getPromptByUuid')\n ->willReturnMap([\n ['id1', $prompt1],\n ['id2', $prompt2],\n ['id3', $prompt3],\n ]);\n $this->askAnythingRepository->expects($this->exactly(3))\n ->method('orderPromptForUser')\n ->willReturnMap([\n [[$prompt1, $user, 1]],\n [[$prompt2, $user, 2]],\n [[$prompt3, $user, 3]],\n ]);\n $this->askAnythingPromptService->reorder($user, $prompts);\n }\n\n public function testCreateAskAnythingPromptWithTwoUsers(): void\n {\n $user = $this->createMock(User::class);\n $user->expects($this->once())\n ->method('getUuid')\n ->willReturn('uuid-of-the-user');\n $shareUser1 = $this->createMock(User::class);\n $shareUser2 = $this->createMock(User::class);\n $title = 'Test title';\n $content = 'Test content';\n $target = AskAnythingPromptTarget::call;\n $shareUsers = ['us-1', 'us-2'];\n $shareGroups = [];\n\n $this->userRepository->expects($this->exactly(2))\n ->method('findByUuid')\n ->willReturnMap([\n ['us-1', $shareUser1],\n ['us-2', $shareUser2],\n ]);\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('getUuid')\n ->willReturn('prompt-1-uuid');\n $prompt->expects($this->once())\n ->method('getTitle')\n ->willReturn($title);\n $prompt->expects($this->once())\n ->method('getContent')\n ->willReturn($content);\n $this->askAnythingRepository->expects($this->once())\n ->method('createPrompt')\n ->with(\n $user,\n $target,\n $title,\n $content,\n [$shareUser1, $shareUser2],\n [],\n )\n ->willReturn($prompt);\n\n $expectedPromptDto = new AskAnythingPromptDto(\n 'prompt-1-uuid',\n $title,\n $content,\n $target,\n 'uuid-of-the-user',\n $shareUsers,\n $shareGroups,\n false,\n );\n\n $actualPromptDto = $this->askAnythingPromptService->create(\n $user,\n $title,\n $content,\n $target,\n $shareUsers,\n $shareGroups\n );\n\n $this->assertEquals($expectedPromptDto, $actualPromptDto);\n }\n\n public function testRecreatePromptsForUserRelations(): void\n {\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('getId')\n ->willReturn(1);\n $prompt->expects($this->once())\n ->method('getTarget')\n ->willReturn(AskAnythingPromptTarget::call);\n $prompt->expects($this->once())\n ->method('getTitle')\n ->willReturn('Test title');\n $prompt->expects($this->once())\n ->method('getContent')\n ->willReturn('Test content');\n\n $sharedPrompt = $this->createMock(UserAskAnythingPrompt::class);\n $sharedUser = $this->createMock(User::class);\n $sharedUser->expects($this->once())\n ->method('isStatusActive')\n ->willReturn(true);\n $sharedUser->expects($this->once())\n ->method('getId')\n ->willReturn(1);\n\n $sharedPrompt->expects($this->once())\n ->method('getUser')\n ->willReturn($sharedUser);\n $sharedPrompt->expects($this->exactly(2))\n ->method('isRemoved')\n ->willReturn(false);\n $sharedPrompt->expects($this->once())\n ->method('delete');\n\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedUsersAndGroupsByPromptId')\n ->with(1)\n ->willReturn(new Collection([$sharedPrompt]));\n\n $this->askAnythingRepository->expects($this->once())\n ->method('createPrompt');\n\n $data = $this->invokePrivateMethod('recreatePromptsForUserRelations', $this->askAnythingPromptService, [$prompt]);\n\n $this->assertEquals([[1], []], $data);\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Tests\\Unit\\Component\\AskAnything;\n\nuse Illuminate\\Database\\Eloquent\\Collection;\nuse Jiminny\\Component\\AskAnything\\AskAnythingPromptService;\nuse Jiminny\\Component\\AskAnything\\Dtos\\AskAnythingPromptDto;\nuse Jiminny\\Contracts\\Repositories\\GroupRepositoryInterface;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPrompt;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPromptTarget;\nuse Jiminny\\Models\\AskAnything\\UserAskAnythingPrompt;\nuse Jiminny\\Models\\Group;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AskAnythingRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse PHPUnit\\Framework\\MockObject\\MockObject;\nuse Tests\\TestCase;\nuse Tests\\Unit\\Traits\\TestPrivateMethod;\n\nclass AskAnythingPromptServiceTest extends TestCase\n{\n use TestPrivateMethod;\n\n private AskAnythingPromptService $askAnythingPromptService;\n private AskAnythingRepository&MockObject $askAnythingRepository;\n private UserRepository&MockObject $userRepository;\n private GroupRepositoryInterface&MockObject $groupRepository;\n\n protected function setUp(): void\n {\n $this->askAnythingRepository = $this->createMock(AskAnythingRepository::class);\n $this->userRepository = $this->createMock(UserRepository::class);\n $this->groupRepository = $this->createMock(GroupRepositoryInterface::class);\n\n $this->askAnythingPromptService = new AskAnythingPromptService(\n $this->askAnythingRepository,\n $this->userRepository,\n $this->groupRepository\n );\n }\n\n public function testGetAskAnythingPrompts(): void\n {\n $user = $this->createMock(User::class);\n $user->expects($this->any())\n ->method('getId')\n ->willReturn(1);\n $user->expects($this->any())\n ->method('getUuid')\n ->willReturn('1');\n $defaultPrompt = $this->createMock(AskAnythingPrompt::class);\n $defaultPrompt->expects($this->once())\n ->method('getOwner')\n ->willReturn(null);\n $defaultPrompt->expects($this->once())\n ->method('getUuid')\n ->willReturn('default-uuid');\n $defaultPrompt->expects($this->once())\n ->method('getTitle')\n ->willReturn('Sentiment');\n $defaultPrompt->expects($this->once())\n ->method('getContent')\n ->willReturn('What was the overall sentiment of the customer during the call?');\n $defaultPrompt->expects($this->once())\n ->method('getHasReports')\n ->willReturn(false);\n $promptOwnedByUser = $this->createMock(AskAnythingPrompt::class);\n $promptOwnedByUser->expects($this->exactly(2))\n ->method('getOwner')\n ->willReturn($user);\n $promptOwnedByUser->expects($this->once())\n ->method('getUuid')\n ->willReturn('uuid-1st-prompt');\n $promptOwnedByUser->expects($this->once())\n ->method('getTitle')\n ->willReturn('First users prompt');\n $promptOwnedByUser->expects($this->once())\n ->method('getContent')\n ->willReturn('Test prompt');\n $promptOwnedByUser->expects($this->once())\n ->method('getId')\n ->willReturn(99);\n $promptOwnedByUser->expects($this->once())\n ->method('getOwnerId')\n ->willReturn(1);\n $promptOwnedByUser->expects($this->once())\n ->method('getHasReports')\n ->willReturn(true);\n $defaultPromptOrderedByUser = $this->createMock(AskAnythingPrompt::class);\n $defaultPromptOrderedByUser->expects($this->once())\n ->method('getOwner')\n ->willReturn(null);\n $defaultPromptOrderedByUser->expects($this->once())\n ->method('getUuid')\n ->willReturn('default-uuid');\n $defaultPromptOrderedByUser->expects($this->once())\n ->method('getTitle')\n ->willReturn('Sentiment');\n $defaultPromptOrderedByUser->expects($this->once())\n ->method('getContent')\n ->willReturn('What was the overall sentiment of the customer during the call?');\n $defaultPromptOrderedByUser->expects($this->once())\n ->method('getHasReports')\n ->willReturn(false);\n $promptOwnedByUserAndSharedWithGroup = $this->createMock(AskAnythingPrompt::class);\n $promptOwnedByUserAndSharedWithGroup->expects($this->exactly(2))\n ->method('getOwner')\n ->willReturn($user);\n $promptOwnedByUserAndSharedWithGroup->expects($this->once())\n ->method('getUuid')\n ->willReturn('uuid-2nd-prompt');\n $promptOwnedByUserAndSharedWithGroup->expects($this->once())\n ->method('getTitle')\n ->willReturn('Prompt shared with group');\n $promptOwnedByUserAndSharedWithGroup->expects($this->once())\n ->method('getContent')\n ->willReturn('Test prompt that is shared with group');\n $promptOwnedByUserAndSharedWithGroup->expects($this->once())\n ->method('getId')\n ->willReturn(109);\n $promptOwnedByUserAndSharedWithGroup->expects($this->once())\n ->method('getOwnerId')\n ->willReturn(1);\n $promptOwnedByUserAndSharedWithGroup->expects($this->once())\n ->method('getHasReports')\n ->willReturn(false);\n\n $group = $this->createMock(Group::class);\n $group->expects($this->once())\n ->method('getUuid')\n ->willReturn('uuid-of-the-group');\n $sharedWithGroup = $this->createMock(UserAskAnythingPrompt::class);\n $sharedWithGroup->expects($this->once())\n ->method('getUser')\n ->willReturn(null);\n $sharedWithGroup->expects($this->once())\n ->method('getGroup')\n ->willReturn($group);\n\n $this->askAnythingRepository->expects($this->exactly(2))\n ->method('findSharedUsersAndGroupsByPromptId')\n ->willReturnMap([\n [99, new Collection([])],\n [109, new Collection([$sharedWithGroup])],\n ]);\n\n $prompts = [$defaultPrompt, $promptOwnedByUser, $defaultPromptOrderedByUser, $promptOwnedByUserAndSharedWithGroup];\n $this->askAnythingRepository->expects($this->once())\n ->method('findPromptsByUserAndTarget')\n ->willReturn(new Collection($prompts));\n\n $expectedDto1 = new AskAnythingPromptDto(\n 'default-uuid',\n 'Sentiment',\n 'What was the overall sentiment of the customer during the call?',\n AskAnythingPromptTarget::call,\n null,\n null,\n null,\n false,\n );\n $expectedDto2 = new AskAnythingPromptDto(\n 'uuid-1st-prompt',\n 'First users prompt',\n 'Test prompt',\n AskAnythingPromptTarget::call,\n '1',\n [],\n [],\n true,\n );\n $expectedDto3 = new AskAnythingPromptDto(\n 'default-uuid',\n 'Sentiment',\n 'What was the overall sentiment of the customer during the call?',\n AskAnythingPromptTarget::call,\n null,\n null,\n null,\n false,\n );\n $expectedDto4 = new AskAnythingPromptDto(\n 'uuid-2nd-prompt',\n 'Prompt shared with group',\n 'Test prompt that is shared with group',\n AskAnythingPromptTarget::call,\n '1',\n [],\n ['uuid-of-the-group'],\n false,\n );\n $dtos = $this->askAnythingPromptService->get($user, AskAnythingPromptTarget::call);\n\n $this->assertEquals([$expectedDto1, $expectedDto2, $expectedDto3, $expectedDto4], $dtos);\n }\n\n public function testEditAskAnythingPrompt(): void\n {\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('isDefaultPrompt')\n ->willReturn(false);\n $prompt->expects($this->once())\n ->method('getOwnerId')\n ->willReturn(123);\n $prompt->expects($this->never())\n ->method('getTarget')\n ->willReturn(AskAnythingPromptTarget::call);\n $user = $this->createMock(User::class);\n $user->expects($this->once())\n ->method('getId')\n ->willReturn(123);\n $user->expects($this->once())\n ->method('getUuid')\n ->willReturn('owner-uuid');\n\n $title = 'new title';\n $content = 'new content';\n $shareUsers = ['us-1'];\n $shareGroups = ['gr-1', 'gr-2'];\n\n $shareUser = $this->createMock(User::class);\n $this->userRepository->expects($this->once())\n ->method('findByUuid')\n ->with('us-1')\n ->willReturn($shareUser);\n $shareGroup1 = $this->createMock(Group::class);\n $shareGroup2 = $this->createMock(Group::class);\n $this->groupRepository->expects($this->exactly(2))\n ->method('findByUuid')\n ->willReturnMap([\n ['gr-1', $shareGroup1],\n ['gr-2', $shareGroup2],\n ]);\n\n $editPrompt = $this->createMock(AskAnythingPrompt::class);\n $editPrompt->expects($this->once())\n ->method('getTitle')\n ->willReturn($title);\n $editPrompt->expects($this->once())\n ->method('getContent')\n ->willReturn($content);\n $editPrompt->expects($this->once())\n ->method('getTarget')\n ->willReturn(AskAnythingPromptTarget::call);\n $editPrompt->expects($this->once())\n ->method('getUuid')\n ->willReturn('uuid-1st-prompt');\n $this->askAnythingRepository->expects($this->once())\n ->method('editPrompt')\n ->with($prompt, $title, $content, [$shareUser], [$shareGroup1, $shareGroup2])\n ->willReturn($editPrompt);\n\n $expectedDto = new AskAnythingPromptDto(\n 'uuid-1st-prompt',\n $title,\n $content,\n AskAnythingPromptTarget::call,\n 'owner-uuid',\n $shareUsers,\n $shareGroups\n );\n $editDto = $this->askAnythingPromptService->edit($prompt, $user, $title, $content, $shareUsers, $shareGroups);\n\n $this->assertEquals($expectedDto, $editDto);\n }\n\n public function testHideDefaultAndCreateAskAnythingPrompt(): void\n {\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('isDefaultPrompt')\n ->willReturn(true);\n $prompt->expects($this->once())\n ->method('getTarget')\n ->willReturn(AskAnythingPromptTarget::call);\n $user = $this->createMock(User::class);\n $user->expects($this->once())\n ->method('getUuid')\n ->willReturn('new-owner-uuid');\n $title = 'title';\n $content = 'content';\n $shareUsers = ['us-1'];\n $shareGroups = [];\n $shareUser = $this->createMock(User::class);\n $this->userRepository->expects($this->once())\n ->method('findByUuid')\n ->with('us-1')\n ->willReturn($shareUser);\n $this->groupRepository->expects($this->never())\n ->method('findByUuid');\n\n $newPrompt = $this->createMock(AskAnythingPrompt::class);\n $newPrompt->expects($this->once())\n ->method('getTarget')\n ->willReturn(AskAnythingPromptTarget::call);\n $newPrompt->expects($this->once())\n ->method('getUuid')\n ->willReturn('uuid-1st-prompt');\n $newPrompt->expects($this->once())\n ->method('getTitle')\n ->willReturn($title);\n $newPrompt->expects($this->once())\n ->method('getContent')\n ->willReturn($content);\n\n $this->askAnythingRepository->expects($this->once())\n ->method('hidePromptForUser');\n $this->askAnythingRepository->expects($this->once())\n ->method('createPrompt')\n ->willReturn($newPrompt);\n\n $expectedDto = new AskAnythingPromptDto(\n 'uuid-1st-prompt',\n $title,\n $content,\n AskAnythingPromptTarget::call,\n 'new-owner-uuid',\n $shareUsers,\n $shareGroups\n );\n\n $actualDto = $this->askAnythingPromptService->edit($prompt, $user, $title, $content, $shareUsers, $shareGroups);\n\n $this->assertEquals($expectedDto, $actualDto);\n }\n\n public function testDeleteAskAnythingPrompt(): void\n {\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('isDefaultPrompt')\n ->willReturn(false);\n $prompt->expects($this->any())\n ->method('getId')\n ->willReturn(1);\n $prompt->expects($this->once())\n ->method('getOwnerId')\n ->willReturn(1);\n\n // Use Mockery for the relationship mock (more flexible)\n $relationMock = \\Mockery::mock(\\Illuminate\\Database\\Eloquent\\Relations\\HasMany::class);\n $relationMock->shouldReceive('withTrashed')\n ->once()\n ->andReturnSelf();\n $relationMock->shouldReceive('update')\n ->once()\n ->with(['ask_anything_prompt_id' => null, 'status' => false]);\n\n $prompt->expects($this->once())\n ->method('automatedReports')\n ->willReturn($relationMock);\n\n $user = $this->createMock(User::class);\n $user->expects($this->once())\n ->method('getId')\n ->willReturn(1);\n $userPrompt = $this->createMock(UserAskAnythingPrompt::class);\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedPromptByUser')\n ->with(1, $user)\n ->willReturn($userPrompt);\n $userPrompt->expects($this->once())\n ->method('delete');\n $this->askAnythingRepository->expects($this->any())\n ->method('findSharedUsersAndGroupsByPromptId')\n ->with(1)\n ->willReturn(new Collection([]));\n $this->askAnythingRepository->expects($this->once())\n ->method('deletePrompt');\n $this->askAnythingPromptService->delete($prompt, $user);\n }\n\n public function testDeleteAskAnythingPromptWithRelations(): void\n {\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('isDefaultPrompt')\n ->willReturn(false);\n $prompt->expects($this->any())\n ->method('getId')\n ->willReturn(1);\n $prompt->expects($this->once())\n ->method('getOwnerId')\n ->willReturn(1);\n $user = $this->createMock(User::class);\n $user->expects($this->any())\n ->method('getId')\n ->willReturn(1);\n $userPrompt = $this->createMock(UserAskAnythingPrompt::class);\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedPromptByUser')\n ->with(1, $user)\n ->willReturn($userPrompt);\n $userPrompt->expects($this->once())\n ->method('delete');\n $this->askAnythingRepository->expects($this->exactly(3))\n ->method('findSharedUsersAndGroupsByPromptId')\n ->willReturnMap([\n [1, new Collection([$userPrompt])],\n [1, new Collection([])],\n ]);\n $this->askAnythingRepository->expects($this->never())\n ->method('deletePrompt');\n $this->askAnythingPromptService->delete($prompt, $user);\n }\n\n public function testHideDefaultAskAnythingPrompt(): void\n {\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('isDefaultPrompt')\n ->willReturn(true);\n $user = $this->createMock(User::class);\n $this->askAnythingRepository->expects($this->once())\n ->method('hidePromptForUser');\n $this->askAnythingPromptService->delete($prompt, $user);\n }\n\n public function testHideSharedWithUserAskAnythingPrompt(): void\n {\n $userPrompt = $this->createMock(UserAskAnythingPrompt::class);\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('isDefaultPrompt')\n ->willReturn(false);\n $prompt->expects($this->once())\n ->method('getOwnerId')\n ->willReturn(1);\n $prompt->expects($this->exactly(3))\n ->method('getId')\n ->willReturn(33);\n\n $relationMock = \\Mockery::mock(\\Illuminate\\Database\\Eloquent\\Relations\\HasMany::class);\n $relationMock->shouldReceive('withTrashed')\n ->once()\n ->andReturnSelf();\n $relationMock->shouldReceive('update')\n ->once()\n ->with(['ask_anything_prompt_id' => null, 'status' => false]);\n $prompt->expects($this->once())\n ->method('automatedReports')\n ->willReturn($relationMock);\n\n $user = $this->createMock(User::class);\n $user->expects($this->once())\n ->method('getId')\n ->willReturn(2);\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedPromptByUser')\n ->with(33, $user)\n ->willReturn($userPrompt);\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedPromptByUserGroup')\n ->with(33, $user)\n ->willReturn(null);\n $userPrompt->expects($this->once())\n ->method('delete');\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedUsersAndGroupsByPromptId')\n ->with(33)\n ->willReturn(new Collection([]));\n\n $this->askAnythingPromptService->delete($prompt, $user);\n }\n\n public function testHideSharedWithUserAndGroupAskAnythingPrompt(): void\n {\n $userPrompt = $this->createMock(UserAskAnythingPrompt::class);\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('isDefaultPrompt')\n ->willReturn(false);\n $prompt->expects($this->once())\n ->method('getOwnerId')\n ->willReturn(1);\n $prompt->expects($this->exactly(2))\n ->method('getId')\n ->willReturn(33);\n $user = $this->createMock(User::class);\n $user->expects($this->once())\n ->method('getId')\n ->willReturn(2);\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedPromptByUser')\n ->with(33, $user)\n ->willReturn($userPrompt);\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedPromptByUserGroup')\n ->with(33, $user)\n ->willReturn($userPrompt);\n $userPrompt->expects($this->never())\n ->method('delete');\n $this->askAnythingRepository->expects($this->once())\n ->method('hidePromptForUser')\n ->with($prompt, $user);\n\n $this->askAnythingPromptService->delete($prompt, $user);\n }\n\n public function testHideSharedWithGroupAskAnythingPrompt(): void\n {\n $userPrompt = $this->createMock(UserAskAnythingPrompt::class);\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('isDefaultPrompt')\n ->willReturn(false);\n $prompt->expects($this->once())\n ->method('getOwnerId')\n ->willReturn(1);\n $prompt->expects($this->exactly(2))\n ->method('getId')\n ->willReturn(33);\n $user = $this->createMock(User::class);\n $user->expects($this->once())\n ->method('getId')\n ->willReturn(2);\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedPromptByUser')\n ->with(33, $user)\n ->willReturn(null);\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedPromptByUserGroup')\n ->with(33, $user)\n ->willReturn($userPrompt);\n $userPrompt->expects($this->never())\n ->method('delete');\n $this->askAnythingRepository->expects($this->once())\n ->method('hidePromptForUser')\n ->with($prompt, $user);\n\n $this->askAnythingPromptService->delete($prompt, $user);\n }\n\n public function testDeleteWithNoSharesAndNotOwner(): void\n {\n $userPrompt = $this->createMock(UserAskAnythingPrompt::class);\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('isDefaultPrompt')\n ->willReturn(false);\n $prompt->expects($this->once())\n ->method('getOwnerId')\n ->willReturn(1);\n $prompt->expects($this->exactly(2))\n ->method('getId')\n ->willReturn(33);\n $user = $this->createMock(User::class);\n $user->expects($this->once())\n ->method('getId')\n ->willReturn(2);\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedPromptByUser')\n ->with(33, $user)\n ->willReturn(null);\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedPromptByUserGroup')\n ->with(33, $user)\n ->willReturn(null);\n $userPrompt->expects($this->never())\n ->method('delete');\n $this->askAnythingRepository->expects($this->never())\n ->method('hidePromptForUser');\n\n $this->expectException(\\InvalidArgumentException::class);\n\n $this->askAnythingPromptService->delete($prompt, $user);\n }\n\n public function testReorderAskAnythingPrompts(): void\n {\n $prompts = ['id1', 'id2', 'id3'];\n $prompt1 = $this->createMock(AskAnythingPrompt::class);\n $prompt2 = $this->createMock(AskAnythingPrompt::class);\n $prompt3 = $this->createMock(AskAnythingPrompt::class);\n $user = $this->createMock(User::class);\n $this->askAnythingRepository->expects($this->exactly(3))\n ->method('getPromptByUuid')\n ->willReturnMap([\n ['id1', $prompt1],\n ['id2', $prompt2],\n ['id3', $prompt3],\n ]);\n $this->askAnythingRepository->expects($this->exactly(3))\n ->method('orderPromptForUser')\n ->willReturnMap([\n [[$prompt1, $user, 1]],\n [[$prompt2, $user, 2]],\n [[$prompt3, $user, 3]],\n ]);\n $this->askAnythingPromptService->reorder($user, $prompts);\n }\n\n public function testCreateAskAnythingPromptWithTwoUsers(): void\n {\n $user = $this->createMock(User::class);\n $user->expects($this->once())\n ->method('getUuid')\n ->willReturn('uuid-of-the-user');\n $shareUser1 = $this->createMock(User::class);\n $shareUser2 = $this->createMock(User::class);\n $title = 'Test title';\n $content = 'Test content';\n $target = AskAnythingPromptTarget::call;\n $shareUsers = ['us-1', 'us-2'];\n $shareGroups = [];\n\n $this->userRepository->expects($this->exactly(2))\n ->method('findByUuid')\n ->willReturnMap([\n ['us-1', $shareUser1],\n ['us-2', $shareUser2],\n ]);\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('getUuid')\n ->willReturn('prompt-1-uuid');\n $prompt->expects($this->once())\n ->method('getTitle')\n ->willReturn($title);\n $prompt->expects($this->once())\n ->method('getContent')\n ->willReturn($content);\n $this->askAnythingRepository->expects($this->once())\n ->method('createPrompt')\n ->with(\n $user,\n $target,\n $title,\n $content,\n [$shareUser1, $shareUser2],\n [],\n )\n ->willReturn($prompt);\n\n $expectedPromptDto = new AskAnythingPromptDto(\n 'prompt-1-uuid',\n $title,\n $content,\n $target,\n 'uuid-of-the-user',\n $shareUsers,\n $shareGroups,\n false,\n );\n\n $actualPromptDto = $this->askAnythingPromptService->create(\n $user,\n $title,\n $content,\n $target,\n $shareUsers,\n $shareGroups\n );\n\n $this->assertEquals($expectedPromptDto, $actualPromptDto);\n }\n\n public function testRecreatePromptsForUserRelations(): void\n {\n $prompt = $this->createMock(AskAnythingPrompt::class);\n $prompt->expects($this->once())\n ->method('getId')\n ->willReturn(1);\n $prompt->expects($this->once())\n ->method('getTarget')\n ->willReturn(AskAnythingPromptTarget::call);\n $prompt->expects($this->once())\n ->method('getTitle')\n ->willReturn('Test title');\n $prompt->expects($this->once())\n ->method('getContent')\n ->willReturn('Test content');\n\n $sharedPrompt = $this->createMock(UserAskAnythingPrompt::class);\n $sharedUser = $this->createMock(User::class);\n $sharedUser->expects($this->once())\n ->method('isStatusActive')\n ->willReturn(true);\n $sharedUser->expects($this->once())\n ->method('getId')\n ->willReturn(1);\n\n $sharedPrompt->expects($this->once())\n ->method('getUser')\n ->willReturn($sharedUser);\n $sharedPrompt->expects($this->exactly(2))\n ->method('isRemoved')\n ->willReturn(false);\n $sharedPrompt->expects($this->once())\n ->method('delete');\n\n $this->askAnythingRepository->expects($this->once())\n ->method('findSharedUsersAndGroupsByPromptId')\n ->with(1)\n ->willReturn(new Collection([$sharedPrompt]));\n\n $this->askAnythingRepository->expects($this->once())\n ->method('createPrompt');\n\n $data = $this->invokePrivateMethod('recreatePromptsForUserRelations', $this->askAnythingPromptService, [$prompt]);\n\n $this->assertEquals([[1], []], $data);\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.42785904,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.43650267,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.4474734,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.45611703,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.46476063,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.47573137,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.4867021,"top":0.09896249,"width":0.024268618,"height":0.01915403},"on_screen":true,"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.51329786,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"bounds":{"left":0.5242686,"top":0.09896249,"width":0.029587766,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"bounds":{"left":0.70611703,"top":0.09896249,"width":0.02825798,"height":0.01915403},"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"21","depth":4,"bounds":{"left":0.66921544,"top":0.123703115,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.68085104,"top":0.123703115,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"18","depth":4,"bounds":{"left":0.69015956,"top":0.123703115,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.7017952,"top":0.123703115,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.7117686,"top":0.123703115,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.72140956,"top":0.12210695,"width":0.00731383,"height":0.018355945},"on_screen":true,"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.7287234,"top":0.12210695,"width":0.006981383,"height":0.018355945},"on_screen":true,"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\n\nselect sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id\nwhere u.team_id = 1;\nSELECT * FROM social_accounts WHERE sociable_id = 1635;\nSELECT * FROM users WHERE id = 1635;\n\nselect * from teams where id = 1;\nselect * from users where team_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 activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;\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\nSELECT * FROM automated_reports where id = 71;\nSELECT * FROM automated_report_results where report_id = 71;\nUPDATE automated_reports set playbook_categories = NULL 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 `automated_report_results`.* FROM `automated_report_results`\nINNER JOIN `automated_reports`\n ON `automated_report_results`.`report_id` = `automated_reports`.`id`\nWHERE 1=1\n AND `automated_report_results`.`generated_at` IS NOT NULL\n# AND `automated_report_results`.`sent_at` IS NOT NULL\n AND `automated_reports`.`team_id` = 1\n AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$.\"users\"')\n;\n\nSELECT * FROM automated_reports where id = 67;\nSELECT * FROM automated_reports where id = 42;\nSELECT * FROM users WHERE id = 143; # group 28\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;\n\nselect * from leads;\n\nSELECT * FROM activities WHERE uuid_to_bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid; # 422003\nSELECT * FROM activities WHERE id IN (16,422003);\nSELECT * FROM activities where status = 'failed';\n\nSELECT * FROM tracks WHERE activity_id = 422003;\n\nSELECT\n a.*\nFROM activities a\nJOIN users u ON a.user_id = u.id\nWHERE\n a.status = 'completed'\n AND uuid_to_bin('641f1acb-16b8-42d1-8726-df52979dad0e') = u.uuid\n AND a.deleted_at IS NULL\n AND EXISTS (\n SELECT 1 FROM tracks t\n WHERE t.activity_id = a.id\n AND t.type IN ('audio', 'video')\n )\nORDER BY a.actual_start_time DESC\nLIMIT 25;\n\nselect * from teams where id = 19;\nselect * from crm_configurations where provider = 'pipedrive';\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 = 19 and sa.provider = 'pipedrive';\n\nSELECT * FROM social_accounts WHERE id = 1116;\n\nUPDATE social_accounts SET provider_user_token = 'v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA',\nprovider_refresh_token = '5034113:19555731:87c14258f0c813d02767ee975f6044d46b6b2bfc',\nexpires = 1779091997,\nstate = 'connected'\nWHERE id = 1116;\n\n \"provider_user_token\": \"v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA\",\n \"provider_refresh_token\": \"5034113:19555731:87c14258f0c813d02767ee975f6044d46b6b2bfc\",\n \"expires\": 1779091997,","depth":4,"on_screen":true,"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\n\nselect sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id\nwhere u.team_id = 1;\nSELECT * FROM social_accounts WHERE sociable_id = 1635;\nSELECT * FROM users WHERE id = 1635;\n\nselect * from teams where id = 1;\nselect * from users where team_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 activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;\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\nSELECT * FROM automated_reports where id = 71;\nSELECT * FROM automated_report_results where report_id = 71;\nUPDATE automated_reports set playbook_categories = NULL 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 `automated_report_results`.* FROM `automated_report_results`\nINNER JOIN `automated_reports`\n ON `automated_report_results`.`report_id` = `automated_reports`.`id`\nWHERE 1=1\n AND `automated_report_results`.`generated_at` IS NOT NULL\n# AND `automated_report_results`.`sent_at` IS NOT NULL\n AND `automated_reports`.`team_id` = 1\n AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$.\"users\"')\n;\n\nSELECT * FROM automated_reports where id = 67;\nSELECT * FROM automated_reports where id = 42;\nSELECT * FROM users WHERE id = 143; # group 28\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;\n\nselect * from leads;\n\nSELECT * FROM activities WHERE uuid_to_bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid; # 422003\nSELECT * FROM activities WHERE id IN (16,422003);\nSELECT * FROM activities where status = 'failed';\n\nSELECT * FROM tracks WHERE activity_id = 422003;\n\nSELECT\n a.*\nFROM activities a\nJOIN users u ON a.user_id = u.id\nWHERE\n a.status = 'completed'\n AND uuid_to_bin('641f1acb-16b8-42d1-8726-df52979dad0e') = u.uuid\n AND a.deleted_at IS NULL\n AND EXISTS (\n SELECT 1 FROM tracks t\n WHERE t.activity_id = a.id\n AND t.type IN ('audio', 'video')\n )\nORDER BY a.actual_start_time DESC\nLIMIT 25;\n\nselect * from teams where id = 19;\nselect * from crm_configurations where provider = 'pipedrive';\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 = 19 and sa.provider = 'pipedrive';\n\nSELECT * FROM social_accounts WHERE id = 1116;\n\nUPDATE social_accounts SET provider_user_token = 'v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA',\nprovider_refresh_token = '5034113:19555731:87c14258f0c813d02767ee975f6044d46b6b2bfc',\nexpires = 1779091997,\nstate = 'connected'\nWHERE id = 1116;\n\n \"provider_user_token\": \"v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA\",\n \"provider_refresh_token\": \"5034113:19555731:87c14258f0c813d02767ee975f6044d46b6b2bfc\",\n \"expires\": 1779091997,","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"Socket fail to connect to host:address=(host=localhost)(port=3306)(type=primary). Connection refused","depth":3,"bounds":{"left":0.42652926,"top":0.9577015,"width":0.29321808,"height":0.013567438},"on_screen":true,"value":"Socket fail to connect to host:address=(host=localhost)(port=3306)(type=primary). Connection refused","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
6040481362467270736
|
2218759000067020365
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
6
1
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Tests\Unit\Component\AskAnything;
use Illuminate\Database\Eloquent\Collection;
use Jiminny\Component\AskAnything\AskAnythingPromptService;
use Jiminny\Component\AskAnything\Dtos\AskAnythingPromptDto;
use Jiminny\Contracts\Repositories\GroupRepositoryInterface;
use Jiminny\Models\AskAnything\AskAnythingPrompt;
use Jiminny\Models\AskAnything\AskAnythingPromptTarget;
use Jiminny\Models\AskAnything\UserAskAnythingPrompt;
use Jiminny\Models\Group;
use Jiminny\Models\User;
use Jiminny\Repositories\AskAnythingRepository;
use Jiminny\Repositories\UserRepository;
use PHPUnit\Framework\MockObject\MockObject;
use Tests\TestCase;
use Tests\Unit\Traits\TestPrivateMethod;
class AskAnythingPromptServiceTest extends TestCase
{
use TestPrivateMethod;
private AskAnythingPromptService $askAnythingPromptService;
private AskAnythingRepository&MockObject $askAnythingRepository;
private UserRepository&MockObject $userRepository;
private GroupRepositoryInterface&MockObject $groupRepository;
protected function setUp(): void
{
$this->askAnythingRepository = $this->createMock(AskAnythingRepository::class);
$this->userRepository = $this->createMock(UserRepository::class);
$this->groupRepository = $this->createMock(GroupRepositoryInterface::class);
$this->askAnythingPromptService = new AskAnythingPromptService(
$this->askAnythingRepository,
$this->userRepository,
$this->groupRepository
);
}
public function testGetAskAnythingPrompts(): void
{
$user = $this->createMock(User::class);
$user->expects($this->any())
->method('getId')
->willReturn(1);
$user->expects($this->any())
->method('getUuid')
->willReturn('1');
$defaultPrompt = $this->createMock(AskAnythingPrompt::class);
$defaultPrompt->expects($this->once())
->method('getOwner')
->willReturn(null);
$defaultPrompt->expects($this->once())
->method('getUuid')
->willReturn('default-uuid');
$defaultPrompt->expects($this->once())
->method('getTitle')
->willReturn('Sentiment');
$defaultPrompt->expects($this->once())
->method('getContent')
->willReturn('What was the overall sentiment of the customer during the call?');
$defaultPrompt->expects($this->once())
->method('getHasReports')
->willReturn(false);
$promptOwnedByUser = $this->createMock(AskAnythingPrompt::class);
$promptOwnedByUser->expects($this->exactly(2))
->method('getOwner')
->willReturn($user);
$promptOwnedByUser->expects($this->once())
->method('getUuid')
->willReturn('uuid-1st-prompt');
$promptOwnedByUser->expects($this->once())
->method('getTitle')
->willReturn('First users prompt');
$promptOwnedByUser->expects($this->once())
->method('getContent')
->willReturn('Test prompt');
$promptOwnedByUser->expects($this->once())
->method('getId')
->willReturn(99);
$promptOwnedByUser->expects($this->once())
->method('getOwnerId')
->willReturn(1);
$promptOwnedByUser->expects($this->once())
->method('getHasReports')
->willReturn(true);
$defaultPromptOrderedByUser = $this->createMock(AskAnythingPrompt::class);
$defaultPromptOrderedByUser->expects($this->once())
->method('getOwner')
->willReturn(null);
$defaultPromptOrderedByUser->expects($this->once())
->method('getUuid')
->willReturn('default-uuid');
$defaultPromptOrderedByUser->expects($this->once())
->method('getTitle')
->willReturn('Sentiment');
$defaultPromptOrderedByUser->expects($this->once())
->method('getContent')
->willReturn('What was the overall sentiment of the customer during the call?');
$defaultPromptOrderedByUser->expects($this->once())
->method('getHasReports')
->willReturn(false);
$promptOwnedByUserAndSharedWithGroup = $this->createMock(AskAnythingPrompt::class);
$promptOwnedByUserAndSharedWithGroup->expects($this->exactly(2))
->method('getOwner')
->willReturn($user);
$promptOwnedByUserAndSharedWithGroup->expects($this->once())
->method('getUuid')
->willReturn('uuid-2nd-prompt');
$promptOwnedByUserAndSharedWithGroup->expects($this->once())
->method('getTitle')
->willReturn('Prompt shared with group');
$promptOwnedByUserAndSharedWithGroup->expects($this->once())
->method('getContent')
->willReturn('Test prompt that is shared with group');
$promptOwnedByUserAndSharedWithGroup->expects($this->once())
->method('getId')
->willReturn(109);
$promptOwnedByUserAndSharedWithGroup->expects($this->once())
->method('getOwnerId')
->willReturn(1);
$promptOwnedByUserAndSharedWithGroup->expects($this->once())
->method('getHasReports')
->willReturn(false);
$group = $this->createMock(Group::class);
$group->expects($this->once())
->method('getUuid')
->willReturn('uuid-of-the-group');
$sharedWithGroup = $this->createMock(UserAskAnythingPrompt::class);
$sharedWithGroup->expects($this->once())
->method('getUser')
->willReturn(null);
$sharedWithGroup->expects($this->once())
->method('getGroup')
->willReturn($group);
$this->askAnythingRepository->expects($this->exactly(2))
->method('findSharedUsersAndGroupsByPromptId')
->willReturnMap([
[99, new Collection([])],
[109, new Collection([$sharedWithGroup])],
]);
$prompts = [$defaultPrompt, $promptOwnedByUser, $defaultPromptOrderedByUser, $promptOwnedByUserAndSharedWithGroup];
$this->askAnythingRepository->expects($this->once())
->method('findPromptsByUserAndTarget')
->willReturn(new Collection($prompts));
$expectedDto1 = new AskAnythingPromptDto(
'default-uuid',
'Sentiment',
'What was the overall sentiment of the customer during the call?',
AskAnythingPromptTarget::call,
null,
null,
null,
false,
);
$expectedDto2 = new AskAnythingPromptDto(
'uuid-1st-prompt',
'First users prompt',
'Test prompt',
AskAnythingPromptTarget::call,
'1',
[],
[],
true,
);
$expectedDto3 = new AskAnythingPromptDto(
'default-uuid',
'Sentiment',
'What was the overall sentiment of the customer during the call?',
AskAnythingPromptTarget::call,
null,
null,
null,
false,
);
$expectedDto4 = new AskAnythingPromptDto(
'uuid-2nd-prompt',
'Prompt shared with group',
'Test prompt that is shared with group',
AskAnythingPromptTarget::call,
'1',
[],
['uuid-of-the-group'],
false,
);
$dtos = $this->askAnythingPromptService->get($user, AskAnythingPromptTarget::call);
$this->assertEquals([$expectedDto1, $expectedDto2, $expectedDto3, $expectedDto4], $dtos);
}
public function testEditAskAnythingPrompt(): void
{
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('isDefaultPrompt')
->willReturn(false);
$prompt->expects($this->once())
->method('getOwnerId')
->willReturn(123);
$prompt->expects($this->never())
->method('getTarget')
->willReturn(AskAnythingPromptTarget::call);
$user = $this->createMock(User::class);
$user->expects($this->once())
->method('getId')
->willReturn(123);
$user->expects($this->once())
->method('getUuid')
->willReturn('owner-uuid');
$title = 'new title';
$content = 'new content';
$shareUsers = ['us-1'];
$shareGroups = ['gr-1', 'gr-2'];
$shareUser = $this->createMock(User::class);
$this->userRepository->expects($this->once())
->method('findByUuid')
->with('us-1')
->willReturn($shareUser);
$shareGroup1 = $this->createMock(Group::class);
$shareGroup2 = $this->createMock(Group::class);
$this->groupRepository->expects($this->exactly(2))
->method('findByUuid')
->willReturnMap([
['gr-1', $shareGroup1],
['gr-2', $shareGroup2],
]);
$editPrompt = $this->createMock(AskAnythingPrompt::class);
$editPrompt->expects($this->once())
->method('getTitle')
->willReturn($title);
$editPrompt->expects($this->once())
->method('getContent')
->willReturn($content);
$editPrompt->expects($this->once())
->method('getTarget')
->willReturn(AskAnythingPromptTarget::call);
$editPrompt->expects($this->once())
->method('getUuid')
->willReturn('uuid-1st-prompt');
$this->askAnythingRepository->expects($this->once())
->method('editPrompt')
->with($prompt, $title, $content, [$shareUser], [$shareGroup1, $shareGroup2])
->willReturn($editPrompt);
$expectedDto = new AskAnythingPromptDto(
'uuid-1st-prompt',
$title,
$content,
AskAnythingPromptTarget::call,
'owner-uuid',
$shareUsers,
$shareGroups
);
$editDto = $this->askAnythingPromptService->edit($prompt, $user, $title, $content, $shareUsers, $shareGroups);
$this->assertEquals($expectedDto, $editDto);
}
public function testHideDefaultAndCreateAskAnythingPrompt(): void
{
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('isDefaultPrompt')
->willReturn(true);
$prompt->expects($this->once())
->method('getTarget')
->willReturn(AskAnythingPromptTarget::call);
$user = $this->createMock(User::class);
$user->expects($this->once())
->method('getUuid')
->willReturn('new-owner-uuid');
$title = 'title';
$content = 'content';
$shareUsers = ['us-1'];
$shareGroups = [];
$shareUser = $this->createMock(User::class);
$this->userRepository->expects($this->once())
->method('findByUuid')
->with('us-1')
->willReturn($shareUser);
$this->groupRepository->expects($this->never())
->method('findByUuid');
$newPrompt = $this->createMock(AskAnythingPrompt::class);
$newPrompt->expects($this->once())
->method('getTarget')
->willReturn(AskAnythingPromptTarget::call);
$newPrompt->expects($this->once())
->method('getUuid')
->willReturn('uuid-1st-prompt');
$newPrompt->expects($this->once())
->method('getTitle')
->willReturn($title);
$newPrompt->expects($this->once())
->method('getContent')
->willReturn($content);
$this->askAnythingRepository->expects($this->once())
->method('hidePromptForUser');
$this->askAnythingRepository->expects($this->once())
->method('createPrompt')
->willReturn($newPrompt);
$expectedDto = new AskAnythingPromptDto(
'uuid-1st-prompt',
$title,
$content,
AskAnythingPromptTarget::call,
'new-owner-uuid',
$shareUsers,
$shareGroups
);
$actualDto = $this->askAnythingPromptService->edit($prompt, $user, $title, $content, $shareUsers, $shareGroups);
$this->assertEquals($expectedDto, $actualDto);
}
public function testDeleteAskAnythingPrompt(): void
{
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('isDefaultPrompt')
->willReturn(false);
$prompt->expects($this->any())
->method('getId')
->willReturn(1);
$prompt->expects($this->once())
->method('getOwnerId')
->willReturn(1);
// Use Mockery for the relationship mock (more flexible)
$relationMock = \Mockery::mock(\Illuminate\Database\Eloquent\Relations\HasMany::class);
$relationMock->shouldReceive('withTrashed')
->once()
->andReturnSelf();
$relationMock->shouldReceive('update')
->once()
->with(['ask_anything_prompt_id' => null, 'status' => false]);
$prompt->expects($this->once())
->method('automatedReports')
->willReturn($relationMock);
$user = $this->createMock(User::class);
$user->expects($this->once())
->method('getId')
->willReturn(1);
$userPrompt = $this->createMock(UserAskAnythingPrompt::class);
$this->askAnythingRepository->expects($this->once())
->method('findSharedPromptByUser')
->with(1, $user)
->willReturn($userPrompt);
$userPrompt->expects($this->once())
->method('delete');
$this->askAnythingRepository->expects($this->any())
->method('findSharedUsersAndGroupsByPromptId')
->with(1)
->willReturn(new Collection([]));
$this->askAnythingRepository->expects($this->once())
->method('deletePrompt');
$this->askAnythingPromptService->delete($prompt, $user);
}
public function testDeleteAskAnythingPromptWithRelations(): void
{
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('isDefaultPrompt')
->willReturn(false);
$prompt->expects($this->any())
->method('getId')
->willReturn(1);
$prompt->expects($this->once())
->method('getOwnerId')
->willReturn(1);
$user = $this->createMock(User::class);
$user->expects($this->any())
->method('getId')
->willReturn(1);
$userPrompt = $this->createMock(UserAskAnythingPrompt::class);
$this->askAnythingRepository->expects($this->once())
->method('findSharedPromptByUser')
->with(1, $user)
->willReturn($userPrompt);
$userPrompt->expects($this->once())
->method('delete');
$this->askAnythingRepository->expects($this->exactly(3))
->method('findSharedUsersAndGroupsByPromptId')
->willReturnMap([
[1, new Collection([$userPrompt])],
[1, new Collection([])],
]);
$this->askAnythingRepository->expects($this->never())
->method('deletePrompt');
$this->askAnythingPromptService->delete($prompt, $user);
}
public function testHideDefaultAskAnythingPrompt(): void
{
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('isDefaultPrompt')
->willReturn(true);
$user = $this->createMock(User::class);
$this->askAnythingRepository->expects($this->once())
->method('hidePromptForUser');
$this->askAnythingPromptService->delete($prompt, $user);
}
public function testHideSharedWithUserAskAnythingPrompt(): void
{
$userPrompt = $this->createMock(UserAskAnythingPrompt::class);
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('isDefaultPrompt')
->willReturn(false);
$prompt->expects($this->once())
->method('getOwnerId')
->willReturn(1);
$prompt->expects($this->exactly(3))
->method('getId')
->willReturn(33);
$relationMock = \Mockery::mock(\Illuminate\Database\Eloquent\Relations\HasMany::class);
$relationMock->shouldReceive('withTrashed')
->once()
->andReturnSelf();
$relationMock->shouldReceive('update')
->once()
->with(['ask_anything_prompt_id' => null, 'status' => false]);
$prompt->expects($this->once())
->method('automatedReports')
->willReturn($relationMock);
$user = $this->createMock(User::class);
$user->expects($this->once())
->method('getId')
->willReturn(2);
$this->askAnythingRepository->expects($this->once())
->method('findSharedPromptByUser')
->with(33, $user)
->willReturn($userPrompt);
$this->askAnythingRepository->expects($this->once())
->method('findSharedPromptByUserGroup')
->with(33, $user)
->willReturn(null);
$userPrompt->expects($this->once())
->method('delete');
$this->askAnythingRepository->expects($this->once())
->method('findSharedUsersAndGroupsByPromptId')
->with(33)
->willReturn(new Collection([]));
$this->askAnythingPromptService->delete($prompt, $user);
}
public function testHideSharedWithUserAndGroupAskAnythingPrompt(): void
{
$userPrompt = $this->createMock(UserAskAnythingPrompt::class);
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('isDefaultPrompt')
->willReturn(false);
$prompt->expects($this->once())
->method('getOwnerId')
->willReturn(1);
$prompt->expects($this->exactly(2))
->method('getId')
->willReturn(33);
$user = $this->createMock(User::class);
$user->expects($this->once())
->method('getId')
->willReturn(2);
$this->askAnythingRepository->expects($this->once())
->method('findSharedPromptByUser')
->with(33, $user)
->willReturn($userPrompt);
$this->askAnythingRepository->expects($this->once())
->method('findSharedPromptByUserGroup')
->with(33, $user)
->willReturn($userPrompt);
$userPrompt->expects($this->never())
->method('delete');
$this->askAnythingRepository->expects($this->once())
->method('hidePromptForUser')
->with($prompt, $user);
$this->askAnythingPromptService->delete($prompt, $user);
}
public function testHideSharedWithGroupAskAnythingPrompt(): void
{
$userPrompt = $this->createMock(UserAskAnythingPrompt::class);
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('isDefaultPrompt')
->willReturn(false);
$prompt->expects($this->once())
->method('getOwnerId')
->willReturn(1);
$prompt->expects($this->exactly(2))
->method('getId')
->willReturn(33);
$user = $this->createMock(User::class);
$user->expects($this->once())
->method('getId')
->willReturn(2);
$this->askAnythingRepository->expects($this->once())
->method('findSharedPromptByUser')
->with(33, $user)
->willReturn(null);
$this->askAnythingRepository->expects($this->once())
->method('findSharedPromptByUserGroup')
->with(33, $user)
->willReturn($userPrompt);
$userPrompt->expects($this->never())
->method('delete');
$this->askAnythingRepository->expects($this->once())
->method('hidePromptForUser')
->with($prompt, $user);
$this->askAnythingPromptService->delete($prompt, $user);
}
public function testDeleteWithNoSharesAndNotOwner(): void
{
$userPrompt = $this->createMock(UserAskAnythingPrompt::class);
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('isDefaultPrompt')
->willReturn(false);
$prompt->expects($this->once())
->method('getOwnerId')
->willReturn(1);
$prompt->expects($this->exactly(2))
->method('getId')
->willReturn(33);
$user = $this->createMock(User::class);
$user->expects($this->once())
->method('getId')
->willReturn(2);
$this->askAnythingRepository->expects($this->once())
->method('findSharedPromptByUser')
->with(33, $user)
->willReturn(null);
$this->askAnythingRepository->expects($this->once())
->method('findSharedPromptByUserGroup')
->with(33, $user)
->willReturn(null);
$userPrompt->expects($this->never())
->method('delete');
$this->askAnythingRepository->expects($this->never())
->method('hidePromptForUser');
$this->expectException(\InvalidArgumentException::class);
$this->askAnythingPromptService->delete($prompt, $user);
}
public function testReorderAskAnythingPrompts(): void
{
$prompts = ['id1', 'id2', 'id3'];
$prompt1 = $this->createMock(AskAnythingPrompt::class);
$prompt2 = $this->createMock(AskAnythingPrompt::class);
$prompt3 = $this->createMock(AskAnythingPrompt::class);
$user = $this->createMock(User::class);
$this->askAnythingRepository->expects($this->exactly(3))
->method('getPromptByUuid')
->willReturnMap([
['id1', $prompt1],
['id2', $prompt2],
['id3', $prompt3],
]);
$this->askAnythingRepository->expects($this->exactly(3))
->method('orderPromptForUser')
->willReturnMap([
[[$prompt1, $user, 1]],
[[$prompt2, $user, 2]],
[[$prompt3, $user, 3]],
]);
$this->askAnythingPromptService->reorder($user, $prompts);
}
public function testCreateAskAnythingPromptWithTwoUsers(): void
{
$user = $this->createMock(User::class);
$user->expects($this->once())
->method('getUuid')
->willReturn('uuid-of-the-user');
$shareUser1 = $this->createMock(User::class);
$shareUser2 = $this->createMock(User::class);
$title = 'Test title';
$content = 'Test content';
$target = AskAnythingPromptTarget::call;
$shareUsers = ['us-1', 'us-2'];
$shareGroups = [];
$this->userRepository->expects($this->exactly(2))
->method('findByUuid')
->willReturnMap([
['us-1', $shareUser1],
['us-2', $shareUser2],
]);
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('getUuid')
->willReturn('prompt-1-uuid');
$prompt->expects($this->once())
->method('getTitle')
->willReturn($title);
$prompt->expects($this->once())
->method('getContent')
->willReturn($content);
$this->askAnythingRepository->expects($this->once())
->method('createPrompt')
->with(
$user,
$target,
$title,
$content,
[$shareUser1, $shareUser2],
[],
)
->willReturn($prompt);
$expectedPromptDto = new AskAnythingPromptDto(
'prompt-1-uuid',
$title,
$content,
$target,
'uuid-of-the-user',
$shareUsers,
$shareGroups,
false,
);
$actualPromptDto = $this->askAnythingPromptService->create(
$user,
$title,
$content,
$target,
$shareUsers,
$shareGroups
);
$this->assertEquals($expectedPromptDto, $actualPromptDto);
}
public function testRecreatePromptsForUserRelations(): void
{
$prompt = $this->createMock(AskAnythingPrompt::class);
$prompt->expects($this->once())
->method('getId')
->willReturn(1);
$prompt->expects($this->once())
->method('getTarget')
->willReturn(AskAnythingPromptTarget::call);
$prompt->expects($this->once())
->method('getTitle')
->willReturn('Test title');
$prompt->expects($this->once())
->method('getContent')
->willReturn('Test content');
$sharedPrompt = $this->createMock(UserAskAnythingPrompt::class);
$sharedUser = $this->createMock(User::class);
$sharedUser->expects($this->once())
->method('isStatusActive')
->willReturn(true);
$sharedUser->expects($this->once())
->method('getId')
->willReturn(1);
$sharedPrompt->expects($this->once())
->method('getUser')
->willReturn($sharedUser);
$sharedPrompt->expects($this->exactly(2))
->method('isRemoved')
->willReturn(false);
$sharedPrompt->expects($this->once())
->method('delete');
$this->askAnythingRepository->expects($this->once())
->method('findSharedUsersAndGroupsByPromptId')
->with(1)
->willReturn(new Collection([$sharedPrompt]));
$this->askAnythingRepository->expects($this->once())
->method('createPrompt');
$data = $this->invokePrivateMethod('recreatePromptsForUserRelations', $this->askAnythingPromptService, [$prompt]);
$this->assertEquals([[1], []], $data);
}
}
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
21
1
18
2
6
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 sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id
where u.team_id = 1;
SELECT * FROM social_accounts WHERE sociable_id = 1635;
SELECT * FROM users WHERE id = 1635;
select * from teams where id = 1;
select * from users where team_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 activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;
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 automated_reports where id = 71;
SELECT * FROM automated_report_results where report_id = 71;
UPDATE automated_reports set playbook_categories = NULL 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 `automated_report_results`.* FROM `automated_report_results`
INNER JOIN `automated_reports`
ON `automated_report_results`.`report_id` = `automated_reports`.`id`
WHERE 1=1
AND `automated_report_results`.`generated_at` IS NOT NULL
# AND `automated_report_results`.`sent_at` IS NOT NULL
AND `automated_reports`.`team_id` = 1
AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$."users"')
;
SELECT * FROM automated_reports where id = 67;
SELECT * FROM automated_reports where id = 42;
SELECT * FROM users WHERE id = 143; # group 28
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;
select * from leads;
SELECT * FROM activities WHERE uuid_to_bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid; # 422003
SELECT * FROM activities WHERE id IN (16,422003);
SELECT * FROM activities where status = 'failed';
SELECT * FROM tracks WHERE activity_id = 422003;
SELECT
a.*
FROM activities a
JOIN users u ON a.user_id = u.id
WHERE
a.status = 'completed'
AND uuid_to_bin('641f1acb-16b8-42d1-8726-df52979dad0e') = u.uuid
AND a.deleted_at IS NULL
AND EXISTS (
SELECT 1 FROM tracks t
WHERE t.activity_id = a.id
AND t.type IN ('audio', 'video')
)
ORDER BY a.actual_start_time DESC
LIMIT 25;
select * from teams where id = 19;
select * from crm_configurations where provider = 'pipedrive';
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 = 19 and sa.provider = 'pipedrive';
SELECT * FROM social_accounts WHERE id = 1116;
UPDATE social_accounts SET provider_user_token = 'v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA',
provider_refresh_token = '5034113:[TELEGRAM_TOKEN]b2bfc',
expires = 1779091997,
state = 'connected'
WHERE id = 1116;
"provider_user_token": "v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA",
"provider_refresh_token": "5034113:[TELEGRAM_TOKEN]b2bfc",
"expires": 1779091997,
Socket fail to connect to host:address=(host=localhost)(port=3306)(type=primary). Connection refused
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57890
|
2037
|
24
|
2026-05-19T11:14:23.426696+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189263426_m2.jpg...
|
PhpStorm
|
faVsco.js – AskAnythingPromptServiceTest.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
|
[{"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},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
8043719072324535154
|
-8628527368849355612
|
visual_change
|
hybrid
|
NULL
|
Project: faVsco.js, menu
PhostormVIewINavicareCode Project: faVsco.js, menu
PhostormVIewINavicareCodeFV faVsco.js?9 JY-20676-delete-report-related-objectsProiectC ActivityController.ong© AskAnythingController.phpw epportunitysyncstrateavinteriace.pho© AskAnythingPromptService.phpCh AutomatedReportsServicelest.onpc) OpportunitysyncstrateayResolver.pho© ProspectCache.phpProspectSearchScope.php© AskAnythingPromptDto.php© AskJiminnyReportsController.phg© Search.php© ProspectsearchStrategyFactory.phpU ProspectsearchStrategyInterface.php© ProviderRegistrv.phpC RecordSelector.onoclass ASKAnyth1ngPromptServ1celest extends Testcasepublic function test6etAskAnythingPrompts(): void->WLLLReturn(Suser)SoromntOwnedBvlsen->exnects(Sthis->onceobT ResolveComoanvNameBvEmailtrait.ono'aetlluid')C) TimePerioditerator.oho->wal1 Returnd value:'uuid-1st-prompt');SnromntOwnedBvllsen->exnects/Sthis->onceoblImportInternallKioskv AutomatedRenorts© ActivityTypeService.phpC) Ask liminnvReportActivityservice.ong© AutomatedReportsCallbackService.ph'getTitle')->willReturn( value: 'First users prompt');$prompt0wnedByUser->expects(Sthis->once)etronralalaluteeitie'getContent')-swil1Potunnd valu'Test prompt'):$prompt0wnedByUser->expects(Sthis->onceo)©Automateakeporsservice.ong© DealStagesService.php(e) PocinientsService.php(e) DonortCort nhnl>mechod constraint'gecld->W1LLReturn valueSpromptOwnedb®U& editsexpec Accept File 38-3 () Reject File 138 €+ 4 of7 files →fmowewolallwreeLocal ChandecConsole XLooXChanges 12 tilesE.env.local app© ActivityController.php app/Http/Controllers/API@ AskAnythingPrompt.php app/Models/AskAnythingSide-by-side viewerÔ d09cbf11 tests/Unit/Services/Kiosk/AutomatedReports/AutomatedReportsServiceTest.phpc)AskAnvihinaPromotservice.ono apo/comoonent/AskAnvihing@ AskAnvthinaPromptServiceTest.php tests/Unit/Component/AskAnvthinaScenvico->undateAck.liminnvRenont/SmockRenont Smocklicen)(C) AskAnvthinaRevositorv.oho apo/Repositories© AskJiminnyReportsController.php app/Http/Controllers/API/V2C)AutomatedReportsService.oho apo/Services/Kiosk|AutomatedReports© AutomatedReportsServiceTest.php tests/Unit/Services/Kiosk/AutomatedReporC).liminnvDebuaCommand.ohn ann/console/Commandspublic function testGetAskJiminnyReportFilters: voidSmockUser = Sthis->createMock(User::class)=php logging.php config© SearchTransformer.php app/Http/TransformersUnversioned Files 9 files..env.nikilocal appE .env.other app© CanAccessAiReportsTest.php tests/Unit/Policies© CreateMockAskJiminnyReportResultCommand.php app/Console/Commands/RE favicon.ico publicE ids.txt appTe raw_sql_query.sql app© SimulateWebhooksCommand.php app/Console/Commands/Crm/HubspotM4 WEBHOOK_FILTERING_IMPLEMENTATION.md app=custom.log= laravel.log4 SF jiminny@localhost] x4 HS_local [jiminny@localhost]& console [PROD]# console [euyA console [STAGING]C) CoachinaFeedhackCoachl.Icerin.nhnPlavaroundSo jiminny vselect * from activities where 1d = 422003: # 00U04000000B6FoMACI021 A1 A18 V.2 Y6 ^SELECT ar.id, ar.uuid, ar.media type, ar.status, a.typeFROM automated_report_results arJOIN automated_reports a ON a.id = ar.report idwncke a.cype = "asklmennyLIMLI 101188 0198SELECT * FROM automated_reports where id = 71:SELECT * FROM automated report results where report id = 71:UPDATE automated reports set playbook categories = NULL where id = 68:SELECT * FROM automated_rerL resulrs where 10 = 451— 192SELECT * FROM automated_ reports order by 1d desc-SELECT * FROM automated_ report results order by 1d desc:select * from activity_searches where user_ id = 143:Socket tail to connect to host.address=(host=localhost|nort=3306/tvoe=orimarv). Connection refusedCurrent versionScenvicp->undatpAck.liminnvRenont/SmockRenontSmocklicenpublic function testUpdateAskJiminnyReportStatusThrowsWhenEnablingWithMissingReferences: voidSmockRenont = Sthic->cneateMock(AutomatedPenont..clacc)•SmockReport->expects($this->onceO)->method('isAskJiminnyReport')->willReturn(true):SmockReport->expects(Sthis->once0)->method('canExecute')->willReturn(false):Smockrevo = sthis->createMockAutomatedReportsRepos1tony::class)^SmockRepo->expects(Sthis->never())->method('update') :Sreflection = new \ReflectionClass(AutomatedReportsService::class);Soroperty = Sreflection->aetProoertv('automatedRenortsRepository'):Soronerty->setValue (SthiSthis->expectExcentionGinval.idAraumentExcent.ion:class):Sthis->expectExceptionMessage('This report is missing a saved search or prompt.')Sthis->senvice->undateAck.liminnvRenon+Status/SmockRenont true)•hell"supoont Dally • In 40 m100% 5• Tue 19 May 14:14:23AskAnythingPromptServiceTestCascadeAsk Jiminny Report M• AutomatedReportsServiceTest.phpReview Items AddressedCritical — N41 Queries (fixed)арр/нtр/Controllers/APl/u ActivityController.php +1 -1app/Models/AskAnvthina/MAskAnvthinaPromot.oho +4na/N AskAnvthinaPromotServiceTest.oho +25-2ts/- AutomatedReportsServiceTest.ono ÷47ann/Renneitnrioe/1AckAnvthinaRenneitorvnhn +7 -4 @s Codo Chudo Onuc 17 Modium+0 ..+13 -17* Reject allAccent all•01.1ditterenceUTE.8io 4 spaces...
|
57888
|
NULL
|
NULL
|
NULL
|
|
57889
|
2036
|
17
|
2026-05-19T11:14:20.357112+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189260357_m1.jpg...
|
PhpStorm
|
faVsco.js – AutomatedReportsService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 46 m100% C7Tue 19 May 14:14:20ED→Describe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
-4754846239413729230
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 46 m100% C7Tue 19 May 14:14:20ED→Describe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57888
|
2037
|
23
|
2026-05-19T11:14:17.198881+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189257198_m2.jpg...
|
PhpStorm
|
faVsco.js – AutomatedReportsService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormVIewINavicarecodeLaravelKeractorWindowmelp PhostormVIewINavicarecodeLaravelKeractorWindowmelpFV faVsco.js?9 JY-20676-delete-report-related-objectsroledeyC ActivityController.ong© AskAnythingController.php=custom.log= laravel.log4 SF jiminny@localhost] x4 HS_local [jiminny@localhost]w epportunitysyncstrateavinteriace.pho© AskAnythingPromptService.php© AutomatedReportsServiceTest.phpA console [STAGING]C) CoachinaFeedhackCoachl.Icerin.nhnc) OpportunitysyncstrateayResolver.pho© AskAnythingPromptDto.phpTx: AutovPlavaroundselect * from activities where 1d = 422003: # 00U04000000B6FoMACIProspectSearchScope.php© AskJiminnyReportsController.phg© AutomatedReportsService.php X C) AskAnythingPromptServiceTest.php© Search.php© ProspectsearchStrategyFactory.phpU ProspectsearchStrategyInterface.php© ProviderRegistrv.php1238class AutomatedReportsserviceA 100 ×3 M34 ^ Y 182pudLic tunction updateAskJ1minnykeport(Automatedkeport sreport, array saala, user pusery. array-103184C RecordSelector.onoT ResolveComoanvNameBvEmailtrait.ono5 usages© TimePerioditerator.phpD importInternallKioskv AutomatedRenortspublic function updateAskJiminnyReportStatus(AutomatedReport Sreport, bool $status): array— 180SELECT ar.id, ar.uuid, ar.mediatype, ar.status, a.typeFROM automated_report_results arJOIN automated_reports a ON a.id = ar.report idWHERE a.type = 'ask jiminny'LIMLI 101188 g1242if ($status && $report->isAskJiminnyReport() && ! $report->canExecute()) ‹throw new TnvalidAraumentExcention1244© ActivityTypeService.php1245© AskJiminnyReportActivityService.php1246©AutomatedReportsCallbackService.ph 1247message: 'This report is missing a saved search or prompt. ".'Edit the report to complete the setup before enabling it.•J290192SELECT * FROM automated_reports where id = 71:SELECT * FROM automated report results where report id = 71;UPDATE automated reports set playbook categories = NULL where id = 68:SELECT * FROM automated_rerL resulrs where 10 = 451SELECT * FROM automated_ reports order by 1d desc›₴194©Automateakeporsservice.ong© DealStagesService.php(©) PecinientsService.onp(e) DonortCort nhnl124911250$this->automatedReportsRepository->update(Sreport['status' => Sstatusl):SELECT * FROM automated_ report results order by 1d desc:select * from activity_searches where user_id = 143;Socket tail to connect to host.address=(host=localhost|nort=3306/tvoe=orimarv). Connection refusedreturn schis->transtormkeportrullvlewsreport->treshooLocal ChandesLoo Xv Changes 12 files=.env.local app© ActivityController.php app/Http/Controllers/API@ AskAnythingPrompt.php app/Models/AskAnythingT/0 +→ Side-by-side viewer -Ad09cbf11 tests/Unit/Services/Kiosk/Autd?phpXB3 B| ?c)AskAnvihinaPromotservice.ono apo/comoonent/AskAnvihing@ AskAnvthinaPromptServiceTest.php tests/Unit/Component/AskAnvthinadeclanp ictrict +unec=1)+(C) AskAnvthinaRevositorv.oho apo/Repositories© AskJiminnyReportsController.php app/Http/Controllers/API/V2C) AutomatedReportsService,oho apo/Services/Kiosk|AutomatedReoorts© AutomatedReportsServiceTest.php tests/Unit/Services/Kiosk/AuC).liminnvDebuaCommand.ohn ann/console/Commandsnamespace Tests\Unit\Services \Kiosk\AutomatedReports;use Carbon\Carbon;use Illuminate\Support\Carbon as IlluminateCarbon;use Illuminate\Contracts \Bus \Dispatcher:php logging.php config© SearchTransformer.php app/Http/TransformersUnversioned Files 9 filesuse ILLuminace vacabase cloquent bullderuse Illuminate\Database\Eloguent Relations HasMany:.env.nikilocal appE .env.other app© CanAccessAiReportsTest.php tests/Unit/Policies© CreateMockAskJiminnyReportResultCommand.php app/Console/Commands/RE favicon.ico publicEids.txt appTe raw_sql_query.sql app© SimulateWebhooksCommand.php app/Console/Commands/Crm/HubspotM4 WEBHOOK_FILTERING_IMPLEMENTATION.md appuse Iuluminace support racadesLoahuse Illuminate\Support\Facades\Storage:use Jiminny Component\AskAnything\AskAnythingPromptService:use Jiminny Component\AskAnything\Dtos\AskAnythingPromptDto:use Jiminny Component Urudenerator webhook:use Jiminny Contracts\Repositories\PlaybookCategoryRepositorv:use Jaminny contracts Revosttortes TeamPenosttory:use Jiminny\Contracts\Repositories\UserRepository:use Jiminny Excentions InvalidArgumentExcention:use Jiminny Excentions ModelNotFoundExcention:use Illuminate Suoport Collection:use Jiminny\Models\AskAnything\AskAnythingPrompt;use Jiminny Models AskAnvthinaAskAnvthinaPromotTarget:use liminny Model s Activitv Seanch.use liminnv Models AutomatedRenon+.use liminnv Models AutomatedRenon+Resul+.& console [PROD]# console [euySo jiminny v021 A1 A18 V2 V6 ^hell"supoont Dally • In 40 m100% 5• Tue 19 May 14:14:16AskAnythingPromptServiceTest vCascadeAsk Jiminny Report M• AutomatedReportsServiceTest.phpReview Items AddressedCritical — N41 Queries (fixed)арр/нtp/Controllers/APl/@ ActivityController.php +1 -1app/Models/AskAnvthina/MAskAnvthinaPromot.oho +4ests/Unit/Comoonent/AskAnvthing/1AskAnvthinaPromotServiceTest.oho +25-2ann/Renneitnrioe/1AckAnvthinaRenneitorvnhn +7 -+0 ..+13 -17* Reject allAccent alll4 @s Codo Chudo Onuc 17 ModiumCurrent versionnamesnace Tests Unit Services Krlosk AutomatedRenorts:use Carbon\Carbon;use Illuminate\Support\Carbon as IlluminateCarbon;use Illuminate \Contracts\Bus\Dispatcher:use Illuminate \Database\Eloquent Builder:use Illuminate \Database\Eloquent Relations\HasMany:use Illuminate\Support\Facades\Log:use Illuminate\Support\Facades\Storage:use Jiminny Component\AskAnything\AskAnythingPromptService:use Jiminny\Component\AskAnything\Dtos\AskAnythingPromptDto;use Jiminny Component\ UrlGenerator\Webhook:Jiminny Contracts Repositories Playbookcategorvrepos1tory:use Jiminny Contracts Repositories\ TeamRepository:Jiminny Contracts Repositories UserRepository:Jaminny Excentions ModelNotFoundExceotion:use Illuminate\Support\Collection;Jiminny Models AskAnvthina AskAnvthinaPromot.use Jiminnv|Models\AskAnvthing\AskAnvthingPromotTarget:Jiiminny Models Activitv Search:use Jiminny\Models\AutomatedReport;use Jiminny Models AutomatedRenortResult:use Jiminny\Models\Feature\FeatureEnum;use liminnv Models Groun•use Jiminny Models\Partner;WN Windsurf Teamsio 4 spaces...
|
NULL
|
-3801328987734415183
|
NULL
|
click
|
ocr
|
NULL
|
PhostormVIewINavicarecodeLaravelKeractorWindowmelp PhostormVIewINavicarecodeLaravelKeractorWindowmelpFV faVsco.js?9 JY-20676-delete-report-related-objectsroledeyC ActivityController.ong© AskAnythingController.php=custom.log= laravel.log4 SF jiminny@localhost] x4 HS_local [jiminny@localhost]w epportunitysyncstrateavinteriace.pho© AskAnythingPromptService.php© AutomatedReportsServiceTest.phpA console [STAGING]C) CoachinaFeedhackCoachl.Icerin.nhnc) OpportunitysyncstrateayResolver.pho© AskAnythingPromptDto.phpTx: AutovPlavaroundselect * from activities where 1d = 422003: # 00U04000000B6FoMACIProspectSearchScope.php© AskJiminnyReportsController.phg© AutomatedReportsService.php X C) AskAnythingPromptServiceTest.php© Search.php© ProspectsearchStrategyFactory.phpU ProspectsearchStrategyInterface.php© ProviderRegistrv.php1238class AutomatedReportsserviceA 100 ×3 M34 ^ Y 182pudLic tunction updateAskJ1minnykeport(Automatedkeport sreport, array saala, user pusery. array-103184C RecordSelector.onoT ResolveComoanvNameBvEmailtrait.ono5 usages© TimePerioditerator.phpD importInternallKioskv AutomatedRenortspublic function updateAskJiminnyReportStatus(AutomatedReport Sreport, bool $status): array— 180SELECT ar.id, ar.uuid, ar.mediatype, ar.status, a.typeFROM automated_report_results arJOIN automated_reports a ON a.id = ar.report idWHERE a.type = 'ask jiminny'LIMLI 101188 g1242if ($status && $report->isAskJiminnyReport() && ! $report->canExecute()) ‹throw new TnvalidAraumentExcention1244© ActivityTypeService.php1245© AskJiminnyReportActivityService.php1246©AutomatedReportsCallbackService.ph 1247message: 'This report is missing a saved search or prompt. ".'Edit the report to complete the setup before enabling it.•J290192SELECT * FROM automated_reports where id = 71:SELECT * FROM automated report results where report id = 71;UPDATE automated reports set playbook categories = NULL where id = 68:SELECT * FROM automated_rerL resulrs where 10 = 451SELECT * FROM automated_ reports order by 1d desc›₴194©Automateakeporsservice.ong© DealStagesService.php(©) PecinientsService.onp(e) DonortCort nhnl124911250$this->automatedReportsRepository->update(Sreport['status' => Sstatusl):SELECT * FROM automated_ report results order by 1d desc:select * from activity_searches where user_id = 143;Socket tail to connect to host.address=(host=localhost|nort=3306/tvoe=orimarv). Connection refusedreturn schis->transtormkeportrullvlewsreport->treshooLocal ChandesLoo Xv Changes 12 files=.env.local app© ActivityController.php app/Http/Controllers/API@ AskAnythingPrompt.php app/Models/AskAnythingT/0 +→ Side-by-side viewer -Ad09cbf11 tests/Unit/Services/Kiosk/Autd?phpXB3 B| ?c)AskAnvihinaPromotservice.ono apo/comoonent/AskAnvihing@ AskAnvthinaPromptServiceTest.php tests/Unit/Component/AskAnvthinadeclanp ictrict +unec=1)+(C) AskAnvthinaRevositorv.oho apo/Repositories© AskJiminnyReportsController.php app/Http/Controllers/API/V2C) AutomatedReportsService,oho apo/Services/Kiosk|AutomatedReoorts© AutomatedReportsServiceTest.php tests/Unit/Services/Kiosk/AuC).liminnvDebuaCommand.ohn ann/console/Commandsnamespace Tests\Unit\Services \Kiosk\AutomatedReports;use Carbon\Carbon;use Illuminate\Support\Carbon as IlluminateCarbon;use Illuminate\Contracts \Bus \Dispatcher:php logging.php config© SearchTransformer.php app/Http/TransformersUnversioned Files 9 filesuse ILLuminace vacabase cloquent bullderuse Illuminate\Database\Eloguent Relations HasMany:.env.nikilocal appE .env.other app© CanAccessAiReportsTest.php tests/Unit/Policies© CreateMockAskJiminnyReportResultCommand.php app/Console/Commands/RE favicon.ico publicEids.txt appTe raw_sql_query.sql app© SimulateWebhooksCommand.php app/Console/Commands/Crm/HubspotM4 WEBHOOK_FILTERING_IMPLEMENTATION.md appuse Iuluminace support racadesLoahuse Illuminate\Support\Facades\Storage:use Jiminny Component\AskAnything\AskAnythingPromptService:use Jiminny Component\AskAnything\Dtos\AskAnythingPromptDto:use Jiminny Component Urudenerator webhook:use Jiminny Contracts\Repositories\PlaybookCategoryRepositorv:use Jaminny contracts Revosttortes TeamPenosttory:use Jiminny\Contracts\Repositories\UserRepository:use Jiminny Excentions InvalidArgumentExcention:use Jiminny Excentions ModelNotFoundExcention:use Illuminate Suoport Collection:use Jiminny\Models\AskAnything\AskAnythingPrompt;use Jiminny Models AskAnvthinaAskAnvthinaPromotTarget:use liminny Model s Activitv Seanch.use liminnv Models AutomatedRenon+.use liminnv Models AutomatedRenon+Resul+.& console [PROD]# console [euySo jiminny v021 A1 A18 V2 V6 ^hell"supoont Dally • In 40 m100% 5• Tue 19 May 14:14:16AskAnythingPromptServiceTest vCascadeAsk Jiminny Report M• AutomatedReportsServiceTest.phpReview Items AddressedCritical — N41 Queries (fixed)арр/нtp/Controllers/APl/@ ActivityController.php +1 -1app/Models/AskAnvthina/MAskAnvthinaPromot.oho +4ests/Unit/Comoonent/AskAnvthing/1AskAnvthinaPromotServiceTest.oho +25-2ann/Renneitnrioe/1AckAnvthinaRenneitorvnhn +7 -+0 ..+13 -17* Reject allAccent alll4 @s Codo Chudo Onuc 17 ModiumCurrent versionnamesnace Tests Unit Services Krlosk AutomatedRenorts:use Carbon\Carbon;use Illuminate\Support\Carbon as IlluminateCarbon;use Illuminate \Contracts\Bus\Dispatcher:use Illuminate \Database\Eloquent Builder:use Illuminate \Database\Eloquent Relations\HasMany:use Illuminate\Support\Facades\Log:use Illuminate\Support\Facades\Storage:use Jiminny Component\AskAnything\AskAnythingPromptService:use Jiminny\Component\AskAnything\Dtos\AskAnythingPromptDto;use Jiminny Component\ UrlGenerator\Webhook:Jiminny Contracts Repositories Playbookcategorvrepos1tory:use Jiminny Contracts Repositories\ TeamRepository:Jiminny Contracts Repositories UserRepository:Jaminny Excentions ModelNotFoundExceotion:use Illuminate\Support\Collection;Jiminny Models AskAnvthina AskAnvthinaPromot.use Jiminnv|Models\AskAnvthing\AskAnvthingPromotTarget:Jiiminny Models Activitv Search:use Jiminny\Models\AutomatedReport;use Jiminny Models AutomatedRenortResult:use Jiminny\Models\Feature\FeatureEnum;use liminnv Models Groun•use Jiminny Models\Partner;WN Windsurf Teamsio 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57887
|
2036
|
16
|
2026-05-19T11:14:15.827926+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189255827_m1.jpg...
|
PhpStorm
|
faVsco.js – AutomatedReportsService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 46 m100% C7Tue 19 May 14:14:15ED→QDescribe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
6797771105009652910
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 46 m100% C7Tue 19 May 14:14:15ED→QDescribe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
57885
|
NULL
|
NULL
|
NULL
|
|
57885
|
2036
|
15
|
2026-05-19T11:14:11.193867+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189251193_m1.jpg...
|
PhpStorm
|
faVsco.js – AutomatedReportsService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 46 m100% C7Tue 19 May 14:14:10ED→QDescribe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
2053819826779304470
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 46 m100% C7Tue 19 May 14:14:10ED→QDescribe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57884
|
2037
|
21
|
2026-05-19T11:14:07.785244+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189247785_m2.jpg...
|
PhpStorm
|
faVsco.js – AskJiminnyReportsController.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormVIewINavicareCodeLaravelKeractorWindowmelp PhostormVIewINavicareCodeLaravelKeractorWindowmelpFV faVsco.js?9 JY-20676-delete-report-related-objectsProiectC ActivityController.ong© AskAnythingController.php© ActivityV2Controller.phpAskAnythingController.php© AskAnythingPromptService.php© AutomatedReportsServiceTest.php©ASKAnythingPromptDto.pnp© AskJIminnykeporscontroller.ongc Dealsvzcontroller.onp© OnDemandV2Controller.phpPlavlistController.phpPlavlistShareController.phpPlavlistTrackController.php© TranscriptionSummaryController.p© AskJiminnyReportsController.php X © AutomatedR©) AskAnythingPromptServiceTest.php© Search.phpclass ASkJ1minnyReportscontroller extends controller635POST /api/v2/aj-reports [api.v2.aj-reports.create]public function create(Request Srequest): JsonResponsec) UploadController.php/** @var User $user *$user = $request->userO:C)Actionitemscontroller.php@ ActivityController.phptry{c)AlcrmNotescontrolller.onoc) Basecontrolller.ono$data = $this->automatedReportsService->createAskJiminnyReport(Srequest->all, $user):C) ClientTokenController.ohoC) CrmController.ohoC) DealLevelPromotsController.ohol© DealRiskController.php© InstantMeetingController.phpc) lanquadeController nhnreturn new Jsonkesponse saata"} catch (InvalidArgumentException $e) {return new JsonResponse(['error' => $e->qetMessageO]} catch (Throwable $e) {$this->logger->error('Failed to create Ask Jiminny report', ['error' => Se-›aetMessageo.status: Response::HTTP_UNPROCESSABLE 194Local ChandesLoo Xv Changes 12 filesE.env.local app© ActivityController.php app/Http/Controllers/API@ AskAnythingPrompt.php app/Models/AskAnything© AskAnvthinaPromptService.php app/Component/AskAnvthina@ AskAnvthinaPromptServiceTest.php tests/Unit/Component/AskAnvthinaT/0 +→ Side-by-side viewer -Highlight wordsyÔ d09cbf11 app/Services/Kiosk/AutomatedReports/AutomatedReportsService.phppublic function updateAskJiminnyReportStatus(AutomatedReport $report, bool $status): array(C) AskAnvthinaRevositorv.oho apo/Repositories© Ask.JiminnvReportsController.pho app/Htto/Controllers/API/V2Sthis->automatedReportsRepository->update(Sreport, ['status' => $status]):C AutomatedReportsService.oho apo/© AutomatedReportsServiceTest.php tests/Unit/Services/Kiosk/AutomatedReporC).liminnvDebuaCommand.ohn ann/console/Commandsireturn Sthis->transformReportFullView(Sreport->freshO):php logging.php config© SearchTransformer.php app/Http/TransformersUnversioned Files 9 files..env.nikilocal appE .env.other app© CanAccessAiReportsTest.php tests/Unit/Policies@ CroatoMockAck.liminnvPonortPocultCommand.nhnann/Concolo/Commandc/DlE favicon.ico publicEids.txt appTe raw_sql_query.sql app© SimulateWebhooksCommand.php app/Console/Commands/Crm/HubspotM4 WEBHOOK_FILTERING_IMPLEMENTATION.md app= custom.log= laravel.log4 SF jiminny@localhost] x4 HS_local [jiminny@localhost]& console [PROD]# console [euyA console [STAGING]C) CoachinaFeedhackCoachl.Icerin.nhnTx: AutovPlavaroundSo jiminny vselect * from activities where 1d = 422003: # 00U04000000B6FoMACIaBTbl8XLX0 A184SELECT ar.id, ar.uuid, ar.mediatype, ar.status, a.typeFROM automated_report_results arJOIN automated_reports a ON a.id = ar.report idwncke a.cype = 'asklmennyLIMLI 101188 0SELECT * FROM automated reports where id = 71;SELECT * FROM automated report results where report id = 71;UPUAlt aucomaced reporus sec playbook cacegories = NULL where 10 = 60SELECT * FROM automated_reL resulrs where 10 = 451SELECT * FROM automated_ reports order by 1d desc›SELECT * FROM automated_ report results order by 1d desc:select * from activity_searches where user_ id = 143:Socket tail to connect to host.address=(host=localhost|nort=3306/tvoe=orimarv). Connection refusedCurrent versionpublic function updateAskJiminnyReportStatus(AutomatedReport $report, bool $status): arrayif (Sstatus && Sreport->isAskJiminnyReport() &&! Sreport->canExecute()) {throw new InvalidArgumentException('This report is missing a saved search or prompt.'Edit the report to complete the setup before enabling it.'Sthis->automatedReportsRepository-›update(Sreport, ['status' => $statusl)›return Sthis->transformReportFullView(Sreport->freshO):hell"supoont Dally • In 40 m100% 5• Tue 19 May 14:14:07AskAnythingPromptServiceTest vCascadeAsk Jiminny Report M• AutomatedReportsServiceTest.phpReview Items AddressedCritical — N41 Queries (fixed)ts/ AutomatedReportsService.php +7apo/Htto/Controllers/APV/IM ActivitvController.oho +1s/AutomatedReportsServiceTest.php +47ann/tnmnnnent/AskAnvfhinn/11AckAnvfhingPromnfService nhn +7 -4Ask anvthing (*4D4 @s Codo Chudo Onuc 17 Modium+0 ..+13 -17* Reject allAccent alll•01.1ditterenceWN Windsurf Toams 66-24UTF.8io 4 spaces...
|
NULL
|
7036867329817766312
|
NULL
|
click
|
ocr
|
NULL
|
PhostormVIewINavicareCodeLaravelKeractorWindowmelp PhostormVIewINavicareCodeLaravelKeractorWindowmelpFV faVsco.js?9 JY-20676-delete-report-related-objectsProiectC ActivityController.ong© AskAnythingController.php© ActivityV2Controller.phpAskAnythingController.php© AskAnythingPromptService.php© AutomatedReportsServiceTest.php©ASKAnythingPromptDto.pnp© AskJIminnykeporscontroller.ongc Dealsvzcontroller.onp© OnDemandV2Controller.phpPlavlistController.phpPlavlistShareController.phpPlavlistTrackController.php© TranscriptionSummaryController.p© AskJiminnyReportsController.php X © AutomatedR©) AskAnythingPromptServiceTest.php© Search.phpclass ASkJ1minnyReportscontroller extends controller635POST /api/v2/aj-reports [api.v2.aj-reports.create]public function create(Request Srequest): JsonResponsec) UploadController.php/** @var User $user *$user = $request->userO:C)Actionitemscontroller.php@ ActivityController.phptry{c)AlcrmNotescontrolller.onoc) Basecontrolller.ono$data = $this->automatedReportsService->createAskJiminnyReport(Srequest->all, $user):C) ClientTokenController.ohoC) CrmController.ohoC) DealLevelPromotsController.ohol© DealRiskController.php© InstantMeetingController.phpc) lanquadeController nhnreturn new Jsonkesponse saata"} catch (InvalidArgumentException $e) {return new JsonResponse(['error' => $e->qetMessageO]} catch (Throwable $e) {$this->logger->error('Failed to create Ask Jiminny report', ['error' => Se-›aetMessageo.status: Response::HTTP_UNPROCESSABLE 194Local ChandesLoo Xv Changes 12 filesE.env.local app© ActivityController.php app/Http/Controllers/API@ AskAnythingPrompt.php app/Models/AskAnything© AskAnvthinaPromptService.php app/Component/AskAnvthina@ AskAnvthinaPromptServiceTest.php tests/Unit/Component/AskAnvthinaT/0 +→ Side-by-side viewer -Highlight wordsyÔ d09cbf11 app/Services/Kiosk/AutomatedReports/AutomatedReportsService.phppublic function updateAskJiminnyReportStatus(AutomatedReport $report, bool $status): array(C) AskAnvthinaRevositorv.oho apo/Repositories© Ask.JiminnvReportsController.pho app/Htto/Controllers/API/V2Sthis->automatedReportsRepository->update(Sreport, ['status' => $status]):C AutomatedReportsService.oho apo/© AutomatedReportsServiceTest.php tests/Unit/Services/Kiosk/AutomatedReporC).liminnvDebuaCommand.ohn ann/console/Commandsireturn Sthis->transformReportFullView(Sreport->freshO):php logging.php config© SearchTransformer.php app/Http/TransformersUnversioned Files 9 files..env.nikilocal appE .env.other app© CanAccessAiReportsTest.php tests/Unit/Policies@ CroatoMockAck.liminnvPonortPocultCommand.nhnann/Concolo/Commandc/DlE favicon.ico publicEids.txt appTe raw_sql_query.sql app© SimulateWebhooksCommand.php app/Console/Commands/Crm/HubspotM4 WEBHOOK_FILTERING_IMPLEMENTATION.md app= custom.log= laravel.log4 SF jiminny@localhost] x4 HS_local [jiminny@localhost]& console [PROD]# console [euyA console [STAGING]C) CoachinaFeedhackCoachl.Icerin.nhnTx: AutovPlavaroundSo jiminny vselect * from activities where 1d = 422003: # 00U04000000B6FoMACIaBTbl8XLX0 A184SELECT ar.id, ar.uuid, ar.mediatype, ar.status, a.typeFROM automated_report_results arJOIN automated_reports a ON a.id = ar.report idwncke a.cype = 'asklmennyLIMLI 101188 0SELECT * FROM automated reports where id = 71;SELECT * FROM automated report results where report id = 71;UPUAlt aucomaced reporus sec playbook cacegories = NULL where 10 = 60SELECT * FROM automated_reL resulrs where 10 = 451SELECT * FROM automated_ reports order by 1d desc›SELECT * FROM automated_ report results order by 1d desc:select * from activity_searches where user_ id = 143:Socket tail to connect to host.address=(host=localhost|nort=3306/tvoe=orimarv). Connection refusedCurrent versionpublic function updateAskJiminnyReportStatus(AutomatedReport $report, bool $status): arrayif (Sstatus && Sreport->isAskJiminnyReport() &&! Sreport->canExecute()) {throw new InvalidArgumentException('This report is missing a saved search or prompt.'Edit the report to complete the setup before enabling it.'Sthis->automatedReportsRepository-›update(Sreport, ['status' => $statusl)›return Sthis->transformReportFullView(Sreport->freshO):hell"supoont Dally • In 40 m100% 5• Tue 19 May 14:14:07AskAnythingPromptServiceTest vCascadeAsk Jiminny Report M• AutomatedReportsServiceTest.phpReview Items AddressedCritical — N41 Queries (fixed)ts/ AutomatedReportsService.php +7apo/Htto/Controllers/APV/IM ActivitvController.oho +1s/AutomatedReportsServiceTest.php +47ann/tnmnnnent/AskAnvfhinn/11AckAnvfhingPromnfService nhn +7 -4Ask anvthing (*4D4 @s Codo Chudo Onuc 17 Modium+0 ..+13 -17* Reject allAccent alll•01.1ditterenceWN Windsurf Toams 66-24UTF.8io 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57883
|
2036
|
14
|
2026-05-19T11:14:07.814240+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189247814_m1.jpg...
|
PhpStorm
|
faVsco.js – AskJiminnyReportsController.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 46 m100% C7Tue 19 May 14:14:07ED→QDescribe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
2467587530510886921
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-obHomeDMsActivityFilesLater..•More>0.(ahlSupport Daily • in 46 m100% C7Tue 19 May 14:14:07ED→QDescribe what you are looking forJiminny... vscnicret# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...Nikolay Yankov6 0• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
57882
|
NULL
|
NULL
|
NULL
|
|
57882
|
2036
|
13
|
2026-05-19T11:14:06.476572+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189246476_m1.jpg...
|
PhpStorm
|
faVsco.js – AskJiminnyReportsController.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
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
{
/** @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 (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} 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
);
}
}
}...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskAnythingPromptServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskAnythingPromptServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskAnythingPromptServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Next Highlighted Error","depth":4,"on_screen":true,"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 /** @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 (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\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,"on_screen":true,"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 /** @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 (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\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}]...
|
1745849889451666716
|
-7048904252479002553
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
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
{
/** @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 (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} 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
);
}
}
}...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57881
|
2037
|
20
|
2026-05-19T11:14:02.804479+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189242804_m2.jpg...
|
PhpStorm
|
faVsco.js – AskJiminnyReportsController.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormVIewINavicareCodeLaravelKeractormelpFV faV PhostormVIewINavicareCodeLaravelKeractormelpFV faVsco.js?9 JY-20676-delete-report-related-objectsProiectC ActivityController.ong© AskAnythingController.php© ActivityV2Controller.phpAskAnythingController.php© AskAnythingPromptService.php© AutomatedReportsServiceTest.php©ASKAnythingPromptDto.png© AskJIminnykeporscontroller.ongc Dealsvzcontroller.onp© OnDemandV2Controller.phpPlavlistController.phpPlavlistShareController.phpPlavlistTrackController.php© TranscriptionSummaryController.p© AskJiminnyReportsController.php X © Automated©) AskAnythingPromptServiceTest.php© Search.phpclass ASkJ1minnyReportscontroller extends controller63 1POST /api/v2/aj-reports [api.v2.aj-reports.create]public function create(Request Srequest): JsonResponsec) UploadController.php/** @var User $user *$user = $request->userO:C)Actionitemscontroller.php@ ActivityController.phptry{c)AlcrmNotescontrolller.onoc) Basecontrolller.ono$data = $this->automatedReportsService->createAskJiminnyReport(Srequest->all, $user):C) ClientTokenController.ohoC) CrmController.ohoC) DealLevelPromotsController.ohol© DealRiskController.php© InstantMeetingController.phpc) lanquadeController nhnreturn new Jsonkesponse saata"} catch (InvalidArgumentException $e) {return new JsonResponse(['error' => $e->qetMessageO]} catch (Throwable $e) {$this->logger->error('Failed to create Ask Jiminny report', ['error' => Se-›aetMessageo.status: Response::HTTP_UNPROCESSABLE 194Local ChandesLoo Xv Changes 12 filesE.env.local app© ActivityController.php app/Http/Controllers/API@ AskAnythingPrompt.php app/Models/AskAnything© AskAnvthinaPromptService.php app/Component/AskAnvthina@ AskAnvthinaPromptServiceTest.php tests/Unit/Component/AskAnvthina< → ® Side-by-side viewer -Highlight wordsyÔ d09cbf11 app/Services/Kiosk/AutomatedReports/AutomatedReportsService.phppublic function updateAskJiminnyReportStatus(AutomatedReport $report, bool $status): array(C) AskAnvthinaRevositorv.oho apo/Repositories© Ask.JiminnvReportsController.pho app/Htto/Controllers/API/V2Sthis->automatedReportsRepository->update(Sreport, ['status' => $status]):C AutomatedReportsService.oho apo/@ AutomatedReportsServiceTest.pho tests/Unit/Services/Kiosk/AutomatedReporreturn Sthis->transformReportFullView(Sreport->freshO):C).liminnvDebuaCommand.ohn ann/console/Commandsiphp logging.php config© SearchTransformer.php app/Http/TransformersUnversioned Files 9 files..env.nikilocal appE .env.other app© CanAccessAiReportsTest.php tests/Unit/Policies@ CroatoMockAck.liminnvPonortPocultCommand.nhnann/Concolo/Commandc/DlE favicon.ico publicEids.txt appTe raw_sql_query.sql app© SimulateWebhooksCommand.php app/Console/Commands/Crm/HubspotM4 WEBHOOK_FILTERING_IMPLEMENTATION.md app= custom.log= laravel.log4 SF jiminny@localhost] x4 HS_local [jiminny@localhost]& console [PROD]# console [euyA console [STAGING]C) CoachinaFeedhackCoachl.Icerin.nhnTx: AutovPlavaroundSo jiminny vselect * from activities where 1d = 422003: # 00U04000000B6FoMACIaBTbl8XLX0 A184SELECT ar.id, ar.uuid, ar.mediatype, ar.status, a.typeFROM automated_report_results arJOIN automated_ reports a ON a.id = ar.report idwncke a.cype = 'asklmennyLIMLI 101188 0SELECT * FROM automated reports where id = 71;SELECT * FROM automated report results where report id = 71;UPUAlt aucomaced reporus sec playbook cacegories = NULL where 10 = 60SELECT * FROM automated_reL resulrs where 10 = 451SELECT * FROM automated_ reports order by 1d desc›SELECT * FROM automated_ report results order by 1d desc:select * from activity_searches where user_ id = 143:Socket tail to connect to host.address=(host=localhost|nort=3306/tvoe=orimarv). Connection refusedCurrent versionpublic function updateAskJiminnyReportStatus(AutomatedReport $report, bool $status): arrayif (Sstatus && Sreport->isAskJiminnyReport() &&! Sreport->canExecute()) {throw new InvalidArgumentException('This report is missing a saved search or prompt.'Edit the report to complete the setup before enabling it.'Sthis->automatedReportsRepository-›update(Sreport, ['status' => $statusl)›return Sthis->transformReportFullView(Sreport->freshO):hell"supoont Dally • In 40 m100% 5• Tue 19 May 14:14:02AskAnythingPromptServiceTest vCascadeAsk Jiminny Report M• AutomatedReportsServiceTest.phpReview Items AddressedCritical — N41 Queries (fixed)ts/ AutomatedReportsService.php +7apo/Htto/Controllers/APV/IM ActivitvController.oho +1ts/ AutomatedReportsServiceTest.php +47ann/tnmnnnent/AskAnvfhinn/11AckAnvfhingPromnfService nhn +7 -4Ask anvthina (*4D4 @s Codo Chudo Onuc 17 Modium+0 ..+13 -17* Reject allAccent alll•01.1ditterenceWN Windsurf Toams 66-24UTF.8io 4 spaces...
|
NULL
|
-4029481077285202369
|
NULL
|
visual_change
|
ocr
|
NULL
|
PhostormVIewINavicareCodeLaravelKeractormelpFV faV PhostormVIewINavicareCodeLaravelKeractormelpFV faVsco.js?9 JY-20676-delete-report-related-objectsProiectC ActivityController.ong© AskAnythingController.php© ActivityV2Controller.phpAskAnythingController.php© AskAnythingPromptService.php© AutomatedReportsServiceTest.php©ASKAnythingPromptDto.png© AskJIminnykeporscontroller.ongc Dealsvzcontroller.onp© OnDemandV2Controller.phpPlavlistController.phpPlavlistShareController.phpPlavlistTrackController.php© TranscriptionSummaryController.p© AskJiminnyReportsController.php X © Automated©) AskAnythingPromptServiceTest.php© Search.phpclass ASkJ1minnyReportscontroller extends controller63 1POST /api/v2/aj-reports [api.v2.aj-reports.create]public function create(Request Srequest): JsonResponsec) UploadController.php/** @var User $user *$user = $request->userO:C)Actionitemscontroller.php@ ActivityController.phptry{c)AlcrmNotescontrolller.onoc) Basecontrolller.ono$data = $this->automatedReportsService->createAskJiminnyReport(Srequest->all, $user):C) ClientTokenController.ohoC) CrmController.ohoC) DealLevelPromotsController.ohol© DealRiskController.php© InstantMeetingController.phpc) lanquadeController nhnreturn new Jsonkesponse saata"} catch (InvalidArgumentException $e) {return new JsonResponse(['error' => $e->qetMessageO]} catch (Throwable $e) {$this->logger->error('Failed to create Ask Jiminny report', ['error' => Se-›aetMessageo.status: Response::HTTP_UNPROCESSABLE 194Local ChandesLoo Xv Changes 12 filesE.env.local app© ActivityController.php app/Http/Controllers/API@ AskAnythingPrompt.php app/Models/AskAnything© AskAnvthinaPromptService.php app/Component/AskAnvthina@ AskAnvthinaPromptServiceTest.php tests/Unit/Component/AskAnvthina< → ® Side-by-side viewer -Highlight wordsyÔ d09cbf11 app/Services/Kiosk/AutomatedReports/AutomatedReportsService.phppublic function updateAskJiminnyReportStatus(AutomatedReport $report, bool $status): array(C) AskAnvthinaRevositorv.oho apo/Repositories© Ask.JiminnvReportsController.pho app/Htto/Controllers/API/V2Sthis->automatedReportsRepository->update(Sreport, ['status' => $status]):C AutomatedReportsService.oho apo/@ AutomatedReportsServiceTest.pho tests/Unit/Services/Kiosk/AutomatedReporreturn Sthis->transformReportFullView(Sreport->freshO):C).liminnvDebuaCommand.ohn ann/console/Commandsiphp logging.php config© SearchTransformer.php app/Http/TransformersUnversioned Files 9 files..env.nikilocal appE .env.other app© CanAccessAiReportsTest.php tests/Unit/Policies@ CroatoMockAck.liminnvPonortPocultCommand.nhnann/Concolo/Commandc/DlE favicon.ico publicEids.txt appTe raw_sql_query.sql app© SimulateWebhooksCommand.php app/Console/Commands/Crm/HubspotM4 WEBHOOK_FILTERING_IMPLEMENTATION.md app= custom.log= laravel.log4 SF jiminny@localhost] x4 HS_local [jiminny@localhost]& console [PROD]# console [euyA console [STAGING]C) CoachinaFeedhackCoachl.Icerin.nhnTx: AutovPlavaroundSo jiminny vselect * from activities where 1d = 422003: # 00U04000000B6FoMACIaBTbl8XLX0 A184SELECT ar.id, ar.uuid, ar.mediatype, ar.status, a.typeFROM automated_report_results arJOIN automated_ reports a ON a.id = ar.report idwncke a.cype = 'asklmennyLIMLI 101188 0SELECT * FROM automated reports where id = 71;SELECT * FROM automated report results where report id = 71;UPUAlt aucomaced reporus sec playbook cacegories = NULL where 10 = 60SELECT * FROM automated_reL resulrs where 10 = 451SELECT * FROM automated_ reports order by 1d desc›SELECT * FROM automated_ report results order by 1d desc:select * from activity_searches where user_ id = 143:Socket tail to connect to host.address=(host=localhost|nort=3306/tvoe=orimarv). Connection refusedCurrent versionpublic function updateAskJiminnyReportStatus(AutomatedReport $report, bool $status): arrayif (Sstatus && Sreport->isAskJiminnyReport() &&! Sreport->canExecute()) {throw new InvalidArgumentException('This report is missing a saved search or prompt.'Edit the report to complete the setup before enabling it.'Sthis->automatedReportsRepository-›update(Sreport, ['status' => $statusl)›return Sthis->transformReportFullView(Sreport->freshO):hell"supoont Dally • In 40 m100% 5• Tue 19 May 14:14:02AskAnythingPromptServiceTest vCascadeAsk Jiminny Report M• AutomatedReportsServiceTest.phpReview Items AddressedCritical — N41 Queries (fixed)ts/ AutomatedReportsService.php +7apo/Htto/Controllers/APV/IM ActivitvController.oho +1ts/ AutomatedReportsServiceTest.php +47ann/tnmnnnent/AskAnvfhinn/11AckAnvfhingPromnfService nhn +7 -4Ask anvthina (*4D4 @s Codo Chudo Onuc 17 Modium+0 ..+13 -17* Reject allAccent alll•01.1ditterenceWN Windsurf Toams 66-24UTF.8io 4 spaces...
|
57879
|
NULL
|
NULL
|
NULL
|
|
57880
|
2036
|
12
|
2026-05-19T11:13:59.622097+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189239622_m1.jpg...
|
PhpStorm
|
faVsco.js – AskJiminnyReportsController.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskAnythingPromptServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskAnythingPromptServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskAnythingPromptServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-1242579813573391087
|
-8420509187310384182
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-ob(ahlSupport Daily - in 47 m100% C7Tue 19 May 14:13:59• .EDHomeDMsActivityFilesLater..•More→Describe what you are looking forJiminny... vNikolay Yankov6 0scnicre# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
57878
|
NULL
|
NULL
|
NULL
|
|
57879
|
2037
|
19
|
2026-05-19T11:13:56.102268+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189236102_m2.jpg...
|
PhpStorm
|
faVsco.js – AskJiminnyReportsController.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions...
|
[{"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},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.098071806,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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.8194814,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskAnythingPromptServiceTest","depth":6,"bounds":{"left":0.83477396,"top":0.019952115,"width":0.080784574,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"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},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
4974519233973743475
|
-4022622654610547319
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
PhpStormFV faVsco.js vProjectViewINavicareCode%9 JY-20676-delete-report-related-objeLaravelKeractor© ActivityV2Controller.php©AskAnythingController.php© AskJiminnykeporscontroller.ong© DealsV2Controller.phpAskAnytingPromptservice.orgE custom.logA console [STAGING]E laravel.log4 SF jiminny@localhost] xC) CoachinaFeedhackCoachl.Icerin.nhnA HS_Jocal [jiminny@localhost]A console [PROD]# console [euy©ASKAnythingPromptDto.png© AskJiminnyReportsController.php x© Automat© AskAnythingPromptServiceTest.php© Search.phpclass ASkJ1minnyReportscontroller extends controllerpublic function togglestatus(Request Srequest, string $uvid): JsonResponseif ($this->isNotOwnedByUser(Sreport, Suser)) €184return new JsonResponse(['error' => 'Report not found'],status: Response::HTTP_NOT_FOUN 185186Plavaroundselect * from activities where 1d = 422003- # 00U0400000nB6FoMACIfajiminny=| 021 41 418 X2 X6 ASELECT ar.ig, ar.wid, ar.nedidatype, ar.status, a.tYRgFROM automated_report_results arJOIN automated_reports a ON a.id = ar.cepert.idWHERE a.type = 'ask_jiminny'LIMIT 10;Sdata = Sthis-›automatedReportsService->updateAskJiminnyReportStatus(sreporc,(bool) Srequest->input(key:) 'enabled'),188SELECT * FROM automated_reports where id = 71;SELECT * FROM automated_report_results where report.id = 71;UPDATE automated_reports set playbook categories = NULL where id = 68;SELECT * FROM automated_report_results where id = 275;192© LayoutManagementController.php© LiveFeedController.php© MeetingsController.php© MessageController.php©MetadataController.php© MobileSettingsController.php© MomentController.php© NudgeController.php© NumberAllocatorController.php© OrganizationLicensesController.phpOrganizationMembersController.php© OrganizationRetentionPolicyController);© OrganizationRolesController.php© OrganizationSyncController.php@ PartnerController.ohr© PhoneNumberController.php€ PlavbackController.ohp© PlaylistController.phpg ScimController.oho©SidekickController.phpTEEE26s (e>@ SoftnhoneController.nhnC) Ssocontroller oho© SubscriptionController.phpC) TeamAiAutomationController.nhn190)191192C) TeamAiConteytController.nhnl©TeamController.php© TeaminsightsController.php193 (gg›221© TranscriptionController.php) TranciationControllor [EMAIL]© VocabularyController.php222 ((g>253Pushed 1 commit to origin/JY-20676-delete-report-related-objects // View pull request (56 minutes ago)return new sonkesponse soata)"f catch (ModelNotFoundException $e) 1return new JsonResponse(l'error' => $e->getMessage()],status: Response: :HTTP_NOT_FOUND);catch (InvalidAgumentException se) Hlreturn new JsonResponse(['error' => $e->getMessage()],status: Response: :HTTP_UNPROCESSABLE_197f catch (Throwable Se) 1194195196198$this->logger->error('Failed to toggle Ask liminny report status', I= $e->getMessage(),'user_id' = $user->getId(),SELECT * FROM automated_reports order by id desc;SELECT * FROMautomated_ reportresults order by 1d desc:select * from activity_searches where user_id = 143;SELECT"automated_report_results' .* FROM "automated_report_resultsINNER JOIN automated_reportsautomated_report_results'. 'report_id' = 'automated_reports'."id'nse(l'error' »> 'Failed to toggle report status'],status: Response::HTTP_INTERNAL_SERVER_ERROR200201203204205206207208209automated_report_results'.'generated_at' IS NOT NULL"automated_report_results'. 'sent_at' IS NOT NULLANNautomated_reports'.'team_id' = 1AND JSON_CONTAINS( automated_reports'. 'recipients', 143, "$."userg"')te t a dtery pre.,GET /api/v2/aj-reports (api.v2.aj-reports.list)public function list(Request Srequest): JsonResponsef..,211212SELECT * FROM automated_reports where id = 67;SELECT * FROM automated_reports where id = 42;SELECT * FROM users WHERE id = 143; # group 28select * from teams where id = 3143;select * from crm_configurations where id = 500;select * from users where name = 'Integration Account'; # 1695SELECT * FROMsocial_accounts WHERE sociable_id = 1695;* Cet a single Ask Jininny report.GET /api/v2/aj-public function get(Request Srequest, string $uuid): JsonResponse(....214215216217218219220select * from activities where crm_configuration_id = 39and recording_state = 'recorded' and duration > 60and status = 'completed' and actual_start_time >= ^2025-12-01';SELEC * FROM activities WHERE uuid to bind'458c/915-6914-4000-6083-5687632629569 = uuilds223224select * from leadsiGET laoi/v2lai-renorts/uuidY/renorts-count faoi.v2.ai-renorts.renorts-countl1usaaepublic function getReportsCount(Request Srequest, string Suuid): JsonResponsef...}SELECT * FROM activities WHERE uuid to bind'f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid: # 422003SELECT * FROM activities WHERE id IN (16,422003);Socket fail to connect to host:address=(host=localhost) (port=3306)(type=primary). Connection refused* Delete an Ask Jiminny report.• supoont Dally • In 47 m100% 5&• Tue 19 May 14:13:55U AskAnythingPromptServiceTest ~CascadeAsk Jiminny Report M+0 ..b. Ada service-level tests tor updateaskJ 1minnykeportstatus validationexplorea Automateakeporisservicelest.pnp and searchea updateAskJiminnykeportstatusThought for 2s›AutomatedReportsServiceTest.phpInoughtsSearched function transformReportFullView in app/Services/Kiosk/AutomatedReports/AutomatedReportsService.php (1) >Thought for 1s• Autor+13 -17review tems A.cressecCritical — N+1 Queries (Tixed)Saved searches - ActivityController.php:1100 now eager-loads via ->withCount('automatedReports') , and SearchTrPrompts - moved loadCount ('automatedReports') into AskAnythingRepository-php:94-100 (single batched countquery for the whole list). The AskAnvthinaPromot::getHasRenortso accessor now orefers automated renorts countlModerate — Business loqic moved to serviceAutonatedRenortsService.ohv:1240-1252 now contains the quard and throws InvalidArqumentExcention . The controllenumentException → 422еторемеопесеПеоееАПОАОРОПЕОЕ ЕеВЕЕООТЕСОЛОТОТа СОАООвПОТОрИИсс ВЕшОЕО аТаВс ЛаТа1а ш ЕModerate - Tests addedunrows ano updatel) Is never called.• testUpdateAskJiminnvReportStatusDoesNotVa GidatewhenDisabUina — verifies disablina bvoasses the validationentirely and proceeas to updatedid not add controller tests oer vour "no unit tests for controllers" rule: the service-level coverage exercises the samelogic.)Minor - create() returns has reports: falseAskAnvthinaPromotService.oho:106 now passes false exolicitlv. Uodated testCreateAskAnvthingPromotwithTwousens to match.Minor - onBeforeDelete only on on_demandNat channod in thic round — flannod for confirmatinn Currontlu anlu an domand nramnte can ho wirod to Ack liminnvann/Httn/Trancformere/M SoarchTrancformer nhn1ts/mAutomatedRenorteService.ohn t7aoo/Htto/Controllers/AP|/iM ActivitvController.ohv +1-11AskAnythingPromptServiceTest.php +25-2tnotefl leit/Coricce/VinollAutomotodDonarte/GAutomotodDonarteCorixoToot.nhn.1hReiect alllAccent alliAsk anvthina 884-L)<> Code Claude Qnus 4.7 MediumW Windsurf Teams146-48f?4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57878
|
2036
|
11
|
2026-05-19T11:13:54.489032+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189234489_m1.jpg...
|
PhpStorm
|
faVsco.js – AskJiminnyReportsController.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskAnythingPromptServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskAnythingPromptServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskAnythingPromptServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
250910524120470007
|
-8996970489369621568
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-ob(ahlSupport Daily - in 47 m100% C7Tue 19 May 14:13:54• .EDHomeDMsActivityFilesLater..•More→Describe what you are looking forJiminny... vNikolay Yankov6 0scnicre# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57877
|
2037
|
18
|
2026-05-19T11:13:52.618343+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189232618_m2.jpg...
|
PhpStorm
|
faVsco.js – AskJiminnyReportsController.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:...
|
[{"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},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.098071806,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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.8194814,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskAnythingPromptServiceTest","depth":6,"bounds":{"left":0.83477396,"top":0.019952115,"width":0.080784574,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false}]...
|
-1242579813573391087
|
-8420509187310384182
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
PhostormProiectViewINavicareCodeLaravelKeractorFV faVsco.js°9 JY-20676-delete-report-related-objects=custom.log= laravel.log4 SF jiminny@localhost] x4 HS_local [jiminny@localhost]© ActivityV2Controller.phpAskAnythingController.php© AskAnythingPromptService.php© AutomatedReportsServiceTest.phpA console [STAGING]© CoachingFeedbackCoachUserln.phpAsKAnythingPromptDto.pngTx: Auto vPlavaround© AskJiminnykeporscontroller.ongselect * fromactivities where 1d = 422003- # 00U0400000nB6FoMACIc Dealsvzcontroller.onpAskJiminnyRer|© Auto!© Search.php© OnDemandV2Controller.phpclass ASkJ1minnyReportsController extends controller182PlavlistController.phppublic function togglestatus(Request Srequest, string $uuid): JsonResponsePlavlistShareController.phpPlavlistTrackController.php© TranscriptionSummaryController.pl 135if (Sthis->isNot0wnedByUser(Sreport, $user)) 1return new JsonResponse(['error' => 'Report not found'],status: Recnonce.•HTTP NOT SOUN 185136SELECT ar.id, ar.uuid, ar.mediatype, ar.status, a.typeFROM automated_report_results arJOIN automated_reports a ON a.id = ar.report.idWHERE a.type = 'ask_ jiminny'LIMIT 10:c) UploadController.phpC)Actionitemscontroller.php@ ActivitvController.phrSenabled = (bool) Srequest->input('enabled');Accept Reject188 0c)AlcrmNotescontrolller.onoif (Senabled && Sreport->isAskJiminnyReport( && ! $report->canExecuteO) {c) Basecontrolller.onoSELECT * FROM automated reports where id = 71;SELECT * FROM automated report results where report id = 71;UPDATE automated reports set playbook categories = NULL where id = 68:SELECT * FROM automated report_ results where id = 275C) ClientTokenController.ohoC) CrmController.ohoC) DealLevelPromotsController.ohoC) DealRiskController.ohoreturn new JsonResponsed['error' 3> Serror),CESSARLE ENTTTYSELECT * FROM automated_reports order by id desc;SELECT * FROMautomated_reportresults order by 1d desc:select * from activity_searches where user_id = 143;© InstantMeetingController.phpc) lanquadeController nhn1196© LayoutManagementController.phpSELENTautomated renort results * FRiM 'automated remort resultsi© LiveFeedController.phpSdata = Sthis->automatedRenortsService->uodateAskJiminnvRenortStatusd© MeetingsController.php© MessageController.phpSreport,thool) Srpquest->innutd kev "enahled!)200automated remort results', renort id' =automated reoorts'.'1di© MetadataController.phpautomated renort results' generated at' IS NOT NULLI© MobileSettingsController.php© MomentController.php€ NudgeController.php00 NumherAllocatorController.php€ OrganizationLicensesController.php€ OrganizationMembersController.php© OrganizationRetentionPolicyControllerc) OrganizationRolescontroller.phgreturn new JsonResponse(Sdata);} catch (ModelNotFoundException $e) f205return new JsonResponse(['error' => $e->getMessageO]status: Resnonce. • HTTP NOT cOlINn)} catch (InvalidArgumentException $e) {AccentReiect207return new JsonResponse(['error' => $e->getMessageO]status: Response::HTTP_UNPROCESSABLE_.ong} catch (Throwable $e) {Sthis->loqger->error('Failed to toggle Ask Jiminny report status'. ['error' => Se->qetMessageO.211'user id' => Suser-›getId.'uuid' => Suuid213automated_report_results.sent_at IS NOT NULLautomated nenonts' "toam id' = 1AND ISON CONTATNS('automated nenonte' "neciniente'. 147 Id lucengll)SELECT * FROM automated_reports where id = 67:SELECT * FROM automated_reports where id = 42;SELECT * FROM users WHERE id = 143; # group 28c) Organizationsynccontroller.pho@ PartnerController.ohrC) PhoneNumberController.ohv@ PlavbackController.ohpPlavlistController.ohp@ ScimController.php@ SidekickController.ohng SoftohoneController.nhnC) Ssocontroller ohoC) SubscrintionController.nhnl215return new JsonResponsed['error' => 'Failed to toggle report status'],status: Response::HITP INTERNAL SERVER ERRORC) TeamAiAutomationController.nhn217218219220221C) TeamAiConteytController.nhnlg) TeamController nhn© TeaminsightsController.php© TranscriptionController.php) TranciationControllor nhnl© UserController.phpVocabularyController.php* List all Ask Jiminny reports.164*/GET lanilv2 lai-renorts fani v2 ai-renorts lictl165 0 >public functiqn list (Reguest Accept File a= nResB8aSflie asea + 2 of 9 files →select * from teams where id = 3143:select * from crm_confiqurations where id = 500:select * from users where name = 'Integration Account': # 1695SELECT * FROMsocial accounts WHERE sociable id = 1695:select * from activities where crm_configuration id = 39and recording state = 'recorded' and duration > 60and status = 'completed' and actual start time >= 12025-12-01'•SELECT * FROM activities WHERE uuid to bin(•458cf915-6914-4000-b083-568763262956') = uuidiselect * from leadsiSELECT * FROM activities WHERE uuid to bind'f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid: # 422003SELECT * FROM activities WHERESocket fail to connect to host:address=(host=localhost) (port=3306)(tvpe=primarv). Connection refusedDuched 1 commit to oriain/IV.20676-delete-renort-rolated-ohiectc // View null reauect (56 minutes aao)• supoont Dally • In 47 m100% 5• Tue 19 May 14:13:52AskAnythingPromptServiceTest v& console [PROD]# console [euyCascadeAsk Jiminny Report M+0 ..So jiminny vb. Ada service-level tests tor updateAskJ 1minnykeportstatus validation021 A1 A18 V.2 V6 ^explorea Automateakeporisservicelest.pnp and searchea updateAskJiminnykeportstatusThought for 2sAutomatedReportsServiceTest.phpInoughtsSearched tunction transtormPeportFUllView in aoo/Services/Kiosk/AutomatedReoorts/AutomatedReoortsService.ono t)Thought for 1s• Autor+13 -17review tems A.cressecCritical — N+1 Queries (Tixed)Saved searches - ActivityController.php:1100 now eager-loads via ->withCount('automatedReports') , and SearchTrPrompts - moved loadCount ('automatedReports') into AskAnythingRepository•php:94-100 (single batched countquery for the whole list). The AskAnvthinaPromot::getHasRenortso accessor now orefers automated renorts countlModerate — Business loqic moved to serviceAutonatedRenortsService.ohv:1240-1252 now contains the quard and throws InvalidArqumentExcention . The controllenumentException → 422еторемеопесеПеоееАПОАОРОПЕОЕ ЕеВЕЕООТЕСОЛОТОТа СОАООвПОТОрИИсс ВЕшОЕО аТаВс ЛаТа1а ш ЕModerate - Tests addedunrows ano updatel) Is never called.• testUpdateAskJiminnvReportStatusDoesNotVa GidatewhenDisabUina — verifies disablina bvoasses the validationentirely and proceeas to updatedid not add controller tests oer vour "no unit tests for controllers" rule: the service-level coverage exercises the samelogic.)Minor - create() returns has reports: falseAskAnvthinaPromotService.oho:106 now passes false exolicitlv. Uodated testCreateAskAnvthingPromotwithTwouseneta matshMinor — onBeforeDelete onlv on on demandNat channod in thic round — flannod for confirmatinn Currontlu anlu an domand nramnte can ho wirod to Ack liminnvann/Httn/Trancformere/M SoarchTrancformer nhn11ts/mAutomatedRenorteService.ohn t7aoo/Htto/Controllers/AP|/M ActivitvController.ohv +1-11AskAnythingPromptServiceTest.php +25-2tnotefl leit/Coricce/VinollAutomotodDonarte/GAutomotodDonarteCorixoToot.nhn.7Accent alliAsk anvthina 884-L)<> Code Claude Qnus 4.7 MediumWN Windsurf TeamoPo 4 spaces...
|
57874
|
NULL
|
NULL
|
NULL
|
|
57876
|
2036
|
10
|
2026-05-19T11:13:52.618316+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189232618_m1.jpg...
|
PhpStorm
|
faVsco.js – AskJiminnyReportsController.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
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
{
/** @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 (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} 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...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskAnythingPromptServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskAnythingPromptServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskAnythingPromptServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.016666668,"height":0.02111111},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.025555555},"on_screen":false,"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},"on_screen":false,"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 /** @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 (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\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,"on_screen":true,"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 /** @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 (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\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":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"on_screen":true,"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}]...
|
-1020255159177156191
|
-7048904252479002553
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
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
{
/** @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 (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} 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...
|
57875
|
NULL
|
NULL
|
NULL
|
|
57875
|
2036
|
9
|
2026-05-19T11:13:51.491072+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189231491_m1.jpg...
|
PhpStorm
|
faVsco.js – AskJiminnyReportsController.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
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
{
/** @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 (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} 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
21
1...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskAnythingPromptServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskAnythingPromptServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskAnythingPromptServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"More Actions","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JetBrains AI","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Search Everywhere","depth":5,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"IDE and Project Settings","depth":5,"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.016666668,"height":0.02111111},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.0,"top":0.0,"width":0.015277778,"height":0.025555555},"on_screen":false,"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},"on_screen":false,"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 /** @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 (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\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,"on_screen":true,"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 /** @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 (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\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":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Explain Plan","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Browse Query History","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Open Query Execution Settings…","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"In-Editor Results","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Cancel Running Statements","depth":4,"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"21","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"}]...
|
-8422901923532594985
|
-6976846658441074105
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
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
{
/** @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 (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} 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
21
1...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57874
|
2037
|
17
|
2026-05-19T11:13:51.463564+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189231463_m2.jpg...
|
PhpStorm
|
faVsco.js – AskJiminnyReportsController.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
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
{
/** @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 (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} 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
21
1
18
2
6
Previous Highlighted Error
Next Highlighted Error...
|
[{"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},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.098071806,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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.8194814,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskAnythingPromptServiceTest","depth":6,"bounds":{"left":0.83477396,"top":0.019952115,"width":0.080784574,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"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},"on_screen":false,"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 /** @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 (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\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,"on_screen":true,"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 /** @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 (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\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":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"bounds":{"left":0.42785904,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.43650267,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.4474734,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.45611703,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.46476063,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.47573137,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.4867021,"top":0.09896249,"width":0.024268618,"height":0.01915403},"on_screen":true,"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.51329786,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"bounds":{"left":0.5242686,"top":0.09896249,"width":0.029587766,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"bounds":{"left":0.70611703,"top":0.09896249,"width":0.02825798,"height":0.01915403},"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"21","depth":4,"bounds":{"left":0.66921544,"top":0.123703115,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.68085104,"top":0.123703115,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"18","depth":4,"bounds":{"left":0.69015956,"top":0.123703115,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.7017952,"top":0.123703115,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.7117686,"top":0.123703115,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.72140956,"top":0.12210695,"width":0.00731383,"height":0.018355945},"on_screen":true,"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.7287234,"top":0.12210695,"width":0.006981383,"height":0.018355945},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-6877674007858303023
|
-7265077034592781753
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
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
{
/** @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 (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} 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
21
1
18
2
6
Previous Highlighted Error
Next Highlighted Error...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57873
|
2037
|
16
|
2026-05-19T11:13:43.063498+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189223063_m2.jpg...
|
PhpStorm
|
faVsco.js – AskJiminnyReportsController.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
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
{
/** @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 (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} 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...
|
[{"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},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.098071806,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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.8194814,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskAnythingPromptServiceTest","depth":6,"bounds":{"left":0.83477396,"top":0.019952115,"width":0.080784574,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"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},"on_screen":false,"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 /** @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 (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\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,"on_screen":true,"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 /** @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 (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\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":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"bounds":{"left":0.42785904,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.43650267,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.4474734,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.45611703,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-8686913920424376812
|
-7048904252479002553
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
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
{
/** @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 (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} 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...
|
57872
|
NULL
|
NULL
|
NULL
|
|
57872
|
2037
|
15
|
2026-05-19T11:13:40.005110+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189220005_m2.jpg...
|
PhpStorm
|
faVsco.js – AskJiminnyReportsController.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
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
{
/** @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 (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} 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...
|
[{"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},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.098071806,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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.8194814,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskAnythingPromptServiceTest","depth":6,"bounds":{"left":0.83477396,"top":0.019952115,"width":0.080784574,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"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},"on_screen":false,"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 /** @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 (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\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,"on_screen":true,"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 /** @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 (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\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":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"bounds":{"left":0.42785904,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-7474663163536819046
|
-6976846658441074617
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
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
{
/** @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 (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} 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...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57871
|
2037
|
14
|
2026-05-19T11:13:30.914390+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189210914_m2.jpg...
|
PhpStorm
|
faVsco.js – AskJiminnyReportsController.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
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
{
/** @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 (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} 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...
|
[{"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},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.098071806,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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.8194814,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskAnythingPromptServiceTest","depth":6,"bounds":{"left":0.83477396,"top":0.019952115,"width":0.080784574,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"9","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"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},"on_screen":false,"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 /** @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 (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\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,"on_screen":true,"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 /** @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 (InvalidArgumentException $e) {\n return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);\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":true,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Execute","depth":4,"bounds":{"left":0.42785904,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.43650267,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.4474734,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-644132259416762313
|
-7048904252479002553
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
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
{
/** @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 (InvalidArgumentException $e) {
return new JsonResponse(['error' => $e->getMessage()], Response::HTTP_UNPROCESSABLE_ENTITY);
} 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...
|
57870
|
NULL
|
NULL
|
NULL
|
|
57870
|
2037
|
13
|
2026-05-19T11:13:26.616585+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189206616_m2.jpg...
|
PhpStorm
|
faVsco.js – AutomatedReportsService.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections...
|
[{"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},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.098071806,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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}]...
|
-6966022010367698874
|
-564708849257816637
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
PhostormProiectVIewINavicareCodeLaravelKeractorFV faVsco.js?9 JY-20676-delete-report-related-objects© AskAnythingController.php=custom.log= laravel.log4 SF jiminny@localhost] x4 HS_local [jiminny@localhost]© AskJiminnyReportActivityService.php©Automateakeporscallbackservice.oh© Automateakeportsservice.ongcDealstagesservice.ong©) kecipientsservice.onpt keporsortonc© ReportSortDirection.phpC) KioskService.php0 MailMeetingGeneratorNotiticationW 0Auth2AskAnytningPromptserwice.ong© AutomatedReportsServiceTest.phpA console [STAGING]C) CoachinaFeedhackCoachl.Icerin.nhnTx: Auto vPlavaroundselect * fromactivities where 1d = 422003- # 00U0400000nB6FoMACISecurity• StrategyD Streaming• TeamM Telenhonv© ClientTokenGenerator.php© InsightsService.php© NumberAllocator.phpC) TextMessagingservice.ong© TwilioClient.php© TwilioClientBuilder.php© TwilioService.php© TwilioSubAccountCreator.php> D UserPilotWebhook© AbstractService.php© ActivityProviderFactory.php© ActivityService.php© ApiResponseService.php© ConferenceService.php© InsiahtSeatService.phpc)Instantmeetinaservice.onoC) ASKAnytnir© AskJin©) AskAny© Search.php class AutomatedReportsservice182puDLic tunction updateAskJ1minnykeport(Automatedkeport sreport, array saata, user suser): array -5 usages186public function updateAskJiminnyReportStatus(AutomatedReport Sreport, bool $status): array188if ($status && Sreport->isAskJiminnyReport( && ! Sreport->canExecuteO)throw new InvalidArgumentException('This report is missing a saved search or prompt.• Extract Surround // E : efore enabling it.RejectCascade ₩Command&1194['status' => Sstatusl):return schis->transtormkeportrullvlew sreport->treshoo* Validate and transform data for ASk Jiminny reports—196=1982002012 usagesprivate function validateAskJiminnvReportData(array Sdata. User Suser): array204205Validate nameSname = trim( string: Sdatal'report name'] 221261ifemntvsname))<1262thrownew_iinval.i.dAroumentsxcent.ion'Renort name is reguired'):12631264if (mb strlen($name) > 50) 12111265throw new InvalzdArgumentExceptzon( message: "Report name must be 50 characters or Less");=213(C) IoaniClient oho1266@ IpapiService.php1267215(C) ParticioantShareService.oho1268// Validate frequency (only daily, weekly, monthly for Ask Jiminny)CPlanhatService.php1269Cfnoqauency = CdatalIfnoauencv! 22 null.(c) PlavbackService.ohnl1276Sfrequency = Sdatal"fr queney 2REOUENCY DATLY, S016:: FREQUENCY WEEKLY, Se1F : FREQUENCY MONEN 21@ PlavbackVidesOnlvService.nhn1271if (! in array($frequency, SaskJiminnyFrequencies, strict: true)) «C) PlavbookCategorvService.nhnl1272throw new InvalidArqumentException( message: 'Frequency must be daily, weekly, or monthly') 219220© PlavlistGeneratorInterface.php1273© ResolveTeamCrmConnection.php1274@ SimnleThrottleService.nhn1275(C) SlackService nhnl1276© SocialAccountService.php1277© SoftPhoneService.php1278// Validate expiration dateSexpiresAt = $data['expires on'] ?? null;if (emptv(SexpiresAt)) {throw new InvalidArgumentException( message: 'Expiration date is required'):© TeamDeactivatedService.php1279(@) Toam@wnerService.onp11286Accept File %+X Reject File 4%€ + 1 of 9 files →try"ed-ahiects /| View null reauect (56 minutes aao)SELECT ar.id, ar.uuid, ar.media type, ar.status, a.typeSp0M automated nenont neculte anJOIN automated_reports a ON a.id = ar.report.idWHERE a.type = 'ask_ jiminny'LIMIT 10:SELECT * FROM automated reports where id = 71;SELECT * FROM automated report results where report id = 71;UPDATE automated reports set playbook categories = NULL where id = 68:SELECT * FROM automated report_ results where id = 275SELECT * FROM automated_reports order by id desc;SELECT * FROMautomated_reportresults order by 1d desc:select * from activity_searches where user_id = 143;select * fromSELENTautomated renort results * FRiM 'automated remort resultsiautomated remort results' renort id ='automated reoorts-'idiautomated renort results' generated at' IS NOT NULLIautomated renort results' sent at' IS NOT NULIautomated nenonts' "toam id' = 1AND ISON CONTATNS('automated nenonte' "neciniente'. 147 Id lucengll)SELECT * FROM automated_reports where id = 67:SELECT * FROM automated_reports where id = 42;SELECT * FROM users WHERE id = 143; # group 28select * from teams where id = 3143:select * from crm_confiqurations where id = 500:select * from users where name = 'Integration Account': # 1695SELECT * FROMsocial accounts WHERE sociable_ id = 1695:select * from activities where crm_ configuration_ id = 39and recording_ state = 'recorded' and duration > 60and status = 'completed' and actual start time >= 12025-12-01'•SELECT * FROM activities WHERE uuid to bin('458cf915-6914-4000-b083-568763262956') = uuidiselect * from leads›SELECT * FROM activities WHERE uuid to bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid: # 422003SELECT * FROM activities WHERE id IN (16,422003):Socket fail to connect to host:address=(host=localhost) (port=3306)(tvpe=primarv). Connection refused• supoont Dally • In 47 m100% 5• Tue 19 May 14:13:26AskAnythingPromptServiceTest v& console [PROD]# console [euyCascadeAsk Jiminny Report M+0 ..So jiminny vb. Ada service-level tests tor updateAskJ 1minnykeportstatus validation021 A1 A18 V.2 V6 ^explorea Automateakeporisservicelest.pnp and searchea updateAskJiminnykeportstatusThought for 2sAutomatedReportsServiceTest.phpInoughtsSearched tunction transtormPeportFUllView in aoo/Services/Kiosk/AutomatedReoorts/AutomatedReoortsService.ono t)Thought for 1s• Autor+13 -17review tems A.cressecCritical — N+1 Queries (Tixed)Saved searches - ActivityController.php:1100 now eager-loads via ->withCount('automatedReports') , and SearchTrPrompts - moved loadCount ('automatedReports') into AskAnythingRepository•php:94-100 (single batched countquery for the whole list). The AskAnvthinaPromot::getHasRenortso accessor now orefers automated renorts countlModerate — Business loqic moved to serviceAutonatedRenortsService.ohv:1240-1252 now contains the quard and throws InvalidArqumentExcention . The controllen(AskJiminnyReportsController.php: 126-160) is back to a thin try/catch with an added InvalidArgiumentException → 422еторемеопесеПеоееАПОАОРОПЕОЕ ЕеВЕЕООТЕСОЛОТОТа СОАООвПОТОрИИсс ВЕшОЕО аТаВс ЛаТа1а ш ЕModerate - Tests addedunrows ano updatel) Is never called.• testUpdateAskJiminnvReportStatusDoesNotVa GidatewhenDisabUina — verifies disablina bvoasses the validationentirely and proceeas to updatedid not add controller tests oer vour "no unit tests for controllers" rule: the service-level coverage exercises the samelogic.)Minor - create() returns has reports: falseAskAnvthinaPromotService.oho:106 now passes false exolicitlv. Uodated testCreateAskAnvthingPromotwithTwouseneta matshMinor — onBeforeDelete onlv on on demandNat channod in thic round — flannod for confirmatinn Currontlu anlu an domand nramnte can ho wirod to Ack liminnuann/Httn/Trancformere/M SoarchTrancformer nhn11ts/mAutomatedRenorteService.ohn t7aoo/Htto/Controllers/AP|/MActivitvController.oho +1-11AskAnythingPromptServiceTest.php +25-2tnotefl leit/Coricce/VinollAutomotodDonarte/GAutomotodDonarteCorixoToot.nhn.1hReiect alllAccent alliAsk anvthing 884-D)<> Code Claude Qnus 4.7 MediumW Windsurf Teamo1214•52 (24 charclio 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57869
|
2036
|
8
|
2026-05-19T11:13:26.630787+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189206630_m1.jpg...
|
PhpStorm
|
faVsco.js – AutomatedReportsService.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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}]...
|
-6966022010367698874
|
-564708849257816637
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-ob(ahlSupport Daily - in 47 m100% C7Tue 19 May 14:13:26• .EDHomeDMsActivityFilesLater..•More→Describe what you are looking forJiminny... vNikolay Yankov6 0scnicre# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
57868
|
NULL
|
NULL
|
NULL
|
|
57868
|
2036
|
7
|
2026-05-19T11:13:20.725380+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189200725_m1.jpg...
|
PhpStorm
|
faVsco.js – SF [jiminny@localhost]
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskAnythingPromptServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskAnythingPromptServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskAnythingPromptServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-3826067055318559026
|
-8565424269558293119
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
SlackFileEditViewGoHistoryWindowHelpDOCKER• ₴1DEV (docker)₴82APPAPP (-zslFixed 1 of 5690 files in 71.757 seconds, 60.00 MBmemory usedWhat's next:Try Docker Debug forseamless, persistent debugging tools in any container or image →Learn more at [URL_WITH_CREDENTIALS] ~/jiminny/app (JY-20676-delete-report-related-ob(ahlSupport Daily - in 47 m100% C7Tue 19 May 14:13:20• .EDHomeDMsActivityFilesLater..•More→Describe what you are looking forJiminny... vNikolay Yankov6 0scnicre# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of jimi...• Messages+. Direct messages8. Nikolay Yankov% Galya DimitrovaGo Vasil Vasilev 00. Aneliya Angelovaã. Stefka Stoyanovao Stoyan Tomova Todor Stamatov *Mario Georgiev. Nikolay Ivanovdo James GrahamStoyan TanevLukas Kovalik y…..l:: AppsJira CloudToastAdd canvas@ Files/api/v2/u3 new messagests?target=callто реално промптовете които показваме врепортите като си го сетват са само отпанорамазначи няма как да си изберат такъв промопт отcalliзначи всичко трябва да е наредLukas Kovalik 12:44 PMдаNikolay Yankov 1:12 PMима 1 code smellПушнах мои промени и качвам на neptuneLukas Kovalik 1:17 PMпромених message Serror = 'This report is missinga saved search or prompt. Edit the report tocomplete the setup before enabling it.;и пушвамNewNikolay Yankov 1:50 PMдобре, иам коментари от claudeLukas Kovalik 1:53 PMда гледам гиNikolay Yankov 2:13 PMКачих клипче тук - добре се държиhttps://github.com/jiminny/app/pull/12098Message Nikolay Yankov...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57867
|
2037
|
12
|
2026-05-19T11:13:20.440436+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189200440_m2.jpg...
|
PhpStorm
|
faVsco.js – SF [jiminny@localhost]
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'...
|
[{"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},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.098071806,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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.8194814,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskAnythingPromptServiceTest","depth":6,"bounds":{"left":0.83477396,"top":0.019952115,"width":0.080784574,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
4959269709546757893
|
-8637481863596221053
|
visual_change
|
hybrid
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
PhostormVIewINavicarecodeFV faVsco.jsg9 JY-20676-delete-rProjectMỀ CLAUDE.mdcomposer. son0 composer.lockdependency-checker.json0 dev.jsonE ids.txtE infection.json.distM-INSTALL.mdM+ INTERNAL_WEBHOOK_SETUP.mdEjiminny storageM+licenses.mom Makerileраскаqе-lock. sonE phpstan.neon.dist= phostan-baseline.neor<phpunit.xmlTe raw sal querv.saM+ README.mdLo sonar-proiect propertiesE test.py<> Untited Diadram.xmliI vetur.config.jsMI WEBHOOK FILTERING IMPLEMENTATION.mo› ib External Librariesv = Scratches and Consolesv O Database ConsolesVASUA console (EU]A DEAL RISKS [EU]A DI [EU]A EU (EU]v A jiminny@localhostA console ljiminny@localhost]A DI [jiminny@localhost]A HS_local [jiminny@localhost]&sr TiminnyolocalnostlA zoho_dev [jiminny@localhost]V A PROD& console PRODI& console 1 PRODI4DI PROD> AQA> A QAI> A QAI PRODSTAGINGA console [STAGiNGIA console 1 [STAGiNG)#uranus STAGINGI> D Extensions) M ScratchesKeractor® ActivityController.phpAskAnytningPromptserwice.ong© AutomatedReportsServiceTest.phpE custom.logA console [STAGING]E laravel.log4 SF [jiminny@localhost] x4 HS_local [jiminny@localhost]C) CoachinaFeedhackCoachl.Icerin.nhnTx: Auto vPlaygroundselect * fromactivities where id = 422003; # 00U0400000pB6fpMACA console [PROD]# console [euy©ASKAnythingPromptDto.png© AskJiminnyReportsController.phg© AutomatedReportsService.php X©) AskAnythingPromptServiceTest.php© Search.phpclass AutomatedReportsselpUDLiC tunction updateAskuamannyкeport(Automateakeport sreport, array saata, user suser): array -182fajiminny| 021 41 A18 X2 X6 A SELECT ar.ig, ar.wid, ar.nedidatype, ar.status, a.tYRgFROM automated_report_results arJOIN automated_reports a ON a.id = ar.report.idWHERE a.type = 'ask_jiminny'LIMIT 10;1public function updateAskJiminnyReportStatus(AutomatedReport $report, bool $status): arrayif ($status && Sreport->isAskJiminnyReport() && | Sreport->canExecute()) €Accept Rejectthrow new InvalidArgumentException('This report is missing a saved search or prompt.'Edit the report to complete the setup before enabling it.186188 0$this->automatedReportsRepository->update($report, ['status' => $status]);return schis->transtormkeportrullvlewsreport->treshoo190191192-193194195196=198* Validate and transform data for ASk Jiminny reportsprivate function validateAskJiminnyReportData(array $data, User Suser): arrayValidate name$name = trim( string: $data['report_name'] ??ifemntvsname))<thrownew_iinval.i.dAroumentsxcent.ion'Renort name is reguired'):204205206207-208if (mb_strlen($name) > 50) €211throw new InvalzdArgumentExceptzon( message: "Report name must be 50 characters or Less');-,13// Validate frequency (only daily, weekly, monthly for Ask Jiminny)$frequency = $data['frequency'] ?? null;215if (! in_array($frequency, $askJiminnyFrequencies, strict: true)) {throw new InvalidArgunentException(message: "Frequency must be daily, weekly, or monthly') 219SELECT * FROM automated_reports where id = 71;SELECT * FROM automated_report_results where report.id = 71;UPDATE automated_reports set playbook categories = NULL 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;SELed automated nemort results * FRiM 'automated remort resultsiautomated_report_results'."report_id' = 'automated_reports'."idautomated_report_results'.'generated_at' IS NOT NULL"automated_report_results'. 'sent_at' IS NOT NULLANNautomated_reports'.'team_id' = 1AND JSON_CONTAINS( automated_reports'. 'recipients', 143, "$."userg"')SELECT * FROM automated_reports where id = 67;SELECT * FROM automated_reports where id = 42;SELECT * FROM users WHERE id = 143; # group 28select * from teams where id = 3143;select * from crm_configurations where id = 500;select * from users where name = 'Integration Account'; # 1695SELECT * FROMsocial_accounts WHERE sociable_id = 1695;select * from activities where crm_configuration_id = 39and recording_state = 'recorded' and duration › 60and status = 'completed' and actual_start_time >= '2025-12-01';SELECT * FROM activities WHERE uuid_to_bin('458cf915-b914-4000-b083-5687b32b2956') = uuid;// Validate expiration date$expiresAt = $data['expires_on'] ?? null;if (empty($expiresAt)) {throw new InvalidArgumentException( message: 'Expiration date is required');X Reject File +*€+ 1of 9 files →222select * from leads›SELECT * FROM activities WHERE uuid_to_bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid; # 422003SELECT * FROM activities WHERE id IN (16,422003);try tSocket tail to connect to host.address=(host=localhost) nort=3306/tvoe=orimarv). Connection refused• supoont Dally • In 47 m100% 5&• Tue 19 May 14:13:19U AskAnythingPromptServiceTest ~CascadeAsk Jiminny Report M+0 ..b. Ada service-level tests tor updateAskJ 1minnykeportstatus validationexplorea Automateakeporisservicelest.pnp and searchea updateAskJiminnykeportstatusThought for 2s›AutomatedReportsServiceTest.phpInoughtsSearched function transformReportFullView in app/Services/Kiosk/AutomatedReports/AutomatedReportsService.php (1) >Thought for 1s• Autor+13 -17review tems A.cressecCritical — N+1 Queries (Tixed)Saved searches - ActivityController.php:1100 now eager-loads via ->withCount('automatedReports') , and SearchTrPrompts - moved loadCount ('automatedReports') into AskAnythingRepository•php:94-100 (single batched countquery for the whole list). The AskAnvthinaPromot::getHasRenortso accessor now orefers automated renorts countlModerate — Business loqic moved to serviceAutonatedRenortsService.ohv:1240-1252 now contains the quard and throws InvalidArqumentExcention . The controllenumentException → 422еторемеопесеПеоееАПОАОРОПЕОЕ ЕеВЕЕООТЕСОЛОТОТа СОАООвПОТОрИИсс ВЕшОЕО аТаВс ЛаТа1а ш ЕModerate - Tests addedtnrows ano updatel) Is never called.• testUpdateAskJiminnvReportStatusDoesNotVa GidatewhenDisabUina — verifies disablina bvoasses the validationentirely and proceeas to updatedid not add controller tests oer vour "no unit tests for controllers" rule: the service-leve coverage exercises the samelogic.)Minor - create() returns has reports: falseAskAnvthinaPromotService.oho: 106 now passes false exolicitlv. Uodated testCreateAskAnvthingPromotwithTwousens to match.Minor - onBeforeDelete only on on_demandNot chanaed in this round — flaaged for confirmation Currentlv only on demand nromnts can ha wired to Ack liminnviers/ @ SearchTransformer.php +1 -1Reports/[ AutomatedReportsService.php +7ann/Httn/Controllere/APVMActivitvController.ohn16AskAnvthinaPromotServiceTest.ohv +25-2tests/Unit/Services/Kiosk/AutomatedReports/ AutomatedReportsServiceTest.php +47inat@ AolAnuthinaDromntSonicochneAsk anvthina (%AL)Accept allW Windsurf Teams196.10UTF-8...
|
57866
|
NULL
|
NULL
|
NULL
|
|
57866
|
2037
|
11
|
2026-05-19T11:13:16.686582+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189196686_m2.jpg...
|
PhpStorm
|
faVsco.js – SF [jiminny@localhost]
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
|
[{"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},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
8043719072324535154
|
-8628527368849355612
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
PhostormVIewINavicarecode Project: faVsco.js, menu
PhostormVIewINavicarecodeLaravelKeractorWindowFV faVsco.js?9 JY-20676-delete-report-related-objectsroledeyC ActivityController.ong© AskAnythingController.phpMIREADME mo© AskAnythingPromptService.php© AutomatedReportsServiceTest.phpso sonar-project.properties= test.py<> Untitled Diagram.xmlIs vetur.config.jsMLWEBHOOK_ FILTERING IMPLEMENTATION.mo©ASKAnythingPromptDto.png© AskJiminnyReportsController.phg© AutomatedReportsService.php X©) AskAnythingPromptServiceTest.php© Search.phpclass AutomatedReportsservicepuDLic tunction updateAskJ1minnykeport(Automatedkeport sreport, array saata, user suser): array› ib External Librariesv = Scratches and consolesv D Database ConsolesV AEUA console (EU]A DEAL RISKS (EU]123812395 usagesA DI CUIA EU (EU]v & liminny@localhostA console [iiminny@localhost public function updateAskJiminnyReportStatus(AutomatedReport Sreport, bool $status): arrayif ($status && $report->isAskJiminnyReport() && ! $report->canExecute()) €throw new InvalidArgumentException(message: 'This report is missing a saved search or prompt.'Edit the report to complete the setup before enabling it.Accept RejectUl lminnvolocalhost4 HS local fiiminny@localhostl4 SF liminnv@localhostl12481249& zoho dev liminnv@localhostV APROD112501251$this->automatedReportsRepository->update(Sreport, ['status' => Sstatusl):+ v Accept File se* X Reject File + 2 g+ 1 of 9 files →nodunn Aabdc.dtnancSanmDanant5,17VHaw(Cnananty Gnacha).Local ChangesConcaleLog xv Changes 12 tilesE .env.local appActivitvController.phn app/Http/Controllers/AP|( → Side-by-side viewer ~Do not ianoreyHighlight words 15 g ?@ d09cbf11 app/Services/Kiosk/AutomatedReports/AutomatedReportsService.phpC)AskAnvthinaPromot.oho apo/Models/AskAnvthinaC)AskAnvthinaPromotService.oho aon/Comoonent/AskAnvthinal@ AskAnvthingPromptServiceTest.phn tests/Unit/Component/AskAnvthingpublic function updateAskJiminnyReportStatus(AutomatedReport $report, bool $status): array(C) AskAnvthinaRenositorv.oho aoo/Renositoriesi@ Ask.liminnvReportsController.phn apn/Htto/Controllers/API/N2Sthis->automatedReportsRepository->update(Sreport, ['status' => $statusl):C)AutomatedRenortsService.oho aon/Services/Kiosk/AutomatedRenorts@ AutomatedRenortsServiceTest.phn tests/Unit/Services/Kiosk/AutomatedRenorreturn sthis->transtormkeportrullvlew Sreport->treshoo^C.liminnvDehuaCommand nhn ann/Concale/Commandephp logging.php config© SearchTransformer.php app/Http/TransformersUnversioned Files 9 filesE.env.nikilocal app=.env.other app©) CanAccessAiReportsTest.php tests/Unit/Policies© CreateMockAskJiminnyReportResultCommand.php app/Console/Commands/RE favicon.ico publicE ids.txt appTe raw_sqL_query.sql app© SimulateWebhooksCommand.php app/Console/Commands/Crm/HubspotM+ WEBHOOK_FILTERING_IMPLEMENTATION.md apd= custom.log= laravel.logf or uiminny@localnosy4 HS_local [jiminny@localhost]& console [PROD]# console [euyA console [STAGING]C) CoachinaFeedhackCoachl.Icerin.nhnTx: AutoviawoneSo jiminny vselect * from activities where 1d = 422003• # 00U04000000B6FoMACl021 A1 A18 V2 V6 ^183184SELECT ar.id, ar.uuid, ar.media type, ar.status, a.typeFROM automated_report_results arJOIN automated_ reports a ON a.id = ar.report idwncke a.cype = "asklmenny186187LIMLI 101188SELECT * FROM automated reports where id = 71;SELECT * FROM automated report results where report id = 71:UPUAIt aucomaced reporus set playbook cacegories = NULL Where 10 = 60SELECT * FROM automated_rerL resulrs where 10 = 451SELECT * FROM automated_ reports order by 1d desc›SELECT * FROM automated_ report results order by 1d desc:select * from activity_searches where user_ id = 143:Socket fail to connect to host:address=(host=localhost)(port=3306)(type=primary). Connection refusedCurrent vercionpublic function updateAskJiminnyReportStatus(AutomatedReport $report, bool $status): arrayif (Sstatus && Sreport->isAskJiminnyReport && ! Sreport->canExecuteO) {throw new InvalidArgumentException('This report is missing a saved search or prompt.'Edit the report to complete the setup before enabling it.'Sthis->automatedReportsRepository->update(Sreport, ['status' => $statusl):returnSthis->transformReportFullView(Sreport->freshob:supoont Dally • In 47 m100% 5• Tue 19 May 14:13:16AskAnythingPromptServiceTest vCascadeAsk Jiminny Report Mb. Ada service-level tests tor updateAskJ 1minnykeportstatus validationexplorea Automateakeporisservicelest.pnp and searchea updateAskJiminnykeportstatus• AutomatedReportsServiceTest.phpInoughtss/wSearchtranstormer.php +1 -s/@ AutomatedReportsService.php +7app/Http/Controllers/APl/ ActivityController.php +1 -na/MAckAnvthinaPromnt.nhn dna/N AskAnvthinaPromotServiceTest.oho +25-2atedReportsServiceTest.pho ÷4710/1 AckAnvthinaPromntService nhn +7 -7+0 ..* Reject allAccept allAsk anything (&*L)+ < code Claude Opus 4.7 Medium1 difterenceW Windsurf Teams196.10UTE.9Aensod...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
57865
|
2037
|
10
|
2026-05-19T11:13:08.315412+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-19/1779 /Users/lukas/.screenpipe/data/data/2026-05-19/1779189188315_m2.jpg...
|
PhpStorm
|
faVsco.js – SF [jiminny@localhost]
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
100
3
34
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Kiosk\AutomatedReports;
use Carbon\CarbonImmutable;
use Carbon\CarbonInterface;
use Carbon\Exceptions\InvalidFormatException;
use DateTime;
use DateTimeInterface;
use DateTimeZone;
use Illuminate\Contracts\Bus\Dispatcher as BusDispatcher;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Jiminny\Component\ActivitySearch\FilterDefinition\InputTypeEnum;
use Jiminny\Component\AskAnything\AskAnythingPromptService;
use Jiminny\Component\AskAnything\Dtos\AskAnythingPromptDto;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Contracts\Repositories\PlaybookCategoryRepository;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Contracts\Repositories\UserRepository;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Exceptions\ModelNotFoundException;
use Jiminny\Jobs\AutomatedReports\RequestGenerateReportJob;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\AskAnything\AskAnythingPrompt;
use Jiminny\Models\AskAnything\AskAnythingPromptTarget;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Partner;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Repositories\AskAnythingRepository;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Repositories\GroupRepository;
use Jiminny\Repositories\SearchRepository;
use Jiminny\Repositories\StageRepository;
use Throwable;
class AutomatedReportsService
{
public const string TYPE_LOSS_ANALYSIS = 'loss_analysis';
public const string TYPE_ASK_JIMINNY = 'ask_jiminny';
/**
* Standard report types (used by kiosk for existing automated reports).
*/
// @TODO this will add filter, however if we need to control feature by FF we need conditional logic
public const array TYPES = [
['id' => 'exec_summary', 'name' => 'Exec Summary'],
['id' => 'coaching_profiles', 'name' => 'Coaching Profiles'],
['id' => 'product_feedback', 'name' => 'Product Feedback'],
['id' => self::TYPE_LOSS_ANALYSIS, 'name' => 'Loss Analysis'],
// ['id' => 'questions', 'name' => 'Questions'],
// ['id' => 'statistical_quant', 'name' => 'Statistical Quantitative'],
];
public const array ALL_TYPES = [
...self::TYPES,
['id' => self::TYPE_ASK_JIMINNY, 'name' => 'Ask Jiminny'],
];
public const string FREQUENCY_DAILY = 'daily';
public const string FREQUENCY_WEEKLY = 'weekly';
public const string FREQUENCY_MONTHLY = 'monthly';
public const string FREQUENCY_QUARTERLY = 'quarterly';
public const string FREQUENCY_ONE_OFF = 'one_off';
/**
* Frequencies for standard (non-Ask Jiminny) reports.
*/
public const array FREQUENCIES = [
['id' => self::FREQUENCY_WEEKLY, 'name' => 'Weekly'],
['id' => self::FREQUENCY_MONTHLY, 'name' => 'Monthly'],
['id' => self::FREQUENCY_QUARTERLY, 'name' => 'Quarterly'],
['id' => self::FREQUENCY_ONE_OFF, 'name' => 'One-off'],
];
/**
* Frequencies for Ask Jiminny reports.
*/
public const array ASK_JIMINNY_FREQUENCIES = [
['id' => self::FREQUENCY_DAILY, 'name' => 'Daily'],
['id' => self::FREQUENCY_WEEKLY, 'name' => 'Weekly'],
['id' => self::FREQUENCY_MONTHLY, 'name' => 'Monthly'],
];
public const string MEDIA_TYPE_PDF = 'pdf';
public const string MEDIA_TYPE_PODCAST = 'podcast';
public const array MEDIA_TYPES = [self::MEDIA_TYPE_PDF, self::MEDIA_TYPE_PODCAST];
public const array MEDIA_TYPE_OBJECT_PDF = ['id' => self::MEDIA_TYPE_PDF, 'name' => 'PDF'];
public const array MEDIA_TYPE_OBJECT_PODCAST = ['id' => self::MEDIA_TYPE_PODCAST, 'name' => 'Podcast'];
public const array MEDIA_TYPE_OBJECTS = [self::MEDIA_TYPE_OBJECT_PDF, self::MEDIA_TYPE_OBJECT_PODCAST];
public const array CALL_TYPE_CONFERENCE = ['id' => 'conference', 'name' => 'Conference'];
public const array CALL_TYPE_DIALER = ['id' => 'dialer', 'name' => 'Dialer'];
public const int SENT_REPORT_AT_HOURS = 5;
public const string PDF_KEY = 'pdf';
public const string AUDIO_KEY = 'audio';
private const array ALL_FREQUENCIES = [
['id' => self::FREQUENCY_DAILY, 'name' => 'Daily'],
['id' => self::FREQUENCY_WEEKLY, 'name' => 'Weekly'],
['id' => self::FREQUENCY_MONTHLY, 'name' => 'Monthly'],
['id' => self::FREQUENCY_QUARTERLY, 'name' => 'Quarterly'],
['id' => self::FREQUENCY_ONE_OFF, 'name' => 'One-off'],
];
private const string S3_DIR = 'reports';
private const array FILE_EXTENSIONS_VARIANTS = ['html', 'MD', 'pdf'];
private const array FILE_PODCAST_EXTENSIONS_VARIANTS = ['json', 'mp3', 'ssml'];
public function __construct(
private readonly TeamRepository $teamRepository,
private readonly GroupRepository $groupRepository,
private readonly UserRepository $userRepository,
private readonly StageRepository $stageRepository,
private readonly DealStagesService $dealStagesService,
private readonly RecipientsService $recipientsService,
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly Webhook $webhookService,
private readonly BusDispatcher $dispatcher,
private readonly ActivityTypeService $activityTypeService,
private readonly PlaybookCategoryRepository $playbookCategoryRepository,
private readonly AskAnythingPromptService $askAnythingPromptService,
private readonly SearchRepository $activitySearchRepository,
private readonly AskAnythingRepository $askAnythingRepository,
) {
}
public static function getTypes(): array
{
$types = self::TYPES;
return array_map(static function ($type) {
return $type['id'];
}, $types);
}
public static function getCallTypes(): array
{
return array_map(static function ($callType) {
return $callType['id'];
}, [self::CALL_TYPE_CONFERENCE, self::CALL_TYPE_DIALER]);
}
public static function getFrequencies(): array
{
return array_map(static function ($frequency) {
return $frequency['id'];
}, self::FREQUENCIES);
}
// front-facing structure
public function getReportEnabledFieldData(bool $value = false): array
{
return [
'id' => 'report_enabled',
'label' => '',
'inputType' => InputTypeEnum::TOGGLE,
'value' => $value,
];
}
// Organizations = Teams
public function getOrganizationFieldData(?string $value = null, bool $shortVersion = false, ?Partner $partner = null): array
{
$options = $this->getTeams(partner: $partner);
if ($shortVersion) {
return [
'id' => 'organization',
'label' => 'Organization',
'options' => $options,
];
}
return [
'id' => 'organization',
'label' => 'Organization',
'inputType' => InputTypeEnum::DROPDOWN,
'required' => true,
'placeholder' => 'Select',
'options' => $options,
'value' => $value,
'dependencies' => [
'teams',
'deal_stage_at_call',
'current_deal_stage',
'recipients',
ActivityTypeService::PLAYBOOK_CATEGORIES_KEY,
],
'dependsOn' => [],
];
}
// Teams = Groups
public function getTeamFieldData(array $options = [], array $value = [], bool $shortVersion = false): array
{
if ($shortVersion) {
return [
'id' => 'teams',
'label' => 'Team',
'options' => $options,
];
}
return [
'id' => 'teams',
'label' => 'Team',
'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,
'required' => false,
'placeholder' => 'Select',
'options' => $options,
'value' => $value, // value should be an array of objects {id, name}
'dependencies' => [ActivityTypeService::PLAYBOOK_CATEGORIES_KEY],
'dependsOn' => [],
];
}
public function getReportTypeFieldData(?string $value = null, bool $shortVersion = false, ?Team $team = null): array
{
$types = [];
if ($team instanceof Team) {
if ($team->hasFeature(FeatureEnum::AUTOMATED_REPORTS)) {
$types = self::TYPES;
}
if ($team->hasFeature(FeatureEnum::ASK_JIMINNY_REPORTS)) {
$types[] = ['id' => self::TYPE_ASK_JIMINNY, 'name' => 'Ask Jiminny'];
}
} else {
$types = self::TYPES;
}
if ($shortVersion) {
return [
'id' => 'report_type',
'label' => 'Report Type',
'options' => $types,
];
}
return [
'id' => 'report_type',
'label' => 'Report Type',
'inputType' => InputTypeEnum::DROPDOWN,
'required' => true,
'placeholder' => 'Select',
'options' => $types,
'value' => $value,
'dependencies' => [],
'dependsOn' => [],
];
}
public function getFrequencyFieldData(?string $value = null): array
{
return [
'id' => 'frequency',
'label' => 'Frequency',
'inputType' => InputTypeEnum::DROPDOWN,
'required' => true,
'placeholder' => 'Select',
'options' => self::FREQUENCIES,
'value' => $value,
'dependencies' => ['period'],
'dependsOn' => [],
];
}
public function getPeriodFieldData(?string $valueStartDate = null, ?string $valueEndDate = null): array
{
return [
'id' => 'period',
'label' => 'Select one-off period',
'inputType' => InputTypeEnum::DATE_RANGE,
'required' => true,
'placeholder' => 'Select',
'value' => ['startDate' => $valueStartDate, 'endDate' => $valueEndDate],
'queryParams' => [
'startDate' => 'start_date_period',
'endDate' => 'end_date_period',
],
'dependencies' => [],
'dependsOn' => ['frequency'],
];
}
public function getActivityTypesFieldData(?Team $team = null, array $value = [], array $teamsFilter = []): array
{
return $this->activityTypeService->getActivityTypeFieldData(team: $team, value: $value, groupIds: $teamsFilter);
}
public function getDealStageAtCallFieldData(?Team $team = null, array $value = []): array
{
return $this->dealStagesService->getDealStageAtCallFieldData(team: $team, value: $value);
}
public function getCurrentDealStageFieldData(?Team $team = null, array $value = []): array
{
return $this->dealStagesService->getCurrentDealStageFieldData(team: $team, value: $value);
}
public function getDealValueFieldData(?int $valueMin = null, ?int $valueMax = null): array
{
return [
'id' => 'deal_value',
'label' => 'Deal Value',
'inputType' => InputTypeEnum::INTEGER_RANGE,
'required' => false,
'value' => ['min' => $valueMin, 'max' => $valueMax],
'queryParams' => [
'min' => 'min_deal_value',
'max' => 'max_deal_value',
],
'dependencies' => [],
'dependsOn' => [],
];
}
public function getCallTypeFieldData(bool $conferenceOn = false, bool $dialerOn = false): array
{
$value = [];
$conferenceOn && $value[] = self::CALL_TYPE_CONFERENCE;
$dialerOn && $value[] = self::CALL_TYPE_DIALER;
return [
'id' => 'call_type',
'label' => 'Call Type',
'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,
'required' => true,
'options' => [
self::CALL_TYPE_CONFERENCE,
self::CALL_TYPE_DIALER,
],
'value' => $value,
'dependencies' => [],
'dependsOn' => [],
];
}
public function getMediaTypeFieldData(?AutomatedReport $report = null): array
{
$value = [];
if ($report) {
$value = $this->transformMediaTypes($report);
}
return [
'id' => 'media_types',
'label' => 'Export as',
'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,
'required' => true,
'options' => self::MEDIA_TYPE_OBJECTS,
'value' => $value,
'dependencies' => [],
'dependsOn' => [],
];
}
public function getCallDurationFieldData(?int $valueMin = null, ?int $valueMax = null): array
{
return [
'id' => 'call_duration',
'label' => 'Call Duration',
'inputType' => InputTypeEnum::INTEGER_RANGE,
'required' => false,
'value' => ['min' => $valueMin, 'max' => $valueMax],
'queryParams' => [
'min' => 'min_call_duration',
'max' => 'max_call_duration',
],
'dependencies' => [],
'dependsOn' => [],
];
}
public function getRecipientsFieldData(?Team $team = null, array $value = []): array
{
return $this->recipientsService->getRecipientsFieldData(team: $team, value: $value);
}
public function getJiminnyRecipientsFieldData(array $value = []): array
{
return $this->recipientsService->getJiminnyRecipientsFieldData($value);
}
public function getAdditionalPromptInputFieldData(?string $value = null): array
{
return [
'id' => 'additional_prompt_input',
'label' => 'Special requirements',
'inputType' => InputTypeEnum::TEXTAREA,
'required' => false,
'placeholder' => 'What should be the focus of the report?',
'value' => $value,
'dependencies' => [],
'dependsOn' => [],
];
}
public function getCustomReportNameFieldData(?string $value = null): array
{
return [
'id' => 'custom_name',
'label' => 'Custom report name',
'inputType' => InputTypeEnum::TEXT,
'required' => false,
'placeholder' => 'Enter custom name',
'value' => $value,
'dependencies' => [],
'dependsOn' => [],
];
}
// data providers
public function getTeams(?Partner $partner = null): array
{
$teams = $this->teamRepository->getTeamsForKiosk(status: Team::STATUS_ACTIVE, partner: $partner);
$teamData = [];
foreach ($teams as $team) {
if (! $team->hasFeature(FeatureEnum::AUTOMATED_REPORTS)) {
continue;
}
$teamData[] = $this->transformTeam($team);
}
return $teamData;
}
public function getTeamGroups(string $teamUuid): array
{
$data = [];
$team = $this->getTeam($teamUuid);
if ($team !== null) {
$groups = $team->groups()->get();
foreach ($groups as $group) {
$data[] = [
'id' => $group->getUuid(),
'name' => $group->getName(),
];
}
}
return $data;
}
public function getTeamsGroupsOptions(array $filterTeamUuids = [], ?Partner $partner = null): array
{
$data = [];
$teams = $this->getTeams(partner: $partner);
foreach ($teams as $team) {
if (! empty($filterTeamUuids) && ! in_array($team['id'], $filterTeamUuids, true)) {
continue;
}
$data[] = [
'label' => $team['name'],
'groups' => $this->getTeamGroups($team['id']),
];
}
return $data;
}
public function getTeam(string $teamUuid): ?Team
{
return $this->teamRepository->idOrUuid($teamUuid);
}
public function getTeamById(int $teamId): ?Team
{
return $this->teamRepository->find($teamId);
}
public function getGroupsUuids(AutomatedReport $report): array
{
$uuids = [];
$reportGroups = $report->getGroups();
foreach ($reportGroups as $groupId) {
if ($group = $this->groupRepository->find($groupId)) {
$uuids[] = $group->getUuid();
}
}
return $uuids;
}
public function getPlaybookCategoriesUuids(AutomatedReport $report): array
{
$uuids = [];
$playbookCategories = $report->getPlaybookCategories();
foreach ($playbookCategories as $id) {
if ($category = $this->playbookCategoryRepository->find($id)) {
$uuids[] = $category->getUuid();
}
}
return $uuids;
}
public function getDealAtCallStagesUuids(AutomatedReport $report): array
{
$uuids = [];
$reportStages = $report->getDealAtCallStages();
foreach ($reportStages as $id) {
if ($stage = $this->stageRepository->find($id)) {
$uuids[] = $stage->getUuid();
}
}
return $uuids;
}
public function getCurrentDealStagesUuids(AutomatedReport $report): array
{
$uuids = [];
$reportStages = $report->getCurrentDealStages();
foreach ($reportStages as $id) {
if ($stage = $this->stageRepository->find($id)) {
$uuids[] = $stage->getUuid();
}
}
return $uuids;
}
public function getUsersUuids(AutomatedReport $report): array
{
return $this->extractUserUuids($report->getRecipients());
}
public function getJiminnyUsersUuids(AutomatedReport $report): array
{
return $this->extractUserUuids($report->getJiminnyRecipients());
}
/**
* @param array<string, mixed> $recipients
*/
private function extractUserUuids(array $recipients): array
{
$userIds = $recipients['users'] ?? [];
return collect($userIds)
->map(fn ($id) => $this->userRepository->find((int) $id))
->filter()
->map(fn (UserContract $user) => $user->getUuid())
->values()
->all();
}
// get mail data
public function getRecipientUsers(AutomatedReport $report): array
{
return $this->buildRecipientUsers($report->getRecipients());
}
/**
* @return array<UserContract>
*/
public function getRecipientUserObjects(AutomatedReport $report): array
{
$userIds = $report->getRecipients()['users'] ?? [];
return collect($userIds)
->map(fn ($id) => $this->userRepository->find((int) $id))
->filter()
->values()
->all();
}
private function getJiminnyRecipientUsers(AutomatedReport $report): array
{
return $this->buildRecipientUsers($report->getJiminnyRecipients());
}
/**
* @param array<string, mixed> $recipients
*/
private function buildRecipientUsers(array $recipients): array
{
$userIds = $recipients['users'] ?? [];
return collect($userIds)
->map(fn ($id) => $this->userRepository->find((int) $id))
->filter()
->map(fn (UserContract $user) => [
'email' => $user->getEmailAddress(),
'name' => $user->getName(),
'timezone' => $user->getTimezone()->getName(),
])
->values()
->all();
}
public function getValidRecipientUsers(AutomatedReport $report, bool $includeJiminny = false): array
{
if ($report->isAskJiminnyReport()) {
$recipients = $this->resolveAskJiminnyRecipients($report);
} else {
$recipients = $this->getRecipientUsers($report);
if ($includeJiminny) {
$recipients = array_merge($recipients, $this->getJiminnyRecipientUsers($report));
}
}
$emails = [];
return array_values(array_filter(
$recipients,
static function ($recipient) use (&$emails) {
if (empty($recipient['email']) || in_array($recipient['email'], $emails, true)) {
return false;
}
$emails[] = $recipient['email'];
return true;
}
));
}
private function resolveAskJiminnyRecipients(AutomatedReport $report): array
{
$recipients = [];
$creator = $report->getCreator();
if ($creator !== null) {
$recipients[] = [
'email' => $creator->getEmailAddress(),
'name' => $creator->getName(),
'timezone' => $creator->getTimezone()->getName(),
];
}
return array_merge(
$recipients,
$this->buildRecipientUsers($report->getRecipients()),
$this->getGroupRecipientUsers($report),
);
}
private function getGroupRecipientUsers(AutomatedReport $report): array
{
$users = [];
foreach ($report->getGroups() as $groupId) {
$group = $this->groupRepository->find($groupId);
if ($group === null) {
continue;
}
foreach ($group->getMembers() as $member) {
$users[] = [
'email' => $member->getEmailAddress(),
'name' => $member->getName(),
'timezone' => $member->getTimezone()->getName(),
];
}
}
return $users;
}
public function getReportTypeName(AutomatedReportResult $report): string
{
$type = $report->getReport()->getType();
$getType = $this->transformReportType($type);
return $getType['name'];
}
public function getReportPeriodName(AutomatedReportResult $report): string
{
$from = $report->getFromDate();
$to = $report->getToDate();
$frequency = $report->getReport()->getFrequency();
if ($from === null || $to === null) {
if (! $report->getReport()->isAskJiminnyReport()) {
$invalidPeriod = $from === null ? 'from' : 'to';
throw new ApplicationException('Report period is invalid: ' . $invalidPeriod);
}
$timezone = $report->getReport()->getCreator()?->getTimezone();
$period = $this->calculateFromAndToDatePeriod($frequency, timezone: $timezone);
$from = $period['fromDate'];
$to = $period['toDate'];
}
return $this->formatReportPeriodName($frequency, $from, $to);
}
private function formatReportPeriodName(string $frequency, Carbon $from, Carbon $to): string
{
$fromYear = $from->format('Y');
$toYear = $to->format('Y');
$differentYears = $fromYear !== $toYear;
switch ($frequency) {
case self::FREQUENCY_DAILY:
return $from->format('j M Y');
case self::FREQUENCY_QUARTERLY:
// 'Jan-Mar 2025' or 'Nov 2024-Jan 2025' if years differ
$startMonth = $from->format('M');
$endMonth = $to->copy()->subMonth();
$endMonthName = $endMonth->format('M');
$endMonthYear = $endMonth->format('Y');
if ($differentYears) {
return "{$startMonth} {$fromYear} - {$endMonthName} {$endMonthYear}";
}
return "{$startMonth} - {$endMonthName} {$toYear}";
case self::FREQUENCY_MONTHLY:
// 'May 2025' - monthly reports are always within the same year
return $from->format('M Y');
case self::FREQUENCY_WEEKLY:
// '4 - 8 Aug 2025', '27 Oct - 3 Nov 2025', or '28 Dec 2024 - 3 Jan 2025' if years differ
$startDay = $from->format('j');
$endDay = $to->format('j');
$startMonth = $from->format('M');
$endMonth = $to->format('M');
if ($differentYears) {
return "{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}";
}
if ($startMonth !== $endMonth) {
return "{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}";
}
return "{$startDay} - {$endDay} {$endMonth} {$toYear}";
case self::FREQUENCY_ONE_OFF:
// '2 May-31 May 2025' or '15 Dec 2024-15 Jan 2025' if years differ
$startDay = $from->format('j');
$startMonth = $from->format('M');
$endDay = $to->format('j');
$endMonth = $to->format('M');
// If same month and year, use a format like '2-31 May 2025'
if ($startMonth === $endMonth && ! $differentYears) {
return "{$startDay} - {$endDay} {$startMonth} {$toYear}";
}
// If different years, include both years
if ($differentYears) {
return "{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}";
}
// Same year but different months
return "{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}";
default:
// Default format for unknown frequencies
return $from->format('j M Y') . ' - ' . $to->format('j M Y');
}
}
public function getReportTeamsName(AutomatedReportResult $report): string
{
$groups = $report->getGroups();
if (empty($groups)) {
return 'All';
}
// Get group names from repository
$groupNames = [];
foreach ($groups as $groupId) {
$group = $this->groupRepository->find($groupId);
if ($group) {
$groupNames[] = $group->getName();
}
}
if (count($groupNames) === 1) {
// Single team format
$teamsName = $groupNames[0];
} else {
// Multiple teams format
$teamsName = implode(', ', $groupNames);
}
return $teamsName;
}
public function getReportFileName(AutomatedReportResult $report): string
{
$customName = $report->getReport()->getCustomName();
$periodName = $this->getReportPeriodName($report);
$filenameSuffix = $this->getFilenameSuffix($report);
if ($customName) {
if ($filenameSuffix) {
$customName .= " {$filenameSuffix}";
}
return $this->sanitizeFileName("{$customName} - {$periodName}");
}
$baseName = $this->getReportTypeName($report);
if ($filenameSuffix) {
$baseName .= " {$filenameSuffix}";
}
return $this->sanitizeFileName("{$baseName} - {$periodName} - {$this->getReportTeamsName($report)}");
}
public function getReportFileNameWithExtension(AutomatedReportResult $result): string
{
$extension = $this->getMediaTypeMetadata($result)['extension'];
return $this->getReportFileName($result) . '.' . $extension;
}
public function sanitizeFileName(string $fileName): string
{
return str_replace(['/', '\\'], '-', $fileName);
}
public function isUserRecipientOfReport(User $user, AutomatedReport $report): bool
{
$recipientIds = array_map('intval', $report->getRecipients()['users'] ?? []);
if (in_array($user->getId(), $recipientIds, true)) {
return true;
}
if ($report->isAskJiminnyReport()) {
$groupId = $user->getGroupId();
if ($groupId !== null && in_array($groupId, $report->getGroups(), true)) {
return true;
}
}
return false;
}
public function transformReportResults(Collection $automatedReportResults): array
{
$data = [];
foreach ($automatedReportResults as $automatedReportResult) {
/** @var AutomatedReportResult $automatedReportResult */
$report = $automatedReportResult->getReport();
$createdBy = $report->getCreator();
$creator = [
'id' => $createdBy?->getUuid(),
'name' => $createdBy?->getName(),
'email' => $createdBy?->getEmailAddress(),
'photoUrl' => $createdBy?->getPhotoUrl(),
];
$data[] = [
'id' => $automatedReportResult->getUuid(),
'name' => $automatedReportResult->getName(),
'frequency' => $this->transformFrequency($report->getFrequency()),
'recipients' => $this->buildRecipients($report),
'report_type' => $this->transformReportType($report->getType()),
'media_type' => $automatedReportResult->getMediaType(),
'downloadUrl' => $this->generateReportResultDownloadUrl($automatedReportResult),
'viewUrl' => $this->generateReportResultViewUrl($automatedReportResult),
'generated_at' => $automatedReportResult->getGeneratedAt()?->toIso8601String(),
'creator' => $creator,
];
}
return $data;
}
private function buildRecipients(AutomatedReport $report): array
{
$creatorUuid = $report->getCreator()?->getUuid();
$recipients = array_values(array_filter(
$this->transformRecipients($report->getRecipients()),
static fn (array $recipient): bool => $recipient['id'] !== $creatorUuid,
));
if (! $report->isAskJiminnyReport()) {
return $recipients;
}
return [
...array_values($this->transformGroups(team: $report->getTeam(), groupsIds: $report->getGroups())),
...$recipients,
];
}
public function hasCallTypeConference(AutomatedReport $report): bool
{
return in_array(self::CALL_TYPE_CONFERENCE['id'], $report->getCallTypes(), true);
}
public function hasCallTypeDialer(AutomatedReport $report): bool
{
return in_array(self::CALL_TYPE_DIALER['id'], $report->getCallTypes(), true);
}
// transformers
private function transformTeam(Team $team): array
{
if (! $team->hasFeature(FeatureEnum::AUTOMATED_REPORTS)) {
return [];
}
return [
'id' => $team->getUuid(),
'name' => $team->getName(),
];
}
private function transformReportFullView(AutomatedReport $report): array
{
$base = $this->transformReportBase($report);
return $report->getType() === self::TYPE_ASK_JIMINNY
? $base + $this->transformAskJiminnyFields($report)
: $base + $this->transformStandardReportFields($report);
}
private function transformReportBase(AutomatedReport $report): array
{
return [
'id' => $report->getUuid(),
'organization' => $this->transformOrganization(team: $report->getTeam()),
'report_type' => $this->transformReportType($report->getType()),
'frequency' => $this->transformFrequency($report->getFrequency()),
];
}
private function transformStandardReportFields(AutomatedReport $report): array
{
$team = $report->getTeam();
return [
'report_enabled' => $report->getStatus(),
'start_date_period' => $report->getFrom()?->format('Y-m-d H:i:s'),
'end_date_period' => $report->getTo()?->format('Y-m-d H:i:s'),
'deal_value_min' => $report->getDealValueMin(),
'deal_value_max' => $report->getDealValueMax(),
'call_types' => $this->transformCallType($report->getCallTypes()),
'media_types' => $this->transformMediaTypes($report),
'call_duration_min' => $this->transformDurationToMinutes($report->getCallDurationMin()),
'call_duration_max' => $this->transformDurationToMinutes($report->getCallDurationMax()),
'teams' => $this->transformGroups(team: $team, groupsIds: $report->getGroups()),
'deal_at_call_stages' => $this->transformStages(team: $team, stagesIds: $report->getDealAtCallStages()),
'current_deal_stages' => $this->transformStages(team: $team, stagesIds: $report->getCurrentDealStages()),
'recipients' => $this->transformRecipients($report->getRecipients()),
'created_by' => $this->transformCreator($report->getCreator()),
'additional_prompt_input' => $report->getAdditionalPromptInput(),
'custom_name' => $report->getCustomName(),
'created_at' => $report->getCreatedAt()->format('Y-m-d H:i:s'),
'updated_at' => $report->getUpdatedAt()->format('Y-m-d H:i:s'),
'deleted_at' => $report->getDeletedAt()?->format('Y-m-d H:i:s'),
];
}
private function transformAskJiminnyFields(AutomatedReport $report): array
{
$team = $report->getTeam();
$creatorId = $report->getAttribute('created_by');
$explicitUserIds = array_values(array_filter(
$report->getRecipients()['users'] ?? [],
static fn ($id) => $id !== $creatorId
));
return [
'report_name' => $report->getCustomName(),
'enabled' => $report->getStatus(),
'share_teams' => $this->transformGroups(team: $team, groupsIds: $report->getGroups()),
'share_users' => $this->transformRecipients(['users' => $explicitUserIds]),
'saved_search' => $this->transformSafeSearch($report->getSavedSearch()),
'ask_jiminny_prompt' => $this->transformAskJiminnyPrompt($report->getAskAnythingPrompt()),
'expires_on' => $report->getExpiresAt()?->format('Y-m-d'),
];
}
private function transformOrganization(?Team $team): array
{
return [
'id' => $team?->getUuid(),
'name' => $team?->getName(),
];
}
private function transformReportType(string $type): array
{
foreach (self::ALL_TYPES as $typeItem) {
if ($typeItem['id'] === $type) {
return $typeItem;
}
}
return [];
}
private function transformCallType(array $types): array
{
$result = [];
$callTypes = [self::CALL_TYPE_CONFERENCE, self::CALL_TYPE_DIALER];
foreach ($types as $type) {
foreach ($callTypes as $callTypeItem) {
if ($callTypeItem['id'] === $type) {
$result[] = $callTypeItem;
break;
}
}
}
return $result;
}
private function transformMediaTypes(AutomatedReport $report): array
{
$values = [];
foreach ($report->getMediaTypes() as $mediaType) {
if (! in_array($mediaType, self::MEDIA_TYPES, true)) {
continue;
}
$values[] = match ($mediaType) {
self::MEDIA_TYPE_PDF => self::MEDIA_TYPE_OBJECT_PDF,
self::MEDIA_TYPE_PODCAST => self::MEDIA_TYPE_OBJECT_PODCAST,
};
}
return $values;
}
private function transformFrequency(string $frequency): array
{
foreach (self::ALL_FREQUENCIES as $frequencyItem) {
if ($frequencyItem['id'] === $frequency) {
return $frequencyItem;
}
}
return [];
}
public function transformDurationToMinutes(?int $duration): ?int
{
if (! $duration) {
return null;
}
return (int) ($duration / 60);
}
private function transformGroups(?Team $team, array $groupsIds): array
{
if (empty($groupsIds) || ! $team) {
return [];
}
$data = [];
foreach ($groupsIds as $groupId) {
$group = $team->groups()->where('id', $groupId)->first();
if ($group) {
$data[] = [
'id' => $group->getUuid(),
'name' => $group->getName(),
'photoUrl' => $group->getPhotoUrl(),
];
}
}
return $data;
}
private function transformStages(?Team $team, array $stagesIds): array
{
if (empty($stagesIds) || ! $team) {
return [];
}
$data = [];
foreach ($stagesIds as $stageId) {
$stage = $team->stages()->where('id', $stageId)->first();
if ($stage) {
$data[] = [
'id' => $stage->getUuid(),
'name' => $stage->getName(),
];
}
}
return $data;
}
private function transformRecipients(array $recipients): array
{
$users = [];
foreach ($recipients['users'] ?? [] as $userId) {
$users[] = $this->transformUser($userId);
}
return $users;
}
private function transformCreator(?User $user): ?array
{
if ($user === null) {
return null;
}
return $this->transformUser($user->getId());
}
private function transformAskJiminnyPrompt(?AskAnythingPrompt $prompt): ?array
{
if ($prompt === null) {
return null;
}
return [
'id' => $prompt->getUuid(),
'name' => $prompt->getTitle(),
];
}
private function transformSafeSearch(?Search $search): ?array
{
if ($search === null) {
return null;
}
return [
'id' => $search->getUuid(),
'name' => $search->getName(),
];
}
private function transformUser(int $userId): array
{
/* @var ?User $user */
$user = $this->userRepository->find($userId);
return [
'id' => $user?->getUuid(),
'name' => $user?->getName(),
'email' => $user?->getEmailAddress(),
'photoUrl' => $user?->getPhotoUrl(),
];
}
public function create(array $data): array
{
$validatedData = $this->validateAndTransformData($data);
$validatedData['created_by'] = auth()->id();
$automatedReport = $this->automatedReportsRepository->create($validatedData);
$this->generateOneOffReport($automatedReport);
return $this->transformReportFullView($automatedReport);
}
public function update(string $uuid, array $data): array
{
$validatedData = $this->validateAndTransformData($data);
$report = $this->automatedReportsRepository->findByUuid($uuid);
if (! $report) {
throw new InvalidArgumentException('Report not found');
}
$oldCustomName = $report->getCustomName();
$automatedReport = $this->automatedReportsRepository->update($report, $validatedData);
if ($oldCustomName !== $automatedReport->getCustomName()) {
$this->updateResultNames($automatedReport);
}
$this->generateOneOffReport($automatedReport);
return $this->transformReportFullView($automatedReport);
}
/**
* Create an Ask Jiminny report.
*/
public function createAskJiminnyReport(array $data, User $creator): array
{
$validatedData = $this->validateAskJiminnyReportData($data, $creator);
$validatedData['created_by'] = $creator->getId();
$automatedReport = $this->automatedReportsRepository->create($validatedData);
return $this->transformReportFullView($automatedReport);
}
/**
* Update an Ask Jiminny report.
*/
public function updateAskJiminnyReport(AutomatedReport $report, array $data, User $user): array
{
if (! $report->isAskJiminnyReport()) {
throw new InvalidArgumentException('Report is not an Ask Jiminny report');
}
$validatedData = $this->validateAskJiminnyReportData($data, $user);
$oldCustomName = $report->getCustomName();
$automatedReport = $this->automatedReportsRepository->update($report, $validatedData);
if ($oldCustomName !== $automatedReport->getCustomName()) {
$this->updateResultNames($automatedReport);
}
return $this->transformReportFullView($automatedReport);
}
public function updateAskJiminnyReportStatus(AutomatedReport $report, bool $status): array
{
if ($status && $report->isAskJiminnyReport() && ! $report->canExecute()) {
throw new InvalidArgumentException(
'This report is missing a saved search or prompt. ' .
'Edit the report to complete the setup before enabling it.'
);
}
$this->automatedReportsRepository->update($report, ['status' => $status]);
return $this->transformReportFullView($report->fresh());
}
/**
* Validate and transform data for Ask Jiminny reports.
*/
private function validateAskJiminnyReportData(array $data, User $user): array
{
// Validate name
$name = trim($data['report_name'] ?? '');
if (empty($name)) {
throw new InvalidArgumentException('Report name is required');
}
if (mb_strlen($name) > 50) {
throw new InvalidArgumentException('Report name must be 50 characters or less');
}
// Validate frequency (only daily, weekly, monthly for Ask Jiminny)
$frequency = $data['frequency'] ?? null;
$askJiminnyFrequencies = [self::FREQUENCY_DAILY, self::FREQUENCY_WEEKLY, self::FREQUENCY_MONTHLY];
if (! in_array($frequency, $askJiminnyFrequencies, true)) {
throw new InvalidArgumentException('Frequency must be daily, weekly, or monthly');
}
// Validate expiration date
$expiresAt = $data['expires_on'] ?? null;
if (empty($expiresAt)) {
throw new InvalidArgumentException('Expiration date is required');
}
try {
$expiresAtDate = Carbon::parse($expiresAt);
} catch (InvalidFormatException $e) {
throw new InvalidArgumentException('Expiration date format is invalid');
}
$maxExpiration = Carbon::now()->addYear()->endOfDay();
if ($expiresAtDate->gt($maxExpiration)) {
throw new InvalidArgumentException('Expiration date cannot be more than 1 year from now');
}
if ($expiresAtDate->isPast()) {
throw new InvalidArgumentException('Expiration date cannot be in the past');
}
// Validate saved search
$activitySearchId = $data['saved_search'] ?? null;
if (empty($activitySearchId)) {
throw new InvalidArgumentException('Saved search is required');
}
$savedSearch = $this->activitySearchRepository->findByUuidAndUser($activitySearchId, $user);
if (! $savedSearch) {
throw new InvalidArgumentException('Saved search not found or does not belong to you');
}
// Validate saved prompt
$askAnythingPromptId = $data['ask_jiminny_prompt'] ?? null;
if (empty($askAnythingPromptId)) {
throw new InvalidArgumentException('Ask Jiminny prompt is required');
}
$prompt = $this->askAnythingRepository->getPromptByUuid($askAnythingPromptId);
if (! $prompt) {
throw new InvalidArgumentException('Ask Jiminny prompt not found');
}
// Validate status
$status = $data['enabled'] ?? false;
$recipientUserIds = [$user->getId()];
if (! empty($data['share_users'])) {
$sharedUserIds = $this->validateAndGetUserIdsByTeam(
$user->team,
(array) $data['share_users']
);
$recipientUserIds = array_merge($recipientUserIds, $sharedUserIds);
}
$sharedGroupIds = [];
if (! empty($data['share_teams'])) {
$sharedGroupIds = $this->validateAndGetGroupIds($user->team, (array) $data['share_teams']);
}
$recipientUserIds = array_values(array_unique($recipientUserIds));
return [
'team_id' => $user->getTeamId(),
'type' => self::TYPE_ASK_JIMINNY,
'status' => (bool) $status,
'frequency' => $frequency,
'custom_name' => $name,
'activity_search_id' => $savedSearch->getId(),
'ask_anything_prompt_id' => $prompt->getId(),
'expires_at' => $expiresAtDate->toDateString(),
'media_types' => [self::MEDIA_TYPE_PDF],
'call_types' => [],
'recipients' => ['users' => $recipientUserIds],
'groups' => $sharedGroupIds,
];
}
public static function getAskJiminnyFrequencies(): array
{
return array_map(static function ($frequency) {
return $frequency['id'];
}, self::ASK_JIMINNY_FREQUENCIES);
}
public function getAskJiminnyReportFilters(User $user): array
{
$savedSearches = $this->activitySearchRepository->findByUserOrderedByName($user)
->map(fn (Search $search) => [
'id' => $search->getUuid(),
'name' => $search->getName(),
])
->values()->all();
$prompts = collect(
$this->askAnythingPromptService->get($user, AskAnythingPromptTarget::on_demand)
)->map(fn (AskAnythingPromptDto $prompt) => [
'id' => $prompt->id,
'name' => $prompt->title,
])->values()->all();
return [
[
'id' => 'prompt',
'label' => 'Prompt',
'options' => $prompts,
],
[
'id' => 'saved_search',
'label' => 'Saved Search',
'options' => $savedSearches,
],
];
}
public function getAskJiminnyReportFormData(User $user, ?AutomatedReport $report = null): array
{
$team = $user->getTeam();
$userTimezone = $user->getTimezone();
$savedSearches = $this->activitySearchRepository->findByUserOrderedByName($user)
->map(fn (Search $search) => [
'id' => $search->getUuid(),
'name' => $search->getName(),
])
->values()->all();
$prompts = collect(
$this->askAnythingPromptService->get($user, AskAnythingPromptTarget::on_demand)
)->map(fn (AskAnythingPromptDto $prompt) => [
'id' => $prompt->id,
'name' => $prompt->title,
])->values()->all();
$teamGroups = $this->groupRepository->getAllByTeam($team)->map(fn ($group) => [
'id' => $group->getUuid(),
'name' => $group->getName(),
])->values()->all();
$shareUsers = $this->recipientsService->getRecipientsFieldData(team: $team)['options'] ?? [];
$sharedTeamsValue = [];
$sharedUsersValue = [];
if ($report) {
$sharedTeamsValue = $this->transformGroups($team, $report->getGroups());
$recipientUserIds = $report->getRecipients()['users'] ?? [];
$creatorId = $report->getAttribute('created_by');
$sharedUserIds = array_values(array_filter(
$recipientUserIds,
static fn ($id) => $id !== $creatorId
));
$sharedUsersValue = collect($sharedUserIds)
->map(fn ($id) => $this->userRepository->find((int) $id))
->filter()
->map(fn (User $u) => [
'id' => $u->getUuid(),
'name' => $u->getName(),
])
->values()
->all();
}
return [
'fields' => [
[
'id' => 'enabled',
'inputType' => InputTypeEnum::TOGGLE,
'label' => '',
'value' => $report?->getStatus() ?? false,
],
[
'id' => 'report_name',
'inputType' => InputTypeEnum::TEXT,
'label' => 'Name',
'placeholder' => 'Enter name',
'required' => true,
'validation' => ['maxLength' => 50],
'value' => $report?->getCustomName() ?? '',
...
|
[{"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},"on_screen":true,"help_text":"~/jiminny/app","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"JY-20676-delete-report-related-objects, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.098071806,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: JY-20676-delete-report-related-objects","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.8194814,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskAnythingPromptServiceTest","depth":6,"bounds":{"left":0.83477396,"top":0.019952115,"width":0.080784574,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskAnythingPromptServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"100","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.011968086,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.007978723,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXStaticText","text":"34","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.010305851,"height":0.0},"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.27027926,"top":1.0,"width":0.00731383,"height":0.0},"on_screen":false,"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},"on_screen":false,"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\\Kiosk\\AutomatedReports;\n\nuse Carbon\\CarbonImmutable;\nuse Carbon\\CarbonInterface;\nuse Carbon\\Exceptions\\InvalidFormatException;\nuse DateTime;\nuse DateTimeInterface;\nuse DateTimeZone;\nuse Illuminate\\Contracts\\Bus\\Dispatcher as BusDispatcher;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\Facades\\Log;\nuse Illuminate\\Support\\Facades\\Storage;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\InputTypeEnum;\nuse Jiminny\\Component\\AskAnything\\AskAnythingPromptService;\nuse Jiminny\\Component\\AskAnything\\Dtos\\AskAnythingPromptDto;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Contracts\\Repositories\\PlaybookCategoryRepository;\nuse Jiminny\\Contracts\\Repositories\\TeamRepository;\nuse Jiminny\\Contracts\\Repositories\\UserRepository;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Exceptions\\ModelNotFoundException;\nuse Jiminny\\Jobs\\AutomatedReports\\RequestGenerateReportJob;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPrompt;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPromptTarget;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Partner;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AskAnythingRepository;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Repositories\\GroupRepository;\nuse Jiminny\\Repositories\\SearchRepository;\nuse Jiminny\\Repositories\\StageRepository;\nuse Throwable;\n\nclass AutomatedReportsService\n{\n public const string TYPE_LOSS_ANALYSIS = 'loss_analysis';\n public const string TYPE_ASK_JIMINNY = 'ask_jiminny';\n\n /**\n * Standard report types (used by kiosk for existing automated reports).\n */\n // @TODO this will add filter, however if we need to control feature by FF we need conditional logic\n public const array TYPES = [\n ['id' => 'exec_summary', 'name' => 'Exec Summary'],\n ['id' => 'coaching_profiles', 'name' => 'Coaching Profiles'],\n ['id' => 'product_feedback', 'name' => 'Product Feedback'],\n ['id' => self::TYPE_LOSS_ANALYSIS, 'name' => 'Loss Analysis'],\n// ['id' => 'questions', 'name' => 'Questions'],\n// ['id' => 'statistical_quant', 'name' => 'Statistical Quantitative'],\n ];\n\n public const array ALL_TYPES = [\n ...self::TYPES,\n ['id' => self::TYPE_ASK_JIMINNY, 'name' => 'Ask Jiminny'],\n ];\n\n public const string FREQUENCY_DAILY = 'daily';\n public const string FREQUENCY_WEEKLY = 'weekly';\n public const string FREQUENCY_MONTHLY = 'monthly';\n public const string FREQUENCY_QUARTERLY = 'quarterly';\n public const string FREQUENCY_ONE_OFF = 'one_off';\n\n /**\n * Frequencies for standard (non-Ask Jiminny) reports.\n */\n public const array FREQUENCIES = [\n ['id' => self::FREQUENCY_WEEKLY, 'name' => 'Weekly'],\n ['id' => self::FREQUENCY_MONTHLY, 'name' => 'Monthly'],\n ['id' => self::FREQUENCY_QUARTERLY, 'name' => 'Quarterly'],\n ['id' => self::FREQUENCY_ONE_OFF, 'name' => 'One-off'],\n ];\n\n /**\n * Frequencies for Ask Jiminny reports.\n */\n public const array ASK_JIMINNY_FREQUENCIES = [\n ['id' => self::FREQUENCY_DAILY, 'name' => 'Daily'],\n ['id' => self::FREQUENCY_WEEKLY, 'name' => 'Weekly'],\n ['id' => self::FREQUENCY_MONTHLY, 'name' => 'Monthly'],\n ];\n\n public const string MEDIA_TYPE_PDF = 'pdf';\n public const string MEDIA_TYPE_PODCAST = 'podcast';\n public const array MEDIA_TYPES = [self::MEDIA_TYPE_PDF, self::MEDIA_TYPE_PODCAST];\n public const array MEDIA_TYPE_OBJECT_PDF = ['id' => self::MEDIA_TYPE_PDF, 'name' => 'PDF'];\n public const array MEDIA_TYPE_OBJECT_PODCAST = ['id' => self::MEDIA_TYPE_PODCAST, 'name' => 'Podcast'];\n public const array MEDIA_TYPE_OBJECTS = [self::MEDIA_TYPE_OBJECT_PDF, self::MEDIA_TYPE_OBJECT_PODCAST];\n\n public const array CALL_TYPE_CONFERENCE = ['id' => 'conference', 'name' => 'Conference'];\n public const array CALL_TYPE_DIALER = ['id' => 'dialer', 'name' => 'Dialer'];\n public const int SENT_REPORT_AT_HOURS = 5;\n public const string PDF_KEY = 'pdf';\n public const string AUDIO_KEY = 'audio';\n\n private const array ALL_FREQUENCIES = [\n ['id' => self::FREQUENCY_DAILY, 'name' => 'Daily'],\n ['id' => self::FREQUENCY_WEEKLY, 'name' => 'Weekly'],\n ['id' => self::FREQUENCY_MONTHLY, 'name' => 'Monthly'],\n ['id' => self::FREQUENCY_QUARTERLY, 'name' => 'Quarterly'],\n ['id' => self::FREQUENCY_ONE_OFF, 'name' => 'One-off'],\n ];\n private const string S3_DIR = 'reports';\n private const array FILE_EXTENSIONS_VARIANTS = ['html', 'MD', 'pdf'];\n private const array FILE_PODCAST_EXTENSIONS_VARIANTS = ['json', 'mp3', 'ssml'];\n\n public function __construct(\n private readonly TeamRepository $teamRepository,\n private readonly GroupRepository $groupRepository,\n private readonly UserRepository $userRepository,\n private readonly StageRepository $stageRepository,\n private readonly DealStagesService $dealStagesService,\n private readonly RecipientsService $recipientsService,\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly Webhook $webhookService,\n private readonly BusDispatcher $dispatcher,\n private readonly ActivityTypeService $activityTypeService,\n private readonly PlaybookCategoryRepository $playbookCategoryRepository,\n private readonly AskAnythingPromptService $askAnythingPromptService,\n private readonly SearchRepository $activitySearchRepository,\n private readonly AskAnythingRepository $askAnythingRepository,\n ) {\n }\n\n public static function getTypes(): array\n {\n $types = self::TYPES;\n\n return array_map(static function ($type) {\n return $type['id'];\n }, $types);\n }\n\n public static function getCallTypes(): array\n {\n return array_map(static function ($callType) {\n return $callType['id'];\n }, [self::CALL_TYPE_CONFERENCE, self::CALL_TYPE_DIALER]);\n }\n\n public static function getFrequencies(): array\n {\n return array_map(static function ($frequency) {\n return $frequency['id'];\n }, self::FREQUENCIES);\n }\n\n // front-facing structure\n public function getReportEnabledFieldData(bool $value = false): array\n {\n return [\n 'id' => 'report_enabled',\n 'label' => '',\n 'inputType' => InputTypeEnum::TOGGLE,\n 'value' => $value,\n ];\n }\n\n // Organizations = Teams\n public function getOrganizationFieldData(?string $value = null, bool $shortVersion = false, ?Partner $partner = null): array\n {\n $options = $this->getTeams(partner: $partner);\n\n if ($shortVersion) {\n return [\n 'id' => 'organization',\n 'label' => 'Organization',\n 'options' => $options,\n ];\n }\n\n return [\n 'id' => 'organization',\n 'label' => 'Organization',\n 'inputType' => InputTypeEnum::DROPDOWN,\n 'required' => true,\n 'placeholder' => 'Select',\n 'options' => $options,\n 'value' => $value,\n 'dependencies' => [\n 'teams',\n 'deal_stage_at_call',\n 'current_deal_stage',\n 'recipients',\n ActivityTypeService::PLAYBOOK_CATEGORIES_KEY,\n ],\n 'dependsOn' => [],\n ];\n }\n\n // Teams = Groups\n public function getTeamFieldData(array $options = [], array $value = [], bool $shortVersion = false): array\n {\n if ($shortVersion) {\n return [\n 'id' => 'teams',\n 'label' => 'Team',\n 'options' => $options,\n ];\n }\n\n return [\n 'id' => 'teams',\n 'label' => 'Team',\n 'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,\n 'required' => false,\n 'placeholder' => 'Select',\n 'options' => $options,\n 'value' => $value, // value should be an array of objects {id, name}\n 'dependencies' => [ActivityTypeService::PLAYBOOK_CATEGORIES_KEY],\n 'dependsOn' => [],\n ];\n }\n\n public function getReportTypeFieldData(?string $value = null, bool $shortVersion = false, ?Team $team = null): array\n {\n $types = [];\n if ($team instanceof Team) {\n if ($team->hasFeature(FeatureEnum::AUTOMATED_REPORTS)) {\n $types = self::TYPES;\n }\n if ($team->hasFeature(FeatureEnum::ASK_JIMINNY_REPORTS)) {\n $types[] = ['id' => self::TYPE_ASK_JIMINNY, 'name' => 'Ask Jiminny'];\n }\n } else {\n $types = self::TYPES;\n }\n\n if ($shortVersion) {\n return [\n 'id' => 'report_type',\n 'label' => 'Report Type',\n 'options' => $types,\n ];\n }\n\n return [\n 'id' => 'report_type',\n 'label' => 'Report Type',\n 'inputType' => InputTypeEnum::DROPDOWN,\n 'required' => true,\n 'placeholder' => 'Select',\n 'options' => $types,\n 'value' => $value,\n 'dependencies' => [],\n 'dependsOn' => [],\n ];\n }\n\n public function getFrequencyFieldData(?string $value = null): array\n {\n return [\n 'id' => 'frequency',\n 'label' => 'Frequency',\n 'inputType' => InputTypeEnum::DROPDOWN,\n 'required' => true,\n 'placeholder' => 'Select',\n 'options' => self::FREQUENCIES,\n 'value' => $value,\n 'dependencies' => ['period'],\n 'dependsOn' => [],\n ];\n }\n\n public function getPeriodFieldData(?string $valueStartDate = null, ?string $valueEndDate = null): array\n {\n return [\n 'id' => 'period',\n 'label' => 'Select one-off period',\n 'inputType' => InputTypeEnum::DATE_RANGE,\n 'required' => true,\n 'placeholder' => 'Select',\n 'value' => ['startDate' => $valueStartDate, 'endDate' => $valueEndDate],\n 'queryParams' => [\n 'startDate' => 'start_date_period',\n 'endDate' => 'end_date_period',\n ],\n 'dependencies' => [],\n 'dependsOn' => ['frequency'],\n ];\n }\n\n public function getActivityTypesFieldData(?Team $team = null, array $value = [], array $teamsFilter = []): array\n {\n return $this->activityTypeService->getActivityTypeFieldData(team: $team, value: $value, groupIds: $teamsFilter);\n }\n\n public function getDealStageAtCallFieldData(?Team $team = null, array $value = []): array\n {\n return $this->dealStagesService->getDealStageAtCallFieldData(team: $team, value: $value);\n }\n\n public function getCurrentDealStageFieldData(?Team $team = null, array $value = []): array\n {\n return $this->dealStagesService->getCurrentDealStageFieldData(team: $team, value: $value);\n }\n\n public function getDealValueFieldData(?int $valueMin = null, ?int $valueMax = null): array\n {\n return [\n 'id' => 'deal_value',\n 'label' => 'Deal Value',\n 'inputType' => InputTypeEnum::INTEGER_RANGE,\n 'required' => false,\n 'value' => ['min' => $valueMin, 'max' => $valueMax],\n 'queryParams' => [\n 'min' => 'min_deal_value',\n 'max' => 'max_deal_value',\n ],\n 'dependencies' => [],\n 'dependsOn' => [],\n ];\n }\n\n public function getCallTypeFieldData(bool $conferenceOn = false, bool $dialerOn = false): array\n {\n $value = [];\n $conferenceOn && $value[] = self::CALL_TYPE_CONFERENCE;\n $dialerOn && $value[] = self::CALL_TYPE_DIALER;\n\n return [\n 'id' => 'call_type',\n 'label' => 'Call Type',\n 'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,\n 'required' => true,\n 'options' => [\n self::CALL_TYPE_CONFERENCE,\n self::CALL_TYPE_DIALER,\n ],\n 'value' => $value,\n 'dependencies' => [],\n 'dependsOn' => [],\n ];\n }\n\n public function getMediaTypeFieldData(?AutomatedReport $report = null): array\n {\n $value = [];\n\n if ($report) {\n $value = $this->transformMediaTypes($report);\n }\n\n return [\n 'id' => 'media_types',\n 'label' => 'Export as',\n 'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,\n 'required' => true,\n 'options' => self::MEDIA_TYPE_OBJECTS,\n 'value' => $value,\n 'dependencies' => [],\n 'dependsOn' => [],\n ];\n }\n\n public function getCallDurationFieldData(?int $valueMin = null, ?int $valueMax = null): array\n {\n return [\n 'id' => 'call_duration',\n 'label' => 'Call Duration',\n 'inputType' => InputTypeEnum::INTEGER_RANGE,\n 'required' => false,\n 'value' => ['min' => $valueMin, 'max' => $valueMax],\n 'queryParams' => [\n 'min' => 'min_call_duration',\n 'max' => 'max_call_duration',\n ],\n 'dependencies' => [],\n 'dependsOn' => [],\n ];\n }\n\n public function getRecipientsFieldData(?Team $team = null, array $value = []): array\n {\n return $this->recipientsService->getRecipientsFieldData(team: $team, value: $value);\n }\n\n public function getJiminnyRecipientsFieldData(array $value = []): array\n {\n return $this->recipientsService->getJiminnyRecipientsFieldData($value);\n }\n\n public function getAdditionalPromptInputFieldData(?string $value = null): array\n {\n return [\n 'id' => 'additional_prompt_input',\n 'label' => 'Special requirements',\n 'inputType' => InputTypeEnum::TEXTAREA,\n 'required' => false,\n 'placeholder' => 'What should be the focus of the report?',\n 'value' => $value,\n 'dependencies' => [],\n 'dependsOn' => [],\n ];\n }\n\n public function getCustomReportNameFieldData(?string $value = null): array\n {\n return [\n 'id' => 'custom_name',\n 'label' => 'Custom report name',\n 'inputType' => InputTypeEnum::TEXT,\n 'required' => false,\n 'placeholder' => 'Enter custom name',\n 'value' => $value,\n 'dependencies' => [],\n 'dependsOn' => [],\n ];\n }\n\n // data providers\n public function getTeams(?Partner $partner = null): array\n {\n $teams = $this->teamRepository->getTeamsForKiosk(status: Team::STATUS_ACTIVE, partner: $partner);\n\n $teamData = [];\n foreach ($teams as $team) {\n if (! $team->hasFeature(FeatureEnum::AUTOMATED_REPORTS)) {\n continue;\n }\n\n $teamData[] = $this->transformTeam($team);\n }\n\n return $teamData;\n }\n\n public function getTeamGroups(string $teamUuid): array\n {\n $data = [];\n $team = $this->getTeam($teamUuid);\n\n if ($team !== null) {\n $groups = $team->groups()->get();\n\n foreach ($groups as $group) {\n $data[] = [\n 'id' => $group->getUuid(),\n 'name' => $group->getName(),\n ];\n }\n }\n\n return $data;\n }\n\n public function getTeamsGroupsOptions(array $filterTeamUuids = [], ?Partner $partner = null): array\n {\n $data = [];\n $teams = $this->getTeams(partner: $partner);\n\n foreach ($teams as $team) {\n if (! empty($filterTeamUuids) && ! in_array($team['id'], $filterTeamUuids, true)) {\n continue;\n }\n\n $data[] = [\n 'label' => $team['name'],\n 'groups' => $this->getTeamGroups($team['id']),\n ];\n }\n\n return $data;\n }\n\n public function getTeam(string $teamUuid): ?Team\n {\n return $this->teamRepository->idOrUuid($teamUuid);\n }\n\n public function getTeamById(int $teamId): ?Team\n {\n return $this->teamRepository->find($teamId);\n }\n\n public function getGroupsUuids(AutomatedReport $report): array\n {\n $uuids = [];\n $reportGroups = $report->getGroups();\n foreach ($reportGroups as $groupId) {\n if ($group = $this->groupRepository->find($groupId)) {\n $uuids[] = $group->getUuid();\n }\n }\n\n return $uuids;\n }\n\n public function getPlaybookCategoriesUuids(AutomatedReport $report): array\n {\n $uuids = [];\n $playbookCategories = $report->getPlaybookCategories();\n foreach ($playbookCategories as $id) {\n if ($category = $this->playbookCategoryRepository->find($id)) {\n $uuids[] = $category->getUuid();\n }\n }\n\n return $uuids;\n }\n\n public function getDealAtCallStagesUuids(AutomatedReport $report): array\n {\n $uuids = [];\n $reportStages = $report->getDealAtCallStages();\n foreach ($reportStages as $id) {\n if ($stage = $this->stageRepository->find($id)) {\n $uuids[] = $stage->getUuid();\n }\n }\n\n return $uuids;\n }\n\n public function getCurrentDealStagesUuids(AutomatedReport $report): array\n {\n $uuids = [];\n $reportStages = $report->getCurrentDealStages();\n foreach ($reportStages as $id) {\n if ($stage = $this->stageRepository->find($id)) {\n $uuids[] = $stage->getUuid();\n }\n }\n\n return $uuids;\n }\n\n public function getUsersUuids(AutomatedReport $report): array\n {\n return $this->extractUserUuids($report->getRecipients());\n }\n\n public function getJiminnyUsersUuids(AutomatedReport $report): array\n {\n return $this->extractUserUuids($report->getJiminnyRecipients());\n }\n\n /**\n * @param array<string, mixed> $recipients\n */\n private function extractUserUuids(array $recipients): array\n {\n $userIds = $recipients['users'] ?? [];\n\n return collect($userIds)\n ->map(fn ($id) => $this->userRepository->find((int) $id))\n ->filter()\n ->map(fn (UserContract $user) => $user->getUuid())\n ->values()\n ->all();\n }\n\n // get mail data\n public function getRecipientUsers(AutomatedReport $report): array\n {\n return $this->buildRecipientUsers($report->getRecipients());\n }\n\n /**\n * @return array<UserContract>\n */\n public function getRecipientUserObjects(AutomatedReport $report): array\n {\n $userIds = $report->getRecipients()['users'] ?? [];\n\n return collect($userIds)\n ->map(fn ($id) => $this->userRepository->find((int) $id))\n ->filter()\n ->values()\n ->all();\n }\n\n private function getJiminnyRecipientUsers(AutomatedReport $report): array\n {\n return $this->buildRecipientUsers($report->getJiminnyRecipients());\n }\n\n /**\n * @param array<string, mixed> $recipients\n */\n private function buildRecipientUsers(array $recipients): array\n {\n $userIds = $recipients['users'] ?? [];\n\n return collect($userIds)\n ->map(fn ($id) => $this->userRepository->find((int) $id))\n ->filter()\n ->map(fn (UserContract $user) => [\n 'email' => $user->getEmailAddress(),\n 'name' => $user->getName(),\n 'timezone' => $user->getTimezone()->getName(),\n ])\n ->values()\n ->all();\n }\n\n public function getValidRecipientUsers(AutomatedReport $report, bool $includeJiminny = false): array\n {\n if ($report->isAskJiminnyReport()) {\n $recipients = $this->resolveAskJiminnyRecipients($report);\n } else {\n $recipients = $this->getRecipientUsers($report);\n if ($includeJiminny) {\n $recipients = array_merge($recipients, $this->getJiminnyRecipientUsers($report));\n }\n }\n\n $emails = [];\n\n return array_values(array_filter(\n $recipients,\n static function ($recipient) use (&$emails) {\n if (empty($recipient['email']) || in_array($recipient['email'], $emails, true)) {\n return false;\n }\n $emails[] = $recipient['email'];\n\n return true;\n }\n ));\n }\n\n private function resolveAskJiminnyRecipients(AutomatedReport $report): array\n {\n $recipients = [];\n\n $creator = $report->getCreator();\n if ($creator !== null) {\n $recipients[] = [\n 'email' => $creator->getEmailAddress(),\n 'name' => $creator->getName(),\n 'timezone' => $creator->getTimezone()->getName(),\n ];\n }\n\n return array_merge(\n $recipients,\n $this->buildRecipientUsers($report->getRecipients()),\n $this->getGroupRecipientUsers($report),\n );\n }\n\n private function getGroupRecipientUsers(AutomatedReport $report): array\n {\n $users = [];\n foreach ($report->getGroups() as $groupId) {\n $group = $this->groupRepository->find($groupId);\n if ($group === null) {\n continue;\n }\n foreach ($group->getMembers() as $member) {\n $users[] = [\n 'email' => $member->getEmailAddress(),\n 'name' => $member->getName(),\n 'timezone' => $member->getTimezone()->getName(),\n ];\n }\n }\n\n return $users;\n }\n\n public function getReportTypeName(AutomatedReportResult $report): string\n {\n $type = $report->getReport()->getType();\n\n $getType = $this->transformReportType($type);\n\n return $getType['name'];\n }\n\n public function getReportPeriodName(AutomatedReportResult $report): string\n {\n $from = $report->getFromDate();\n $to = $report->getToDate();\n $frequency = $report->getReport()->getFrequency();\n\n if ($from === null || $to === null) {\n if (! $report->getReport()->isAskJiminnyReport()) {\n $invalidPeriod = $from === null ? 'from' : 'to';\n\n throw new ApplicationException('Report period is invalid: ' . $invalidPeriod);\n }\n\n $timezone = $report->getReport()->getCreator()?->getTimezone();\n $period = $this->calculateFromAndToDatePeriod($frequency, timezone: $timezone);\n $from = $period['fromDate'];\n $to = $period['toDate'];\n }\n\n return $this->formatReportPeriodName($frequency, $from, $to);\n }\n\n private function formatReportPeriodName(string $frequency, Carbon $from, Carbon $to): string\n {\n $fromYear = $from->format('Y');\n $toYear = $to->format('Y');\n $differentYears = $fromYear !== $toYear;\n\n switch ($frequency) {\n case self::FREQUENCY_DAILY:\n return $from->format('j M Y');\n\n case self::FREQUENCY_QUARTERLY:\n // 'Jan-Mar 2025' or 'Nov 2024-Jan 2025' if years differ\n $startMonth = $from->format('M');\n $endMonth = $to->copy()->subMonth();\n $endMonthName = $endMonth->format('M');\n $endMonthYear = $endMonth->format('Y');\n\n if ($differentYears) {\n return \"{$startMonth} {$fromYear} - {$endMonthName} {$endMonthYear}\";\n }\n\n return \"{$startMonth} - {$endMonthName} {$toYear}\";\n\n case self::FREQUENCY_MONTHLY:\n // 'May 2025' - monthly reports are always within the same year\n return $from->format('M Y');\n\n case self::FREQUENCY_WEEKLY:\n // '4 - 8 Aug 2025', '27 Oct - 3 Nov 2025', or '28 Dec 2024 - 3 Jan 2025' if years differ\n $startDay = $from->format('j');\n $endDay = $to->format('j');\n $startMonth = $from->format('M');\n $endMonth = $to->format('M');\n\n if ($differentYears) {\n return \"{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n if ($startMonth !== $endMonth) {\n return \"{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n return \"{$startDay} - {$endDay} {$endMonth} {$toYear}\";\n\n case self::FREQUENCY_ONE_OFF:\n // '2 May-31 May 2025' or '15 Dec 2024-15 Jan 2025' if years differ\n $startDay = $from->format('j');\n $startMonth = $from->format('M');\n $endDay = $to->format('j');\n $endMonth = $to->format('M');\n\n // If same month and year, use a format like '2-31 May 2025'\n if ($startMonth === $endMonth && ! $differentYears) {\n return \"{$startDay} - {$endDay} {$startMonth} {$toYear}\";\n }\n\n // If different years, include both years\n if ($differentYears) {\n return \"{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n // Same year but different months\n return \"{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}\";\n\n default:\n // Default format for unknown frequencies\n return $from->format('j M Y') . ' - ' . $to->format('j M Y');\n }\n }\n\n public function getReportTeamsName(AutomatedReportResult $report): string\n {\n $groups = $report->getGroups();\n\n if (empty($groups)) {\n return 'All';\n }\n\n // Get group names from repository\n $groupNames = [];\n foreach ($groups as $groupId) {\n $group = $this->groupRepository->find($groupId);\n if ($group) {\n $groupNames[] = $group->getName();\n }\n }\n\n if (count($groupNames) === 1) {\n // Single team format\n $teamsName = $groupNames[0];\n } else {\n // Multiple teams format\n $teamsName = implode(', ', $groupNames);\n }\n\n return $teamsName;\n }\n\n public function getReportFileName(AutomatedReportResult $report): string\n {\n $customName = $report->getReport()->getCustomName();\n $periodName = $this->getReportPeriodName($report);\n $filenameSuffix = $this->getFilenameSuffix($report);\n\n if ($customName) {\n if ($filenameSuffix) {\n $customName .= \" {$filenameSuffix}\";\n }\n\n return $this->sanitizeFileName(\"{$customName} - {$periodName}\");\n }\n\n $baseName = $this->getReportTypeName($report);\n\n if ($filenameSuffix) {\n $baseName .= \" {$filenameSuffix}\";\n }\n\n return $this->sanitizeFileName(\"{$baseName} - {$periodName} - {$this->getReportTeamsName($report)}\");\n }\n\n public function getReportFileNameWithExtension(AutomatedReportResult $result): string\n {\n $extension = $this->getMediaTypeMetadata($result)['extension'];\n\n return $this->getReportFileName($result) . '.' . $extension;\n }\n\n public function sanitizeFileName(string $fileName): string\n {\n return str_replace(['/', '\\\\'], '-', $fileName);\n }\n\n public function isUserRecipientOfReport(User $user, AutomatedReport $report): bool\n {\n $recipientIds = array_map('intval', $report->getRecipients()['users'] ?? []);\n if (in_array($user->getId(), $recipientIds, true)) {\n return true;\n }\n\n if ($report->isAskJiminnyReport()) {\n $groupId = $user->getGroupId();\n if ($groupId !== null && in_array($groupId, $report->getGroups(), true)) {\n return true;\n }\n }\n\n return false;\n }\n\n public function transformReportResults(Collection $automatedReportResults): array\n {\n $data = [];\n foreach ($automatedReportResults as $automatedReportResult) {\n /** @var AutomatedReportResult $automatedReportResult */\n\n $report = $automatedReportResult->getReport();\n\n $createdBy = $report->getCreator();\n $creator = [\n 'id' => $createdBy?->getUuid(),\n 'name' => $createdBy?->getName(),\n 'email' => $createdBy?->getEmailAddress(),\n 'photoUrl' => $createdBy?->getPhotoUrl(),\n ];\n\n $data[] = [\n 'id' => $automatedReportResult->getUuid(),\n 'name' => $automatedReportResult->getName(),\n 'frequency' => $this->transformFrequency($report->getFrequency()),\n 'recipients' => $this->buildRecipients($report),\n 'report_type' => $this->transformReportType($report->getType()),\n 'media_type' => $automatedReportResult->getMediaType(),\n 'downloadUrl' => $this->generateReportResultDownloadUrl($automatedReportResult),\n 'viewUrl' => $this->generateReportResultViewUrl($automatedReportResult),\n 'generated_at' => $automatedReportResult->getGeneratedAt()?->toIso8601String(),\n 'creator' => $creator,\n ];\n }\n\n return $data;\n }\n\n private function buildRecipients(AutomatedReport $report): array\n {\n $creatorUuid = $report->getCreator()?->getUuid();\n\n $recipients = array_values(array_filter(\n $this->transformRecipients($report->getRecipients()),\n static fn (array $recipient): bool => $recipient['id'] !== $creatorUuid,\n ));\n\n if (! $report->isAskJiminnyReport()) {\n return $recipients;\n }\n\n return [\n ...array_values($this->transformGroups(team: $report->getTeam(), groupsIds: $report->getGroups())),\n ...$recipients,\n ];\n }\n\n public function hasCallTypeConference(AutomatedReport $report): bool\n {\n return in_array(self::CALL_TYPE_CONFERENCE['id'], $report->getCallTypes(), true);\n }\n\n public function hasCallTypeDialer(AutomatedReport $report): bool\n {\n return in_array(self::CALL_TYPE_DIALER['id'], $report->getCallTypes(), true);\n }\n\n // transformers\n private function transformTeam(Team $team): array\n {\n if (! $team->hasFeature(FeatureEnum::AUTOMATED_REPORTS)) {\n return [];\n }\n\n return [\n 'id' => $team->getUuid(),\n 'name' => $team->getName(),\n ];\n }\n\n private function transformReportFullView(AutomatedReport $report): array\n {\n $base = $this->transformReportBase($report);\n\n return $report->getType() === self::TYPE_ASK_JIMINNY\n ? $base + $this->transformAskJiminnyFields($report)\n : $base + $this->transformStandardReportFields($report);\n }\n\n private function transformReportBase(AutomatedReport $report): array\n {\n return [\n 'id' => $report->getUuid(),\n 'organization' => $this->transformOrganization(team: $report->getTeam()),\n 'report_type' => $this->transformReportType($report->getType()),\n 'frequency' => $this->transformFrequency($report->getFrequency()),\n ];\n }\n\n private function transformStandardReportFields(AutomatedReport $report): array\n {\n $team = $report->getTeam();\n\n return [\n 'report_enabled' => $report->getStatus(),\n 'start_date_period' => $report->getFrom()?->format('Y-m-d H:i:s'),\n 'end_date_period' => $report->getTo()?->format('Y-m-d H:i:s'),\n 'deal_value_min' => $report->getDealValueMin(),\n 'deal_value_max' => $report->getDealValueMax(),\n 'call_types' => $this->transformCallType($report->getCallTypes()),\n 'media_types' => $this->transformMediaTypes($report),\n 'call_duration_min' => $this->transformDurationToMinutes($report->getCallDurationMin()),\n 'call_duration_max' => $this->transformDurationToMinutes($report->getCallDurationMax()),\n 'teams' => $this->transformGroups(team: $team, groupsIds: $report->getGroups()),\n 'deal_at_call_stages' => $this->transformStages(team: $team, stagesIds: $report->getDealAtCallStages()),\n 'current_deal_stages' => $this->transformStages(team: $team, stagesIds: $report->getCurrentDealStages()),\n 'recipients' => $this->transformRecipients($report->getRecipients()),\n 'created_by' => $this->transformCreator($report->getCreator()),\n 'additional_prompt_input' => $report->getAdditionalPromptInput(),\n 'custom_name' => $report->getCustomName(),\n 'created_at' => $report->getCreatedAt()->format('Y-m-d H:i:s'),\n 'updated_at' => $report->getUpdatedAt()->format('Y-m-d H:i:s'),\n 'deleted_at' => $report->getDeletedAt()?->format('Y-m-d H:i:s'),\n ];\n }\n\n private function transformAskJiminnyFields(AutomatedReport $report): array\n {\n $team = $report->getTeam();\n $creatorId = $report->getAttribute('created_by');\n $explicitUserIds = array_values(array_filter(\n $report->getRecipients()['users'] ?? [],\n static fn ($id) => $id !== $creatorId\n ));\n\n return [\n 'report_name' => $report->getCustomName(),\n 'enabled' => $report->getStatus(),\n 'share_teams' => $this->transformGroups(team: $team, groupsIds: $report->getGroups()),\n 'share_users' => $this->transformRecipients(['users' => $explicitUserIds]),\n 'saved_search' => $this->transformSafeSearch($report->getSavedSearch()),\n 'ask_jiminny_prompt' => $this->transformAskJiminnyPrompt($report->getAskAnythingPrompt()),\n 'expires_on' => $report->getExpiresAt()?->format('Y-m-d'),\n ];\n }\n\n private function transformOrganization(?Team $team): array\n {\n return [\n 'id' => $team?->getUuid(),\n 'name' => $team?->getName(),\n ];\n }\n\n private function transformReportType(string $type): array\n {\n foreach (self::ALL_TYPES as $typeItem) {\n if ($typeItem['id'] === $type) {\n return $typeItem;\n }\n }\n\n return [];\n }\n\n private function transformCallType(array $types): array\n {\n $result = [];\n $callTypes = [self::CALL_TYPE_CONFERENCE, self::CALL_TYPE_DIALER];\n\n foreach ($types as $type) {\n foreach ($callTypes as $callTypeItem) {\n if ($callTypeItem['id'] === $type) {\n $result[] = $callTypeItem;\n\n break;\n }\n }\n }\n\n return $result;\n }\n\n private function transformMediaTypes(AutomatedReport $report): array\n {\n $values = [];\n\n foreach ($report->getMediaTypes() as $mediaType) {\n if (! in_array($mediaType, self::MEDIA_TYPES, true)) {\n continue;\n }\n\n $values[] = match ($mediaType) {\n self::MEDIA_TYPE_PDF => self::MEDIA_TYPE_OBJECT_PDF,\n self::MEDIA_TYPE_PODCAST => self::MEDIA_TYPE_OBJECT_PODCAST,\n };\n }\n\n return $values;\n }\n\n private function transformFrequency(string $frequency): array\n {\n foreach (self::ALL_FREQUENCIES as $frequencyItem) {\n if ($frequencyItem['id'] === $frequency) {\n return $frequencyItem;\n }\n }\n\n return [];\n }\n\n public function transformDurationToMinutes(?int $duration): ?int\n {\n if (! $duration) {\n return null;\n }\n\n return (int) ($duration / 60);\n }\n\n private function transformGroups(?Team $team, array $groupsIds): array\n {\n if (empty($groupsIds) || ! $team) {\n return [];\n }\n\n $data = [];\n foreach ($groupsIds as $groupId) {\n $group = $team->groups()->where('id', $groupId)->first();\n\n if ($group) {\n $data[] = [\n 'id' => $group->getUuid(),\n 'name' => $group->getName(),\n 'photoUrl' => $group->getPhotoUrl(),\n ];\n }\n }\n\n return $data;\n }\n\n private function transformStages(?Team $team, array $stagesIds): array\n {\n if (empty($stagesIds) || ! $team) {\n return [];\n }\n\n $data = [];\n foreach ($stagesIds as $stageId) {\n $stage = $team->stages()->where('id', $stageId)->first();\n\n if ($stage) {\n $data[] = [\n 'id' => $stage->getUuid(),\n 'name' => $stage->getName(),\n ];\n }\n }\n\n return $data;\n }\n\n private function transformRecipients(array $recipients): array\n {\n $users = [];\n foreach ($recipients['users'] ?? [] as $userId) {\n $users[] = $this->transformUser($userId);\n }\n\n return $users;\n }\n\n private function transformCreator(?User $user): ?array\n {\n if ($user === null) {\n return null;\n }\n\n return $this->transformUser($user->getId());\n }\n\n private function transformAskJiminnyPrompt(?AskAnythingPrompt $prompt): ?array\n {\n if ($prompt === null) {\n return null;\n }\n\n return [\n 'id' => $prompt->getUuid(),\n 'name' => $prompt->getTitle(),\n ];\n }\n\n private function transformSafeSearch(?Search $search): ?array\n {\n if ($search === null) {\n return null;\n }\n\n return [\n 'id' => $search->getUuid(),\n 'name' => $search->getName(),\n ];\n }\n\n private function transformUser(int $userId): array\n {\n /* @var ?User $user */\n $user = $this->userRepository->find($userId);\n\n return [\n 'id' => $user?->getUuid(),\n 'name' => $user?->getName(),\n 'email' => $user?->getEmailAddress(),\n 'photoUrl' => $user?->getPhotoUrl(),\n ];\n }\n\n public function create(array $data): array\n {\n $validatedData = $this->validateAndTransformData($data);\n $validatedData['created_by'] = auth()->id();\n\n $automatedReport = $this->automatedReportsRepository->create($validatedData);\n\n $this->generateOneOffReport($automatedReport);\n\n return $this->transformReportFullView($automatedReport);\n }\n\n public function update(string $uuid, array $data): array\n {\n $validatedData = $this->validateAndTransformData($data);\n $report = $this->automatedReportsRepository->findByUuid($uuid);\n\n if (! $report) {\n throw new InvalidArgumentException('Report not found');\n }\n\n $oldCustomName = $report->getCustomName();\n\n $automatedReport = $this->automatedReportsRepository->update($report, $validatedData);\n\n if ($oldCustomName !== $automatedReport->getCustomName()) {\n $this->updateResultNames($automatedReport);\n }\n\n $this->generateOneOffReport($automatedReport);\n\n return $this->transformReportFullView($automatedReport);\n }\n\n /**\n * Create an Ask Jiminny report.\n */\n public function createAskJiminnyReport(array $data, User $creator): array\n {\n $validatedData = $this->validateAskJiminnyReportData($data, $creator);\n $validatedData['created_by'] = $creator->getId();\n\n $automatedReport = $this->automatedReportsRepository->create($validatedData);\n\n return $this->transformReportFullView($automatedReport);\n }\n\n /**\n * Update an Ask Jiminny report.\n */\n public function updateAskJiminnyReport(AutomatedReport $report, array $data, User $user): array\n {\n if (! $report->isAskJiminnyReport()) {\n throw new InvalidArgumentException('Report is not an Ask Jiminny report');\n }\n\n $validatedData = $this->validateAskJiminnyReportData($data, $user);\n\n $oldCustomName = $report->getCustomName();\n\n $automatedReport = $this->automatedReportsRepository->update($report, $validatedData);\n\n if ($oldCustomName !== $automatedReport->getCustomName()) {\n $this->updateResultNames($automatedReport);\n }\n\n return $this->transformReportFullView($automatedReport);\n }\n\n public function updateAskJiminnyReportStatus(AutomatedReport $report, bool $status): array\n {\n if ($status && $report->isAskJiminnyReport() && ! $report->canExecute()) {\n throw new InvalidArgumentException(\n 'This report is missing a saved search or prompt. ' .\n 'Edit the report to complete the setup before enabling it.'\n );\n }\n\n $this->automatedReportsRepository->update($report, ['status' => $status]);\n\n return $this->transformReportFullView($report->fresh());\n }\n\n /**\n * Validate and transform data for Ask Jiminny reports.\n */\n private function validateAskJiminnyReportData(array $data, User $user): array\n {\n // Validate name\n $name = trim($data['report_name'] ?? '');\n if (empty($name)) {\n throw new InvalidArgumentException('Report name is required');\n }\n if (mb_strlen($name) > 50) {\n throw new InvalidArgumentException('Report name must be 50 characters or less');\n }\n\n // Validate frequency (only daily, weekly, monthly for Ask Jiminny)\n $frequency = $data['frequency'] ?? null;\n $askJiminnyFrequencies = [self::FREQUENCY_DAILY, self::FREQUENCY_WEEKLY, self::FREQUENCY_MONTHLY];\n if (! in_array($frequency, $askJiminnyFrequencies, true)) {\n throw new InvalidArgumentException('Frequency must be daily, weekly, or monthly');\n }\n\n // Validate expiration date\n $expiresAt = $data['expires_on'] ?? null;\n if (empty($expiresAt)) {\n throw new InvalidArgumentException('Expiration date is required');\n }\n\n try {\n $expiresAtDate = Carbon::parse($expiresAt);\n } catch (InvalidFormatException $e) {\n throw new InvalidArgumentException('Expiration date format is invalid');\n }\n $maxExpiration = Carbon::now()->addYear()->endOfDay();\n if ($expiresAtDate->gt($maxExpiration)) {\n throw new InvalidArgumentException('Expiration date cannot be more than 1 year from now');\n }\n if ($expiresAtDate->isPast()) {\n throw new InvalidArgumentException('Expiration date cannot be in the past');\n }\n\n // Validate saved search\n $activitySearchId = $data['saved_search'] ?? null;\n if (empty($activitySearchId)) {\n throw new InvalidArgumentException('Saved search is required');\n }\n $savedSearch = $this->activitySearchRepository->findByUuidAndUser($activitySearchId, $user);\n if (! $savedSearch) {\n throw new InvalidArgumentException('Saved search not found or does not belong to you');\n }\n\n // Validate saved prompt\n $askAnythingPromptId = $data['ask_jiminny_prompt'] ?? null;\n if (empty($askAnythingPromptId)) {\n throw new InvalidArgumentException('Ask Jiminny prompt is required');\n }\n $prompt = $this->askAnythingRepository->getPromptByUuid($askAnythingPromptId);\n if (! $prompt) {\n throw new InvalidArgumentException('Ask Jiminny prompt not found');\n }\n\n // Validate status\n $status = $data['enabled'] ?? false;\n\n $recipientUserIds = [$user->getId()];\n\n if (! empty($data['share_users'])) {\n $sharedUserIds = $this->validateAndGetUserIdsByTeam(\n $user->team,\n (array) $data['share_users']\n );\n $recipientUserIds = array_merge($recipientUserIds, $sharedUserIds);\n }\n\n $sharedGroupIds = [];\n if (! empty($data['share_teams'])) {\n $sharedGroupIds = $this->validateAndGetGroupIds($user->team, (array) $data['share_teams']);\n }\n\n $recipientUserIds = array_values(array_unique($recipientUserIds));\n\n return [\n 'team_id' => $user->getTeamId(),\n 'type' => self::TYPE_ASK_JIMINNY,\n 'status' => (bool) $status,\n 'frequency' => $frequency,\n 'custom_name' => $name,\n 'activity_search_id' => $savedSearch->getId(),\n 'ask_anything_prompt_id' => $prompt->getId(),\n 'expires_at' => $expiresAtDate->toDateString(),\n 'media_types' => [self::MEDIA_TYPE_PDF],\n 'call_types' => [],\n 'recipients' => ['users' => $recipientUserIds],\n 'groups' => $sharedGroupIds,\n ];\n }\n\n public static function getAskJiminnyFrequencies(): array\n {\n return array_map(static function ($frequency) {\n return $frequency['id'];\n }, self::ASK_JIMINNY_FREQUENCIES);\n }\n\n public function getAskJiminnyReportFilters(User $user): array\n {\n $savedSearches = $this->activitySearchRepository->findByUserOrderedByName($user)\n ->map(fn (Search $search) => [\n 'id' => $search->getUuid(),\n 'name' => $search->getName(),\n ])\n ->values()->all();\n\n $prompts = collect(\n $this->askAnythingPromptService->get($user, AskAnythingPromptTarget::on_demand)\n )->map(fn (AskAnythingPromptDto $prompt) => [\n 'id' => $prompt->id,\n 'name' => $prompt->title,\n ])->values()->all();\n\n return [\n [\n 'id' => 'prompt',\n 'label' => 'Prompt',\n 'options' => $prompts,\n ],\n [\n 'id' => 'saved_search',\n 'label' => 'Saved Search',\n 'options' => $savedSearches,\n ],\n ];\n }\n\n public function getAskJiminnyReportFormData(User $user, ?AutomatedReport $report = null): array\n {\n $team = $user->getTeam();\n $userTimezone = $user->getTimezone();\n\n $savedSearches = $this->activitySearchRepository->findByUserOrderedByName($user)\n ->map(fn (Search $search) => [\n 'id' => $search->getUuid(),\n 'name' => $search->getName(),\n ])\n ->values()->all();\n\n $prompts = collect(\n $this->askAnythingPromptService->get($user, AskAnythingPromptTarget::on_demand)\n )->map(fn (AskAnythingPromptDto $prompt) => [\n 'id' => $prompt->id,\n 'name' => $prompt->title,\n ])->values()->all();\n\n $teamGroups = $this->groupRepository->getAllByTeam($team)->map(fn ($group) => [\n 'id' => $group->getUuid(),\n 'name' => $group->getName(),\n ])->values()->all();\n\n $shareUsers = $this->recipientsService->getRecipientsFieldData(team: $team)['options'] ?? [];\n\n $sharedTeamsValue = [];\n $sharedUsersValue = [];\n if ($report) {\n $sharedTeamsValue = $this->transformGroups($team, $report->getGroups());\n\n $recipientUserIds = $report->getRecipients()['users'] ?? [];\n $creatorId = $report->getAttribute('created_by');\n $sharedUserIds = array_values(array_filter(\n $recipientUserIds,\n static fn ($id) => $id !== $creatorId\n ));\n $sharedUsersValue = collect($sharedUserIds)\n ->map(fn ($id) => $this->userRepository->find((int) $id))\n ->filter()\n ->map(fn (User $u) => [\n 'id' => $u->getUuid(),\n 'name' => $u->getName(),\n ])\n ->values()\n ->all();\n }\n\n return [\n 'fields' => [\n [\n 'id' => 'enabled',\n 'inputType' => InputTypeEnum::TOGGLE,\n 'label' => '',\n 'value' => $report?->getStatus() ?? false,\n ],\n [\n 'id' => 'report_name',\n 'inputType' => InputTypeEnum::TEXT,\n 'label' => 'Name',\n 'placeholder' => 'Enter name',\n 'required' => true,\n 'validation' => ['maxLength' => 50],\n 'value' => $report?->getCustomName() ?? '',\n ],\n [\n 'id' => 'frequency',\n 'inputType' => InputTypeEnum::DROPDOWN,\n 'label' => 'Frequency',\n 'required' => true,\n 'placeholder' => 'Select',\n 'options' => self::ASK_JIMINNY_FREQUENCIES,\n 'value' => $report ? $this->transformFrequency($report->getFrequency()) : null,\n ],\n [\n 'id' => 'expires_on',\n 'inputType' => InputTypeEnum::DATE,\n 'label' => 'Expires on',\n 'required' => true,\n 'placeholder' => 'Select',\n 'validation' => [\n 'minDate' => now($userTimezone)->toDateString(),\n 'maxDate' => now($userTimezone)->addYear()->toDateString(),\n ],\n 'value' => $report?->getExpiresAt()?->toDateString(),\n ],\n [\n 'id' => 'share_teams',\n 'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,\n 'label' => 'Team',\n 'required' => false,\n 'placeholder' => 'Select',\n 'options' => $teamGroups,\n 'value' => $sharedTeamsValue,\n ],\n [\n 'id' => 'share_users',\n 'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,\n 'label' => 'Team member',\n 'required' => false,\n 'placeholder' => 'Select',\n 'groupLabelKey' => 'label',\n 'groupValuesKey' => 'users',\n 'optionLabelKey' => 'name',\n 'optionValueKey' => 'id',\n 'options' => $shareUsers,\n 'value' => $sharedUsersValue,\n ],\n [\n 'id' => 'saved_search',\n 'inputType' => InputTypeEnum::DROPDOWN,\n 'label' => 'Saved search',\n 'required' => true,\n 'placeholder' => 'Select',\n 'options' => $savedSearches,\n 'value' => $report && $report->getSavedSearch() ? [\n 'id' => $report->getSavedSearch()->getUuid(),\n 'name' => $report->getSavedSearch()->getName(),\n ] : null,\n ],\n [\n 'id' => 'ask_jiminny_prompt',\n 'inputType' => InputTypeEnum::DROPDOWN,\n 'label' => 'Ask Jiminny prompt',\n 'required' => true,\n 'placeholder' => 'Select',\n 'options' => $prompts,\n 'value' => $report && $report->getAskAnythingPrompt() ? [\n 'id' => $report->getAskAnythingPrompt()->getUuid(),\n 'name' => $report->getAskAnythingPrompt()->getTitle(),\n ] : null,\n ],\n ],\n ];\n }\n\n private function updateResultNames(AutomatedReport $automatedReport): void\n {\n $results = $this->automatedReportsRepository->getResultsByReport($automatedReport);\n\n foreach ($results as $result) {\n $result->update(['name' => $this->getReportFileName($result)]);\n }\n }\n\n public function updateStatus(string $uuid, array $data): array\n {\n $automatedReport = $this->automatedReportsRepository->findByUuid($uuid);\n\n if (! $automatedReport) {\n throw new ModelNotFoundException('Report not found');\n }\n\n $status = $this->validateReportStatus($data['report_enabled'] ?? null);\n $automatedReport->update([\n 'status' => $status,\n ]);\n\n $this->generateOneOffReport($automatedReport);\n\n return $this->transformReportFullView($automatedReport);\n }\n\n private function generateOneOffReport(AutomatedReport $automatedReport): void\n {\n // the scheduler handles all the other frequency types\n if ($automatedReport->getStatus() === false || $automatedReport->getFrequency() !== self::FREQUENCY_ONE_OFF) {\n return;\n }\n\n $this->dispatcher->dispatch(new RequestGenerateReportJob($automatedReport->getUuid()));\n }\n\n public function getReport(string $uuid, ?Partner $partner = null): AutomatedReport\n {\n $automatedReport = $this->automatedReportsRepository->findByUuid($uuid);\n\n if (! $automatedReport) {\n throw new ModelNotFoundException('Report not found');\n }\n\n if ($partner !== null && ! $partner->isDefaultPartner() && $automatedReport->team->partner_id !== $partner->getId()) {\n throw new ModelNotFoundException('Report not found');\n }\n\n return $automatedReport;\n }\n\n public function get(string $uuid, ?Partner $partner = null): array\n {\n $automatedReport = $this->getReport($uuid, $partner);\n\n return $this->transformReportFullView($automatedReport);\n }\n\n public function list(string $sortColumn = 'created_at', string $sortDirection = 'desc', ?Partner $partner = null): array\n {\n $results = [];\n $collection = $this->automatedReportsRepository->getAllStandardReports($sortColumn, $sortDirection, $partner);\n\n /** @var AutomatedReport $report */\n foreach ($collection as $report) {\n $results[] = $this->transformReportFullView($report);\n }\n\n return ['data' => $results];\n }\n\n public function listAskJiminnyReports(\n User $user,\n string $sortColumn = 'created_at',\n string $sortDirection = 'desc'\n ): array {\n $results = [];\n $collection = $this->automatedReportsRepository->getAskJiminnyReportsByUser($user, $sortColumn, $sortDirection);\n\n /** @var AutomatedReport $report */\n foreach ($collection as $report) {\n $results[] = $this->transformReportFullView($report);\n }\n\n return ['data' => $results];\n }\n\n public function delete(string $uuid): void\n {\n $automatedReport = $this->automatedReportsRepository->findByUuid($uuid);\n\n if (! $automatedReport) {\n throw new ModelNotFoundException('Report not found');\n }\n\n $automatedReport->delete();\n }\n\n public function createReportResult(AutomatedReport $automatedReport, array $data = []): AutomatedReportResult\n {\n return $this->automatedReportsRepository->createResult(\n array_merge(\n [\n 'report_id' => $automatedReport->getId(),\n 'status' => AutomatedReportResult::STATUS_DEFAULT,\n ],\n $data\n )\n );\n }\n\n public function getOrCreateReportResult(AutomatedReport $automatedReport, array $data = []): AutomatedReportResult\n {\n $existing = $this->automatedReportsRepository->findLatestSameDayDefaultOrFailedResult($automatedReport);\n\n if ($existing !== null) {\n $existing->update(['status' => AutomatedReportResult::STATUS_DEFAULT]);\n\n return $existing;\n }\n\n return $this->createReportResult($automatedReport, $data);\n }\n\n public function getReportResult(string $resultUuid): AutomatedReportResult\n {\n $report = $this->automatedReportsRepository->findResultByUuid($resultUuid);\n\n if (! $report) {\n throw new ModelNotFoundException('Report Result not found');\n }\n\n return $report;\n }\n\n public function findChildResult(AutomatedReportResult $result, string $type): ?AutomatedReportResult\n {\n return $this->automatedReportsRepository->findChildResult($result, $type);\n }\n\n // prophet API calls\n /**\n * @throws ApplicationException\n */\n public function getGenerateReportPayload(AutomatedReport $automatedReport, string $reportResultUuid): array\n {\n $period = $this->calculateFromAndToDate($automatedReport);\n $fromDate = $period['fromDate'];\n $toDate = $period['toDate'];\n\n return [\n 'team_id' => $automatedReport->getTeamId(),\n 'request_id' => $reportResultUuid,\n 'report_type' => $automatedReport->getType(),\n 'media_types' => $automatedReport->getMediaTypes(),\n 'from_date' => $fromDate->startOfDay()->format(DateTimeInterface::RFC3339),\n 'to_date' => $toDate->endOfDay()->format(DateTimeInterface::RFC3339),\n 'group_ids' => $automatedReport->getGroups(),\n 'call_deal_stage' => $automatedReport->getDealAtCallStages(),\n 'current_deal_stage' => $automatedReport->getCurrentDealStages(),\n 'deal_min_value' => $automatedReport->getDealValueMin(),\n 'deal_max_value' => $automatedReport->getDealValueMax(),\n 'call_types' => $automatedReport->getCallTypes(),\n 'call_duration_min_seconds' => $automatedReport->getCallDurationMin(),\n 'call_duration_max_seconds' => $automatedReport->getCallDurationMax(),\n 'special_requirements' => $automatedReport->getAdditionalPromptInput(),\n 'callback_url' => $this->getCallbackUrl(),\n 'report_period' => $this->formatReportPeriodName(\n $automatedReport->getFrequency(),\n $fromDate,\n $toDate,\n ),\n 'playbook_categories' => $automatedReport->getPlaybookCategories(),\n 'custom_name' => $automatedReport->getCustomName(),\n ];\n }\n\n // $inputPayload - FE payload structure\n public function getActivitiesCountPayload(array $inputPayload): array\n {\n // Use validateAndTransformData to validate and normalize input\n $validatedData = $this->validateAndTransformData($inputPayload);\n $period = $this->calculateFromAndToDatePeriod(\n $validatedData['frequency'],\n Carbon::parse($validatedData['from']),\n Carbon::parse($validatedData['to']),\n );\n $fromDate = $period['fromDate'];\n $toDate = $period['toDate'];\n\n // Create payload similar to getGenerateReportPayload\n return [\n 'team_id' => $validatedData['team_id'],\n 'group_ids' => $validatedData['groups'] ?? [],\n 'report_type' => $validatedData['type'],\n 'from_date' => $fromDate->format(DateTimeInterface::RFC3339),\n 'to_date' => $toDate->format(DateTimeInterface::RFC3339),\n 'call_deal_stage' => $validatedData['deal_at_call_stages'] ?? [],\n 'current_deal_stage' => $validatedData['current_deal_stages'] ?? [],\n 'deal_min_value' => $validatedData['deal_value_min'] ?? null,\n 'deal_max_value' => $validatedData['deal_value_max'] ?? null,\n 'call_types' => $validatedData['call_types'],\n 'call_duration_min_seconds' => $validatedData['call_duration_min'] ?? null,\n 'call_duration_max_seconds' => $validatedData['call_duration_max'] ?? null,\n 'special_requirements' => $validatedData['additional_prompt_input'] ?? null,\n 'playbook_categories' => $validatedData['playbook_categories'] ?? [],\n 'request_id' => null,\n 'callback_url' => null,\n ];\n }\n\n public function shouldSendReport(array $users, ?CarbonInterface $generatedAt = null): bool\n {\n if (empty($users)) {\n return false;\n }\n\n $earliestTz = collect($users)\n ->mapWithKeys(function (array $user) {\n $tz = new DateTimeZone($user['timezone']);\n $nowUtc = new DateTime('now', new DateTimeZone('UTC'));\n $offset = $tz->getOffset($nowUtc);\n\n return [$user['timezone'] => $offset];\n })\n ->sortDesc()\n ->keys()\n ->first();\n\n $now = Carbon::now($earliestTz);\n $isScheduledTime = (int) $now->format('H') === self::SENT_REPORT_AT_HOURS;\n\n if ($isScheduledTime) {\n return true;\n }\n\n return $this->hasPassedScheduledTime($generatedAt, $earliestTz);\n }\n\n public function hasPassedScheduledTime(?CarbonInterface $generatedAt, string $timezone): bool\n {\n if ($generatedAt === null) {\n return false;\n }\n\n $now = Carbon::now($timezone);\n $scheduledTime = $now->copy()->setTime(self::SENT_REPORT_AT_HOURS, 0, 0);\n\n if ($now->hour < self::SENT_REPORT_AT_HOURS) {\n $scheduledTime = $scheduledTime->subDay();\n }\n\n $scheduledTimeUtc = $scheduledTime->copy()->utc();\n $generatedAtUtc = $generatedAt->copy()->utc();\n $nowUtc = $now->copy()->utc();\n\n return $generatedAtUtc->lt($scheduledTimeUtc) && $nowUtc->gt($scheduledTimeUtc);\n }\n\n public function calculateFromAndToDatePeriod(\n string $frequency,\n ?Carbon $fromDate = null,\n ?Carbon $toDate = null,\n DateTimeZone|string|null $timezone = null,\n ): array {\n if ($frequency === self::FREQUENCY_ONE_OFF) {\n return [\n 'fromDate' => $fromDate,\n 'toDate' => $toDate,\n ];\n }\n\n $now = Carbon::now($timezone);\n\n return match ($frequency) {\n self::FREQUENCY_DAILY => [\n 'fromDate' => $now->copy()->subDay()->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_WEEKLY => [\n 'fromDate' => $now->copy()->subWeek()->startOfWeek(CarbonInterface::MONDAY),\n 'toDate' => $now->copy()->subWeek()->endOfWeek(CarbonInterface::SUNDAY),\n ],\n self::FREQUENCY_MONTHLY => [\n 'fromDate' => $now->copy()->subMonthNoOverflow()->startOfMonth(),\n 'toDate' => $now->copy()->subMonthNoOverflow()->endOfMonth(),\n ],\n self::FREQUENCY_QUARTERLY => [\n 'fromDate' => $now->copy()->subQuarterNoOverflow()->startOfQuarter(),\n 'toDate' => $now->copy()->subQuarterNoOverflow()->endOfQuarter(),\n ],\n default => throw new InvalidArgumentException(\"Unsupported frequency: {$frequency}\"),\n };\n }\n\n private function calculateFromAndToDate(AutomatedReport $automatedReport): array\n {\n return $this->calculateFromAndToDatePeriod(\n $automatedReport->getFrequency(),\n $automatedReport->getFrom(),\n $automatedReport->getTo()\n );\n }\n\n public function getAskJiminnyGenerateReportPayload(\n AutomatedReport $automatedReport,\n AutomatedReportResult $reportResult,\n array $activityIds,\n ): array {\n return [\n 'user_question' => $automatedReport->getAskAnythingPrompt()?->getContent(),\n 'call_ids' => array_map('strval', $activityIds),\n 'team_id' => $automatedReport->getTeamId(),\n 'request_id' => $reportResult->getUuid(),\n 'callback_url' => $this->getCallbackUrl(),\n 'report_period' => $this->getReportPeriodName($reportResult),\n 'report_name' => $automatedReport->getCustomName(),\n ];\n }\n\n private function getCallbackUrl(): string\n {\n return $this->webhookService->route('jiminny.webhook.reports.ready');\n }\n\n /**\n * Validate and transform payload data for automated reports\n *\n * @param array $data\n *\n * @throws InvalidArgumentException\n *\n * @return array\n */\n private function validateAndTransformData(array $data): array\n {\n // Validate organization (team) and check feature\n $team = $this->validateOrganization($data['organization'] ?? null);\n\n $status = $this->validateReportStatus($data['report_enabled'] ?? null);\n $type = $this->validateReportType($data['report_type'] ?? null);\n $frequency = $this->validateFrequency($data['frequency'] ?? null);\n $additionalPromptInput = $this->validateAdditionalPromptInput(\n $data['additional_prompt_input'] ?? null\n );\n $customReportName = $this->validateCustomReportName($data['custom_name'] ?? null);\n\n // Prepare data for the database\n $reportData = [\n 'team_id' => $team->getId(),\n 'type' => $type,\n 'status' => $status,\n 'frequency' => $frequency,\n 'additional_prompt_input' => $additionalPromptInput,\n 'custom_name' => $customReportName,\n ];\n\n // Validate deal values\n $reportData = $this->validateDealValues($data, $reportData);\n\n // Validate date range\n $reportData = $this->validateDateRange($data, $reportData, $frequency);\n\n // Validate call durations\n $reportData = $this->validateCallDurations($data, $reportData);\n\n // Validate call types\n $reportData = $this->validateCallTypes($data, $reportData);\n\n // Validate media types\n $reportData = $this->validateMediaTypes($data, $reportData);\n\n // Validate groups\n if (isset($data['teams'])) {\n $reportData['groups'] = $this->validateAndGetGroupIds($team, $data['teams']);\n }\n\n // Validate deal stages\n $reportData = $this->validateDealStages($data, $reportData, $team, $type);\n\n // Validate playbook categories\n $reportData = $this->validatePlaybookCategories($data, $reportData, $team);\n\n // Validate recipients\n $reportData['recipients'] = [\n 'users' => $this->validateAndGetUserIdsByTeam($team, $data['recipients'] ?? []),\n ];\n\n if (isset($data['jiminny_recipients'])) {\n // Validate Jiminny recipients\n $reportData['jiminny_recipients'] = [\n 'users' => $this->validateAndGetJiminnyUserIds((array) $data['jiminny_recipients']),\n ];\n }\n\n return $reportData;\n }\n\n private function validateDealValues(array $data, array $reportData): array\n {\n if (isset($data['min_deal_value'])) {\n $reportData['deal_value_min'] = (int) $data['min_deal_value'];\n\n if ($reportData['deal_value_min'] > 4294967295 || $reportData['deal_value_min'] < 0) {\n throw new InvalidArgumentException('Min deal value should be between 0 and 4294967295');\n }\n }\n\n if (isset($data['max_deal_value'])) {\n $reportData['deal_value_max'] = (int) $data['max_deal_value'];\n\n if ($reportData['deal_value_max'] > 4294967295 || $reportData['deal_value_max'] < 0) {\n throw new InvalidArgumentException('Max deal value should be between 0 and 4294967295');\n }\n }\n\n if (isset($data['min_deal_value'], $data['max_deal_value'])\n && $data['min_deal_value'] > $data['max_deal_value']\n ) {\n throw new InvalidArgumentException('Min deal value cannot be greater than max deal value');\n }\n\n return $reportData;\n }\n\n private function validateDateRange(array $data, array $reportData, string $frequency): array\n {\n // Set date range only for one_off frequency\n if ($frequency === 'one_off') {\n if (isset($data['start_date_period'])) {\n $reportData['from'] = $this->parseDate($data['start_date_period']);\n }\n\n if (isset($data['end_date_period'])) {\n $reportData['to'] = $this->parseDate($data['end_date_period']);\n }\n\n if (empty($reportData['from']) || empty($reportData['to'])) {\n throw new InvalidArgumentException(\n 'Start date and end date are required for one_off frequency'\n );\n }\n } else {\n $reportData['from'] = null;\n $reportData['to'] = null;\n }\n\n return $reportData;\n }\n\n private function validateCallDurations(array $data, array $reportData): array\n {\n // Convert call durations from minutes to seconds\n if (isset($data['min_call_duration'])) {\n $reportData['call_duration_min'] = (int) $data['min_call_duration'] * 60;\n\n if ($reportData['call_duration_min'] > 4294967295 || $reportData['call_duration_min'] < 0) {\n throw new InvalidArgumentException('Min call duration should be between 0 and 4294967295');\n }\n }\n\n if (isset($data['max_call_duration'])) {\n $reportData['call_duration_max'] = (int) $data['max_call_duration'] * 60;\n\n if ($reportData['call_duration_max'] > 4294967295 || $reportData['call_duration_max'] < 0) {\n throw new InvalidArgumentException('Max call duration should be between 0 and 4294967295');\n }\n }\n\n return $reportData;\n }\n\n private function validateCallTypes(array $data, array $reportData): array\n {\n // Set call types\n $reportData['call_types'] = $data['call_type'] ?? [];\n if (empty($reportData['call_types'])) {\n $reportData['call_types'] = self::getCallTypes();\n }\n\n foreach ($reportData['call_types'] as $callType) {\n if (! in_array($callType, self::getCallTypes(), true)) {\n throw new InvalidArgumentException(sprintf('Call type %s is invalid', $callType));\n }\n }\n\n return $reportData;\n }\n\n private function validateMediaTypes(array $data, array $reportData): array\n {\n // Set media types from input data\n $reportData['media_types'] = $data['media_types'] ?? [];\n\n if (empty($reportData['media_types'])) {\n throw new InvalidArgumentException('Media types are required');\n }\n\n foreach ($reportData['media_types'] as $mediaType) {\n if (! in_array($mediaType, self::MEDIA_TYPES, true)) {\n throw new InvalidArgumentException(sprintf('Media type %s is invalid', $mediaType));\n }\n }\n\n return $reportData;\n }\n\n private function validateDealStages(array $data, array $reportData, Team $team, string $reportType): array\n {\n // Validate and set deal stages\n if (isset($data['deal_stage_at_call'])) {\n $reportData['deal_at_call_stages'] =\n $this->validateAndGetDealStageIds($team, $data['deal_stage_at_call'], 'Deal stage at call');\n }\n\n if (isset($data['current_deal_stage'])) {\n $reportData['current_deal_stages'] =\n $this->validateAndGetDealStageIds($team, $data['current_deal_stage'], 'Current deal stage');\n }\n\n // Ensure current_deal_stage is not provided for loss_analysis report type\n if ($reportType === self::TYPE_LOSS_ANALYSIS && ! empty($data['current_deal_stage'])) {\n throw new InvalidArgumentException('Current deal stage is not applicable for Loss Analysis reports');\n }\n\n return $reportData;\n }\n\n // transform uuid to id\n private function validatePlaybookCategories(array $data, array $reportData, Team $team): array\n {\n $key = 'playbook_categories';\n\n if (isset($data[$key])) {\n $payloadIds = $data[$key];\n $ids = [];\n\n foreach ($payloadIds as $uuid) {\n $uuid = (string) $uuid;\n\n try {\n $playbookCategory = $this->playbookCategoryRepository->findByUuid($uuid);\n } catch (Throwable $throwable) {\n Log::error(__METHOD__ . ' ' . $throwable->getMessage());\n\n throw new InvalidArgumentException(sprintf('Playbook category %s not found', $uuid));\n }\n\n if (! $playbookCategory) {\n throw new InvalidArgumentException(sprintf('Playbook category %s not found', $uuid));\n }\n\n if (! $playbookCategory->hasPlaybook()) {\n throw new InvalidArgumentException(sprintf('Playbook category %s has no playbook', $uuid));\n }\n\n if ($playbookCategory->getPlaybook()->getTeamId() !== $team->getId()) {\n throw new InvalidArgumentException(\n sprintf('Playbook category %s not found for team %s', $uuid, $team->getUuid())\n );\n }\n\n $ids[] = $playbookCategory->getId();\n }\n\n $reportData[$key] = $ids;\n }\n\n return $reportData;\n }\n\n private function validateReportStatus($status): bool\n {\n if (! in_array($status, [true, false], true)) {\n throw new InvalidArgumentException('Report status is invalid');\n }\n\n return $status;\n }\n\n private function validateReportType($type): string\n {\n if (! in_array($type, self::getTypes(), true)) {\n throw new InvalidArgumentException(sprintf('Report type is invalid: %s', $type));\n }\n\n return $type;\n }\n\n private function validateFrequency($frequency): string\n {\n if (! in_array($frequency, self::getFrequencies(), true)) {\n throw new InvalidArgumentException('Frequency is invalid');\n }\n\n return $frequency;\n }\n\n private function validateAdditionalPromptInput(?string $additionalPromptInput): ?string\n {\n if ($additionalPromptInput && strlen($additionalPromptInput) > 5000) {\n throw new InvalidArgumentException('Additional Prompt Input should be less than 5000 characters');\n }\n\n return $additionalPromptInput;\n }\n\n private function validateCustomReportName(?string $customReportName): ?string\n {\n if ($customReportName === null || $customReportName === '') {\n return null;\n }\n\n if (strlen($customReportName) > 70) {\n throw new InvalidArgumentException('Custom report name should be less than 70 characters');\n }\n\n return $customReportName;\n }\n\n private function validateOrganization(?string $organizationUuid): Team\n {\n if (! $organizationUuid) {\n throw new InvalidArgumentException('Organization is required');\n }\n\n $team = $this->teamRepository->idOrUuid($organizationUuid);\n\n if (! $team) {\n throw new InvalidArgumentException('Organization not found');\n }\n\n if (! $team->hasFeature(FeatureEnum::AUTOMATED_REPORTS)) {\n throw new InvalidArgumentException('Organization does not have the Automated Reports feature');\n }\n\n return $team;\n }\n\n private function validateAndGetGroupIds(Team $team, array $teamUuids): array\n {\n $groupIds = [];\n\n foreach ($teamUuids as $uuid) {\n $group = $this->groupRepository->findByUuid($uuid);\n\n if ($group === null || $group->getTeamId() !== $team->getId()) {\n throw new InvalidArgumentException(\n sprintf('Group %s not found for team %s', $uuid, $team->getUuid())\n );\n }\n\n $groupIds[] = $group->getId();\n\n }\n\n return $groupIds;\n }\n\n private function validateAndGetDealStageIds(Team $team, array $stageUuids, string $propertyLabel): array\n {\n $stageIds = [];\n\n foreach ($stageUuids as $uuid) {\n $stage = $this->stageRepository->findByUuid($uuid);\n\n if ($stage === null || $stage->getTeamId() !== $team->getId()) {\n throw new InvalidArgumentException(\n sprintf('Stage %s not found for team %s for %s', $uuid, $team->getUuid(), $propertyLabel)\n );\n }\n\n $stageIds[] = $stage->getId();\n }\n\n return $stageIds;\n }\n\n private function validateAndGetUserIds(array $userUuids, callable $teamCheck): array\n {\n if (empty($userUuids)) {\n return [];\n }\n\n $userIds = [];\n\n foreach ($userUuids as $uuid) {\n $user = $this->userRepository->findByUuid($uuid);\n\n if (! $user || ! $user->isStatusActive()) {\n throw new InvalidArgumentException(\n sprintf('User %s not found or is not active', $uuid)\n );\n }\n\n if (! $teamCheck($user)) {\n throw new InvalidArgumentException(\n sprintf('User %s does not belong to the allowed team(s)', $uuid)\n );\n }\n\n $userIds[] = $user->getId();\n }\n\n return $userIds;\n }\n\n private function validateAndGetUserIdsByTeam(Team $team, array $userUuids): array\n {\n return $this->validateAndGetUserIds($userUuids, fn ($user) => $user->getTeamId() === $team->getId());\n }\n\n private function validateAndGetJiminnyUserIds(array $userUuids): array\n {\n $allowedTeamIds = config('kiosk.teamIds', []);\n\n return $this->validateAndGetUserIds($userUuids, fn ($user) => in_array($user->getTeamId(), $allowedTeamIds, true));\n }\n\n private function parseDate(string $dateString): string\n {\n return date('Y-m-d H:i:s', strtotime($dateString));\n }\n\n private function generateReportResultViewUrl(AutomatedReportResult $result): string\n {\n $mediaResource = $this->getReportMediaRouteResource($result);\n\n return route('ai-reports.' . $mediaResource . '.view', ['uuid' => $result->getUuid()]);\n }\n\n private function generateReportResultDownloadUrl(AutomatedReportResult $result): string\n {\n $mediaResource = $this->getReportMediaRouteResource($result);\n\n return route('ai-reports.' . $mediaResource . '.download', ['uuid' => $result->getUuid()]);\n }\n\n private function getReportMediaRouteResource(AutomatedReportResult $result): string\n {\n if ($result->getMediaType() === self::MEDIA_TYPE_PDF) {\n return self::PDF_KEY;\n } elseif ($result->getMediaType() === self::MEDIA_TYPE_PODCAST) {\n return self::AUDIO_KEY;\n }\n\n throw new \\InvalidArgumentException('Unknown media type.');\n }\n\n public function getMediaPath(AutomatedReportResult $result): ?string\n {\n $url = match ($result->getMediaType()) {\n self::MEDIA_TYPE_PDF => $result->getPdfUrl(),\n self::MEDIA_TYPE_PODCAST => $result->getPodcastAudioUrl(),\n default => null,\n };\n\n if ($url === null) {\n return null;\n }\n\n $path = parse_url(trim($url, '\"\\''), PHP_URL_PATH);\n\n return $path ?: null;\n }\n\n public function getFilenameSuffix(AutomatedReportResult $result): ?string\n {\n return match ($result->getMediaType()) {\n self::MEDIA_TYPE_PODCAST => 'Podcast',\n default => null,\n };\n }\n\n public function getMailSubjectSuffix(AutomatedReportResult $result): string\n {\n return match ($result->getMediaType()) {\n self::MEDIA_TYPE_PDF => 'report',\n self::MEDIA_TYPE_PODCAST => 'podcast',\n default => '',\n };\n }\n\n public function getMediaTypeMetadata(AutomatedReportResult $result): array\n {\n return match ($result->getMediaType()) {\n self::MEDIA_TYPE_PODCAST => ['extension' => 'mp3', 'mime' => 'audio/mpeg'],\n self::MEDIA_TYPE_PDF => ['extension' => 'pdf', 'mime' => 'application/pdf'],\n default => ['extension' => null, 'mime' => null],\n };\n }\n\n public function deleteS3Files(AutomatedReportResult $result): void\n {\n $teamUuid = $result->getReport()->getTeam()->getUuid();\n $reportUuid = $result->getUuid();\n\n // delete all files for a report uuid no mather of pdf, podcast, or both\n // in case of both - the podcast files are linked to the pdf (parent) uuid\n // pdf and podcast date times should be close\n $path = sprintf('%s/%s/%s', $teamUuid, self::S3_DIR, $reportUuid);\n\n foreach (self::FILE_EXTENSIONS_VARIANTS as $extension) {\n $file = $path . '.' . $extension;\n\n if (Storage::exists($file)) {\n Storage::delete($file);\n Log::info('[Reports] Deleted S3 file', [\n 'path' => $file,\n ]);\n }\n }\n\n foreach (self::FILE_PODCAST_EXTENSIONS_VARIANTS as $extension) {\n $file = $path . '_podcast.' . $extension;\n\n if (Storage::exists($file)) {\n Storage::delete($file);\n Log::info('[Reports] Deleted Podcast S3 file', [\n 'path' => $file,\n ]);\n }\n }\n }\n\n /**\n *\n * @param int|null $teamId Optional team ID to filter results\n *\n * @return Collection<int, int> Collection of team IDs\n */\n public function getTeamIdsWithReportsResults(?int $teamId = null): Collection\n {\n return $this->automatedReportsRepository->getTeamIdsWithReportsResults($teamId);\n }\n\n /**\n * Core delete logic for report results using a query\n *\n * @param Builder $query\n * @param array $logContext\n *\n * @return int\n */\n private function deleteReportResultsByQuery(Builder $query, array $logContext = []): int\n {\n $deletedCount = 0;\n\n if ($query->exists()) {\n Log::info(\n 'Run delete report results',\n array_merge(\n $logContext,\n [\n 'service' => 'AutomatedReportsService',\n ]\n )\n );\n\n $query->chunkById(50, function ($results) use (&$deletedCount, $logContext) {\n foreach ($results as $result) {\n $this->deleteReportResult($result);\n $deletedCount++;\n\n Log::info(\n 'Deleted a report result',\n array_merge(\n $logContext,\n [\n 'result_id' => $result->getId(),\n 'report_id' => $result->getReportId(),\n ]\n )\n );\n }\n });\n }\n\n return $deletedCount;\n }\n\n /**\n * Delete report results for a team by retention period\n *\n * @param Team $team\n * @param CarbonImmutable $retentionDate\n *\n * @return int Number of deleted report results\n */\n public function deleteReportsResultsInRetentionPeriod(Team $team, CarbonImmutable $retentionDate): int\n {\n $reportIds = $this->automatedReportsRepository->getReportIdsByTeam($team);\n\n if ($reportIds->isEmpty()) {\n return 0;\n }\n\n $query = $this->automatedReportsRepository\n ->getReportResultsQueryForRetention($team, $retentionDate);\n\n return $this->deleteReportResultsByQuery($query, [\n 'team_id' => $team->getId(),\n 'retention_date' => $retentionDate->toDateTimeString(),\n ]);\n }\n\n /**\n * Delete ALL report results for a specific automated report\n *\n * @param string $uuid\n *\n * @return int\n */\n public function deleteReportResults(string $uuid): int\n {\n $report = $this->getReport($uuid);\n\n $query = $this->automatedReportsRepository->getResultsByReportQuery($report);\n\n return $this->deleteReportResultsByQuery($query, [\n 'report_uuid' => $uuid,\n 'report_id' => $report->getId(),\n ]);\n }\n\n public function deleteReportResult(AutomatedReportResult $result): void\n {\n $this->deleteS3Files($result);\n\n $result->delete();\n }\n\n /**\n * Get all reports for a specific team\n *\n * @param Team $team\n *\n * @return \\Illuminate\\Database\\Eloquent\\Collection\n */\n public function getTeamReports(Team $team): \\Illuminate\\Database\\Eloquent\\Collection\n {\n return $this->automatedReportsRepository->getReportsByTeam($team);\n }\n\n /**\n * Get all report results for a specific report\n *\n * @param AutomatedReport $report\n *\n * @return \\Illuminate\\Database\\Eloquent\\Collection\n */\n public function getReportResults(AutomatedReport $report): \\Illuminate\\Database\\Eloquent\\Collection\n {\n return $this->automatedReportsRepository->getResultsByReport($report);\n }\n\n public function deleteAllReportResults(AutomatedReport $report): void\n {\n $results = $this->getReportResults($report);\n\n /** @var AutomatedReportResult $result */\n foreach ($results as $result) {\n Log::info('Deleting result', [\n 'report' => $report->getId(),\n 'result' => $result->getId(),\n ]);\n\n $this->deleteReportResult($result);\n }\n }\n\n public function deleteAllData(Team $team): void\n {\n Log::info('Deleting automated report and results for team', [\n 'team' => $team->getId(),\n ]);\n\n $reports = $this->getTeamReports($team);\n\n /** @var AutomatedReport $report */\n foreach ($reports as $report) {\n Log::info('Deleting report', [\n 'team' => $team->getId(),\n 'report' => $report->getId(),\n ]);\n\n $this->deleteAllReportResults($report);\n\n $report->delete();\n }\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Services\\Kiosk\\AutomatedReports;\n\nuse Carbon\\CarbonImmutable;\nuse Carbon\\CarbonInterface;\nuse Carbon\\Exceptions\\InvalidFormatException;\nuse DateTime;\nuse DateTimeInterface;\nuse DateTimeZone;\nuse Illuminate\\Contracts\\Bus\\Dispatcher as BusDispatcher;\nuse Illuminate\\Database\\Eloquent\\Builder;\nuse Illuminate\\Support\\Carbon;\nuse Illuminate\\Support\\Collection;\nuse Illuminate\\Support\\Facades\\Log;\nuse Illuminate\\Support\\Facades\\Storage;\nuse Jiminny\\Component\\ActivitySearch\\FilterDefinition\\InputTypeEnum;\nuse Jiminny\\Component\\AskAnything\\AskAnythingPromptService;\nuse Jiminny\\Component\\AskAnything\\Dtos\\AskAnythingPromptDto;\nuse Jiminny\\Component\\UrlGenerator\\Webhook;\nuse Jiminny\\Contracts\\Repositories\\PlaybookCategoryRepository;\nuse Jiminny\\Contracts\\Repositories\\TeamRepository;\nuse Jiminny\\Contracts\\Repositories\\UserRepository;\nuse Jiminny\\Exceptions\\ApplicationException;\nuse Jiminny\\Exceptions\\InvalidArgumentException;\nuse Jiminny\\Exceptions\\ModelNotFoundException;\nuse Jiminny\\Jobs\\AutomatedReports\\RequestGenerateReportJob;\nuse Jiminny\\Models\\Activity\\Search;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPrompt;\nuse Jiminny\\Models\\AskAnything\\AskAnythingPromptTarget;\nuse Jiminny\\Models\\AutomatedReport;\nuse Jiminny\\Models\\AutomatedReportResult;\nuse Jiminny\\Models\\Contracts\\UserContract;\nuse Jiminny\\Models\\Feature\\FeatureEnum;\nuse Jiminny\\Models\\Partner;\nuse Jiminny\\Models\\Team;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\AskAnythingRepository;\nuse Jiminny\\Repositories\\AutomatedReportsRepository;\nuse Jiminny\\Repositories\\GroupRepository;\nuse Jiminny\\Repositories\\SearchRepository;\nuse Jiminny\\Repositories\\StageRepository;\nuse Throwable;\n\nclass AutomatedReportsService\n{\n public const string TYPE_LOSS_ANALYSIS = 'loss_analysis';\n public const string TYPE_ASK_JIMINNY = 'ask_jiminny';\n\n /**\n * Standard report types (used by kiosk for existing automated reports).\n */\n // @TODO this will add filter, however if we need to control feature by FF we need conditional logic\n public const array TYPES = [\n ['id' => 'exec_summary', 'name' => 'Exec Summary'],\n ['id' => 'coaching_profiles', 'name' => 'Coaching Profiles'],\n ['id' => 'product_feedback', 'name' => 'Product Feedback'],\n ['id' => self::TYPE_LOSS_ANALYSIS, 'name' => 'Loss Analysis'],\n// ['id' => 'questions', 'name' => 'Questions'],\n// ['id' => 'statistical_quant', 'name' => 'Statistical Quantitative'],\n ];\n\n public const array ALL_TYPES = [\n ...self::TYPES,\n ['id' => self::TYPE_ASK_JIMINNY, 'name' => 'Ask Jiminny'],\n ];\n\n public const string FREQUENCY_DAILY = 'daily';\n public const string FREQUENCY_WEEKLY = 'weekly';\n public const string FREQUENCY_MONTHLY = 'monthly';\n public const string FREQUENCY_QUARTERLY = 'quarterly';\n public const string FREQUENCY_ONE_OFF = 'one_off';\n\n /**\n * Frequencies for standard (non-Ask Jiminny) reports.\n */\n public const array FREQUENCIES = [\n ['id' => self::FREQUENCY_WEEKLY, 'name' => 'Weekly'],\n ['id' => self::FREQUENCY_MONTHLY, 'name' => 'Monthly'],\n ['id' => self::FREQUENCY_QUARTERLY, 'name' => 'Quarterly'],\n ['id' => self::FREQUENCY_ONE_OFF, 'name' => 'One-off'],\n ];\n\n /**\n * Frequencies for Ask Jiminny reports.\n */\n public const array ASK_JIMINNY_FREQUENCIES = [\n ['id' => self::FREQUENCY_DAILY, 'name' => 'Daily'],\n ['id' => self::FREQUENCY_WEEKLY, 'name' => 'Weekly'],\n ['id' => self::FREQUENCY_MONTHLY, 'name' => 'Monthly'],\n ];\n\n public const string MEDIA_TYPE_PDF = 'pdf';\n public const string MEDIA_TYPE_PODCAST = 'podcast';\n public const array MEDIA_TYPES = [self::MEDIA_TYPE_PDF, self::MEDIA_TYPE_PODCAST];\n public const array MEDIA_TYPE_OBJECT_PDF = ['id' => self::MEDIA_TYPE_PDF, 'name' => 'PDF'];\n public const array MEDIA_TYPE_OBJECT_PODCAST = ['id' => self::MEDIA_TYPE_PODCAST, 'name' => 'Podcast'];\n public const array MEDIA_TYPE_OBJECTS = [self::MEDIA_TYPE_OBJECT_PDF, self::MEDIA_TYPE_OBJECT_PODCAST];\n\n public const array CALL_TYPE_CONFERENCE = ['id' => 'conference', 'name' => 'Conference'];\n public const array CALL_TYPE_DIALER = ['id' => 'dialer', 'name' => 'Dialer'];\n public const int SENT_REPORT_AT_HOURS = 5;\n public const string PDF_KEY = 'pdf';\n public const string AUDIO_KEY = 'audio';\n\n private const array ALL_FREQUENCIES = [\n ['id' => self::FREQUENCY_DAILY, 'name' => 'Daily'],\n ['id' => self::FREQUENCY_WEEKLY, 'name' => 'Weekly'],\n ['id' => self::FREQUENCY_MONTHLY, 'name' => 'Monthly'],\n ['id' => self::FREQUENCY_QUARTERLY, 'name' => 'Quarterly'],\n ['id' => self::FREQUENCY_ONE_OFF, 'name' => 'One-off'],\n ];\n private const string S3_DIR = 'reports';\n private const array FILE_EXTENSIONS_VARIANTS = ['html', 'MD', 'pdf'];\n private const array FILE_PODCAST_EXTENSIONS_VARIANTS = ['json', 'mp3', 'ssml'];\n\n public function __construct(\n private readonly TeamRepository $teamRepository,\n private readonly GroupRepository $groupRepository,\n private readonly UserRepository $userRepository,\n private readonly StageRepository $stageRepository,\n private readonly DealStagesService $dealStagesService,\n private readonly RecipientsService $recipientsService,\n private readonly AutomatedReportsRepository $automatedReportsRepository,\n private readonly Webhook $webhookService,\n private readonly BusDispatcher $dispatcher,\n private readonly ActivityTypeService $activityTypeService,\n private readonly PlaybookCategoryRepository $playbookCategoryRepository,\n private readonly AskAnythingPromptService $askAnythingPromptService,\n private readonly SearchRepository $activitySearchRepository,\n private readonly AskAnythingRepository $askAnythingRepository,\n ) {\n }\n\n public static function getTypes(): array\n {\n $types = self::TYPES;\n\n return array_map(static function ($type) {\n return $type['id'];\n }, $types);\n }\n\n public static function getCallTypes(): array\n {\n return array_map(static function ($callType) {\n return $callType['id'];\n }, [self::CALL_TYPE_CONFERENCE, self::CALL_TYPE_DIALER]);\n }\n\n public static function getFrequencies(): array\n {\n return array_map(static function ($frequency) {\n return $frequency['id'];\n }, self::FREQUENCIES);\n }\n\n // front-facing structure\n public function getReportEnabledFieldData(bool $value = false): array\n {\n return [\n 'id' => 'report_enabled',\n 'label' => '',\n 'inputType' => InputTypeEnum::TOGGLE,\n 'value' => $value,\n ];\n }\n\n // Organizations = Teams\n public function getOrganizationFieldData(?string $value = null, bool $shortVersion = false, ?Partner $partner = null): array\n {\n $options = $this->getTeams(partner: $partner);\n\n if ($shortVersion) {\n return [\n 'id' => 'organization',\n 'label' => 'Organization',\n 'options' => $options,\n ];\n }\n\n return [\n 'id' => 'organization',\n 'label' => 'Organization',\n 'inputType' => InputTypeEnum::DROPDOWN,\n 'required' => true,\n 'placeholder' => 'Select',\n 'options' => $options,\n 'value' => $value,\n 'dependencies' => [\n 'teams',\n 'deal_stage_at_call',\n 'current_deal_stage',\n 'recipients',\n ActivityTypeService::PLAYBOOK_CATEGORIES_KEY,\n ],\n 'dependsOn' => [],\n ];\n }\n\n // Teams = Groups\n public function getTeamFieldData(array $options = [], array $value = [], bool $shortVersion = false): array\n {\n if ($shortVersion) {\n return [\n 'id' => 'teams',\n 'label' => 'Team',\n 'options' => $options,\n ];\n }\n\n return [\n 'id' => 'teams',\n 'label' => 'Team',\n 'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,\n 'required' => false,\n 'placeholder' => 'Select',\n 'options' => $options,\n 'value' => $value, // value should be an array of objects {id, name}\n 'dependencies' => [ActivityTypeService::PLAYBOOK_CATEGORIES_KEY],\n 'dependsOn' => [],\n ];\n }\n\n public function getReportTypeFieldData(?string $value = null, bool $shortVersion = false, ?Team $team = null): array\n {\n $types = [];\n if ($team instanceof Team) {\n if ($team->hasFeature(FeatureEnum::AUTOMATED_REPORTS)) {\n $types = self::TYPES;\n }\n if ($team->hasFeature(FeatureEnum::ASK_JIMINNY_REPORTS)) {\n $types[] = ['id' => self::TYPE_ASK_JIMINNY, 'name' => 'Ask Jiminny'];\n }\n } else {\n $types = self::TYPES;\n }\n\n if ($shortVersion) {\n return [\n 'id' => 'report_type',\n 'label' => 'Report Type',\n 'options' => $types,\n ];\n }\n\n return [\n 'id' => 'report_type',\n 'label' => 'Report Type',\n 'inputType' => InputTypeEnum::DROPDOWN,\n 'required' => true,\n 'placeholder' => 'Select',\n 'options' => $types,\n 'value' => $value,\n 'dependencies' => [],\n 'dependsOn' => [],\n ];\n }\n\n public function getFrequencyFieldData(?string $value = null): array\n {\n return [\n 'id' => 'frequency',\n 'label' => 'Frequency',\n 'inputType' => InputTypeEnum::DROPDOWN,\n 'required' => true,\n 'placeholder' => 'Select',\n 'options' => self::FREQUENCIES,\n 'value' => $value,\n 'dependencies' => ['period'],\n 'dependsOn' => [],\n ];\n }\n\n public function getPeriodFieldData(?string $valueStartDate = null, ?string $valueEndDate = null): array\n {\n return [\n 'id' => 'period',\n 'label' => 'Select one-off period',\n 'inputType' => InputTypeEnum::DATE_RANGE,\n 'required' => true,\n 'placeholder' => 'Select',\n 'value' => ['startDate' => $valueStartDate, 'endDate' => $valueEndDate],\n 'queryParams' => [\n 'startDate' => 'start_date_period',\n 'endDate' => 'end_date_period',\n ],\n 'dependencies' => [],\n 'dependsOn' => ['frequency'],\n ];\n }\n\n public function getActivityTypesFieldData(?Team $team = null, array $value = [], array $teamsFilter = []): array\n {\n return $this->activityTypeService->getActivityTypeFieldData(team: $team, value: $value, groupIds: $teamsFilter);\n }\n\n public function getDealStageAtCallFieldData(?Team $team = null, array $value = []): array\n {\n return $this->dealStagesService->getDealStageAtCallFieldData(team: $team, value: $value);\n }\n\n public function getCurrentDealStageFieldData(?Team $team = null, array $value = []): array\n {\n return $this->dealStagesService->getCurrentDealStageFieldData(team: $team, value: $value);\n }\n\n public function getDealValueFieldData(?int $valueMin = null, ?int $valueMax = null): array\n {\n return [\n 'id' => 'deal_value',\n 'label' => 'Deal Value',\n 'inputType' => InputTypeEnum::INTEGER_RANGE,\n 'required' => false,\n 'value' => ['min' => $valueMin, 'max' => $valueMax],\n 'queryParams' => [\n 'min' => 'min_deal_value',\n 'max' => 'max_deal_value',\n ],\n 'dependencies' => [],\n 'dependsOn' => [],\n ];\n }\n\n public function getCallTypeFieldData(bool $conferenceOn = false, bool $dialerOn = false): array\n {\n $value = [];\n $conferenceOn && $value[] = self::CALL_TYPE_CONFERENCE;\n $dialerOn && $value[] = self::CALL_TYPE_DIALER;\n\n return [\n 'id' => 'call_type',\n 'label' => 'Call Type',\n 'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,\n 'required' => true,\n 'options' => [\n self::CALL_TYPE_CONFERENCE,\n self::CALL_TYPE_DIALER,\n ],\n 'value' => $value,\n 'dependencies' => [],\n 'dependsOn' => [],\n ];\n }\n\n public function getMediaTypeFieldData(?AutomatedReport $report = null): array\n {\n $value = [];\n\n if ($report) {\n $value = $this->transformMediaTypes($report);\n }\n\n return [\n 'id' => 'media_types',\n 'label' => 'Export as',\n 'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,\n 'required' => true,\n 'options' => self::MEDIA_TYPE_OBJECTS,\n 'value' => $value,\n 'dependencies' => [],\n 'dependsOn' => [],\n ];\n }\n\n public function getCallDurationFieldData(?int $valueMin = null, ?int $valueMax = null): array\n {\n return [\n 'id' => 'call_duration',\n 'label' => 'Call Duration',\n 'inputType' => InputTypeEnum::INTEGER_RANGE,\n 'required' => false,\n 'value' => ['min' => $valueMin, 'max' => $valueMax],\n 'queryParams' => [\n 'min' => 'min_call_duration',\n 'max' => 'max_call_duration',\n ],\n 'dependencies' => [],\n 'dependsOn' => [],\n ];\n }\n\n public function getRecipientsFieldData(?Team $team = null, array $value = []): array\n {\n return $this->recipientsService->getRecipientsFieldData(team: $team, value: $value);\n }\n\n public function getJiminnyRecipientsFieldData(array $value = []): array\n {\n return $this->recipientsService->getJiminnyRecipientsFieldData($value);\n }\n\n public function getAdditionalPromptInputFieldData(?string $value = null): array\n {\n return [\n 'id' => 'additional_prompt_input',\n 'label' => 'Special requirements',\n 'inputType' => InputTypeEnum::TEXTAREA,\n 'required' => false,\n 'placeholder' => 'What should be the focus of the report?',\n 'value' => $value,\n 'dependencies' => [],\n 'dependsOn' => [],\n ];\n }\n\n public function getCustomReportNameFieldData(?string $value = null): array\n {\n return [\n 'id' => 'custom_name',\n 'label' => 'Custom report name',\n 'inputType' => InputTypeEnum::TEXT,\n 'required' => false,\n 'placeholder' => 'Enter custom name',\n 'value' => $value,\n 'dependencies' => [],\n 'dependsOn' => [],\n ];\n }\n\n // data providers\n public function getTeams(?Partner $partner = null): array\n {\n $teams = $this->teamRepository->getTeamsForKiosk(status: Team::STATUS_ACTIVE, partner: $partner);\n\n $teamData = [];\n foreach ($teams as $team) {\n if (! $team->hasFeature(FeatureEnum::AUTOMATED_REPORTS)) {\n continue;\n }\n\n $teamData[] = $this->transformTeam($team);\n }\n\n return $teamData;\n }\n\n public function getTeamGroups(string $teamUuid): array\n {\n $data = [];\n $team = $this->getTeam($teamUuid);\n\n if ($team !== null) {\n $groups = $team->groups()->get();\n\n foreach ($groups as $group) {\n $data[] = [\n 'id' => $group->getUuid(),\n 'name' => $group->getName(),\n ];\n }\n }\n\n return $data;\n }\n\n public function getTeamsGroupsOptions(array $filterTeamUuids = [], ?Partner $partner = null): array\n {\n $data = [];\n $teams = $this->getTeams(partner: $partner);\n\n foreach ($teams as $team) {\n if (! empty($filterTeamUuids) && ! in_array($team['id'], $filterTeamUuids, true)) {\n continue;\n }\n\n $data[] = [\n 'label' => $team['name'],\n 'groups' => $this->getTeamGroups($team['id']),\n ];\n }\n\n return $data;\n }\n\n public function getTeam(string $teamUuid): ?Team\n {\n return $this->teamRepository->idOrUuid($teamUuid);\n }\n\n public function getTeamById(int $teamId): ?Team\n {\n return $this->teamRepository->find($teamId);\n }\n\n public function getGroupsUuids(AutomatedReport $report): array\n {\n $uuids = [];\n $reportGroups = $report->getGroups();\n foreach ($reportGroups as $groupId) {\n if ($group = $this->groupRepository->find($groupId)) {\n $uuids[] = $group->getUuid();\n }\n }\n\n return $uuids;\n }\n\n public function getPlaybookCategoriesUuids(AutomatedReport $report): array\n {\n $uuids = [];\n $playbookCategories = $report->getPlaybookCategories();\n foreach ($playbookCategories as $id) {\n if ($category = $this->playbookCategoryRepository->find($id)) {\n $uuids[] = $category->getUuid();\n }\n }\n\n return $uuids;\n }\n\n public function getDealAtCallStagesUuids(AutomatedReport $report): array\n {\n $uuids = [];\n $reportStages = $report->getDealAtCallStages();\n foreach ($reportStages as $id) {\n if ($stage = $this->stageRepository->find($id)) {\n $uuids[] = $stage->getUuid();\n }\n }\n\n return $uuids;\n }\n\n public function getCurrentDealStagesUuids(AutomatedReport $report): array\n {\n $uuids = [];\n $reportStages = $report->getCurrentDealStages();\n foreach ($reportStages as $id) {\n if ($stage = $this->stageRepository->find($id)) {\n $uuids[] = $stage->getUuid();\n }\n }\n\n return $uuids;\n }\n\n public function getUsersUuids(AutomatedReport $report): array\n {\n return $this->extractUserUuids($report->getRecipients());\n }\n\n public function getJiminnyUsersUuids(AutomatedReport $report): array\n {\n return $this->extractUserUuids($report->getJiminnyRecipients());\n }\n\n /**\n * @param array<string, mixed> $recipients\n */\n private function extractUserUuids(array $recipients): array\n {\n $userIds = $recipients['users'] ?? [];\n\n return collect($userIds)\n ->map(fn ($id) => $this->userRepository->find((int) $id))\n ->filter()\n ->map(fn (UserContract $user) => $user->getUuid())\n ->values()\n ->all();\n }\n\n // get mail data\n public function getRecipientUsers(AutomatedReport $report): array\n {\n return $this->buildRecipientUsers($report->getRecipients());\n }\n\n /**\n * @return array<UserContract>\n */\n public function getRecipientUserObjects(AutomatedReport $report): array\n {\n $userIds = $report->getRecipients()['users'] ?? [];\n\n return collect($userIds)\n ->map(fn ($id) => $this->userRepository->find((int) $id))\n ->filter()\n ->values()\n ->all();\n }\n\n private function getJiminnyRecipientUsers(AutomatedReport $report): array\n {\n return $this->buildRecipientUsers($report->getJiminnyRecipients());\n }\n\n /**\n * @param array<string, mixed> $recipients\n */\n private function buildRecipientUsers(array $recipients): array\n {\n $userIds = $recipients['users'] ?? [];\n\n return collect($userIds)\n ->map(fn ($id) => $this->userRepository->find((int) $id))\n ->filter()\n ->map(fn (UserContract $user) => [\n 'email' => $user->getEmailAddress(),\n 'name' => $user->getName(),\n 'timezone' => $user->getTimezone()->getName(),\n ])\n ->values()\n ->all();\n }\n\n public function getValidRecipientUsers(AutomatedReport $report, bool $includeJiminny = false): array\n {\n if ($report->isAskJiminnyReport()) {\n $recipients = $this->resolveAskJiminnyRecipients($report);\n } else {\n $recipients = $this->getRecipientUsers($report);\n if ($includeJiminny) {\n $recipients = array_merge($recipients, $this->getJiminnyRecipientUsers($report));\n }\n }\n\n $emails = [];\n\n return array_values(array_filter(\n $recipients,\n static function ($recipient) use (&$emails) {\n if (empty($recipient['email']) || in_array($recipient['email'], $emails, true)) {\n return false;\n }\n $emails[] = $recipient['email'];\n\n return true;\n }\n ));\n }\n\n private function resolveAskJiminnyRecipients(AutomatedReport $report): array\n {\n $recipients = [];\n\n $creator = $report->getCreator();\n if ($creator !== null) {\n $recipients[] = [\n 'email' => $creator->getEmailAddress(),\n 'name' => $creator->getName(),\n 'timezone' => $creator->getTimezone()->getName(),\n ];\n }\n\n return array_merge(\n $recipients,\n $this->buildRecipientUsers($report->getRecipients()),\n $this->getGroupRecipientUsers($report),\n );\n }\n\n private function getGroupRecipientUsers(AutomatedReport $report): array\n {\n $users = [];\n foreach ($report->getGroups() as $groupId) {\n $group = $this->groupRepository->find($groupId);\n if ($group === null) {\n continue;\n }\n foreach ($group->getMembers() as $member) {\n $users[] = [\n 'email' => $member->getEmailAddress(),\n 'name' => $member->getName(),\n 'timezone' => $member->getTimezone()->getName(),\n ];\n }\n }\n\n return $users;\n }\n\n public function getReportTypeName(AutomatedReportResult $report): string\n {\n $type = $report->getReport()->getType();\n\n $getType = $this->transformReportType($type);\n\n return $getType['name'];\n }\n\n public function getReportPeriodName(AutomatedReportResult $report): string\n {\n $from = $report->getFromDate();\n $to = $report->getToDate();\n $frequency = $report->getReport()->getFrequency();\n\n if ($from === null || $to === null) {\n if (! $report->getReport()->isAskJiminnyReport()) {\n $invalidPeriod = $from === null ? 'from' : 'to';\n\n throw new ApplicationException('Report period is invalid: ' . $invalidPeriod);\n }\n\n $timezone = $report->getReport()->getCreator()?->getTimezone();\n $period = $this->calculateFromAndToDatePeriod($frequency, timezone: $timezone);\n $from = $period['fromDate'];\n $to = $period['toDate'];\n }\n\n return $this->formatReportPeriodName($frequency, $from, $to);\n }\n\n private function formatReportPeriodName(string $frequency, Carbon $from, Carbon $to): string\n {\n $fromYear = $from->format('Y');\n $toYear = $to->format('Y');\n $differentYears = $fromYear !== $toYear;\n\n switch ($frequency) {\n case self::FREQUENCY_DAILY:\n return $from->format('j M Y');\n\n case self::FREQUENCY_QUARTERLY:\n // 'Jan-Mar 2025' or 'Nov 2024-Jan 2025' if years differ\n $startMonth = $from->format('M');\n $endMonth = $to->copy()->subMonth();\n $endMonthName = $endMonth->format('M');\n $endMonthYear = $endMonth->format('Y');\n\n if ($differentYears) {\n return \"{$startMonth} {$fromYear} - {$endMonthName} {$endMonthYear}\";\n }\n\n return \"{$startMonth} - {$endMonthName} {$toYear}\";\n\n case self::FREQUENCY_MONTHLY:\n // 'May 2025' - monthly reports are always within the same year\n return $from->format('M Y');\n\n case self::FREQUENCY_WEEKLY:\n // '4 - 8 Aug 2025', '27 Oct - 3 Nov 2025', or '28 Dec 2024 - 3 Jan 2025' if years differ\n $startDay = $from->format('j');\n $endDay = $to->format('j');\n $startMonth = $from->format('M');\n $endMonth = $to->format('M');\n\n if ($differentYears) {\n return \"{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n if ($startMonth !== $endMonth) {\n return \"{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n return \"{$startDay} - {$endDay} {$endMonth} {$toYear}\";\n\n case self::FREQUENCY_ONE_OFF:\n // '2 May-31 May 2025' or '15 Dec 2024-15 Jan 2025' if years differ\n $startDay = $from->format('j');\n $startMonth = $from->format('M');\n $endDay = $to->format('j');\n $endMonth = $to->format('M');\n\n // If same month and year, use a format like '2-31 May 2025'\n if ($startMonth === $endMonth && ! $differentYears) {\n return \"{$startDay} - {$endDay} {$startMonth} {$toYear}\";\n }\n\n // If different years, include both years\n if ($differentYears) {\n return \"{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}\";\n }\n\n // Same year but different months\n return \"{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}\";\n\n default:\n // Default format for unknown frequencies\n return $from->format('j M Y') . ' - ' . $to->format('j M Y');\n }\n }\n\n public function getReportTeamsName(AutomatedReportResult $report): string\n {\n $groups = $report->getGroups();\n\n if (empty($groups)) {\n return 'All';\n }\n\n // Get group names from repository\n $groupNames = [];\n foreach ($groups as $groupId) {\n $group = $this->groupRepository->find($groupId);\n if ($group) {\n $groupNames[] = $group->getName();\n }\n }\n\n if (count($groupNames) === 1) {\n // Single team format\n $teamsName = $groupNames[0];\n } else {\n // Multiple teams format\n $teamsName = implode(', ', $groupNames);\n }\n\n return $teamsName;\n }\n\n public function getReportFileName(AutomatedReportResult $report): string\n {\n $customName = $report->getReport()->getCustomName();\n $periodName = $this->getReportPeriodName($report);\n $filenameSuffix = $this->getFilenameSuffix($report);\n\n if ($customName) {\n if ($filenameSuffix) {\n $customName .= \" {$filenameSuffix}\";\n }\n\n return $this->sanitizeFileName(\"{$customName} - {$periodName}\");\n }\n\n $baseName = $this->getReportTypeName($report);\n\n if ($filenameSuffix) {\n $baseName .= \" {$filenameSuffix}\";\n }\n\n return $this->sanitizeFileName(\"{$baseName} - {$periodName} - {$this->getReportTeamsName($report)}\");\n }\n\n public function getReportFileNameWithExtension(AutomatedReportResult $result): string\n {\n $extension = $this->getMediaTypeMetadata($result)['extension'];\n\n return $this->getReportFileName($result) . '.' . $extension;\n }\n\n public function sanitizeFileName(string $fileName): string\n {\n return str_replace(['/', '\\\\'], '-', $fileName);\n }\n\n public function isUserRecipientOfReport(User $user, AutomatedReport $report): bool\n {\n $recipientIds = array_map('intval', $report->getRecipients()['users'] ?? []);\n if (in_array($user->getId(), $recipientIds, true)) {\n return true;\n }\n\n if ($report->isAskJiminnyReport()) {\n $groupId = $user->getGroupId();\n if ($groupId !== null && in_array($groupId, $report->getGroups(), true)) {\n return true;\n }\n }\n\n return false;\n }\n\n public function transformReportResults(Collection $automatedReportResults): array\n {\n $data = [];\n foreach ($automatedReportResults as $automatedReportResult) {\n /** @var AutomatedReportResult $automatedReportResult */\n\n $report = $automatedReportResult->getReport();\n\n $createdBy = $report->getCreator();\n $creator = [\n 'id' => $createdBy?->getUuid(),\n 'name' => $createdBy?->getName(),\n 'email' => $createdBy?->getEmailAddress(),\n 'photoUrl' => $createdBy?->getPhotoUrl(),\n ];\n\n $data[] = [\n 'id' => $automatedReportResult->getUuid(),\n 'name' => $automatedReportResult->getName(),\n 'frequency' => $this->transformFrequency($report->getFrequency()),\n 'recipients' => $this->buildRecipients($report),\n 'report_type' => $this->transformReportType($report->getType()),\n 'media_type' => $automatedReportResult->getMediaType(),\n 'downloadUrl' => $this->generateReportResultDownloadUrl($automatedReportResult),\n 'viewUrl' => $this->generateReportResultViewUrl($automatedReportResult),\n 'generated_at' => $automatedReportResult->getGeneratedAt()?->toIso8601String(),\n 'creator' => $creator,\n ];\n }\n\n return $data;\n }\n\n private function buildRecipients(AutomatedReport $report): array\n {\n $creatorUuid = $report->getCreator()?->getUuid();\n\n $recipients = array_values(array_filter(\n $this->transformRecipients($report->getRecipients()),\n static fn (array $recipient): bool => $recipient['id'] !== $creatorUuid,\n ));\n\n if (! $report->isAskJiminnyReport()) {\n return $recipients;\n }\n\n return [\n ...array_values($this->transformGroups(team: $report->getTeam(), groupsIds: $report->getGroups())),\n ...$recipients,\n ];\n }\n\n public function hasCallTypeConference(AutomatedReport $report): bool\n {\n return in_array(self::CALL_TYPE_CONFERENCE['id'], $report->getCallTypes(), true);\n }\n\n public function hasCallTypeDialer(AutomatedReport $report): bool\n {\n return in_array(self::CALL_TYPE_DIALER['id'], $report->getCallTypes(), true);\n }\n\n // transformers\n private function transformTeam(Team $team): array\n {\n if (! $team->hasFeature(FeatureEnum::AUTOMATED_REPORTS)) {\n return [];\n }\n\n return [\n 'id' => $team->getUuid(),\n 'name' => $team->getName(),\n ];\n }\n\n private function transformReportFullView(AutomatedReport $report): array\n {\n $base = $this->transformReportBase($report);\n\n return $report->getType() === self::TYPE_ASK_JIMINNY\n ? $base + $this->transformAskJiminnyFields($report)\n : $base + $this->transformStandardReportFields($report);\n }\n\n private function transformReportBase(AutomatedReport $report): array\n {\n return [\n 'id' => $report->getUuid(),\n 'organization' => $this->transformOrganization(team: $report->getTeam()),\n 'report_type' => $this->transformReportType($report->getType()),\n 'frequency' => $this->transformFrequency($report->getFrequency()),\n ];\n }\n\n private function transformStandardReportFields(AutomatedReport $report): array\n {\n $team = $report->getTeam();\n\n return [\n 'report_enabled' => $report->getStatus(),\n 'start_date_period' => $report->getFrom()?->format('Y-m-d H:i:s'),\n 'end_date_period' => $report->getTo()?->format('Y-m-d H:i:s'),\n 'deal_value_min' => $report->getDealValueMin(),\n 'deal_value_max' => $report->getDealValueMax(),\n 'call_types' => $this->transformCallType($report->getCallTypes()),\n 'media_types' => $this->transformMediaTypes($report),\n 'call_duration_min' => $this->transformDurationToMinutes($report->getCallDurationMin()),\n 'call_duration_max' => $this->transformDurationToMinutes($report->getCallDurationMax()),\n 'teams' => $this->transformGroups(team: $team, groupsIds: $report->getGroups()),\n 'deal_at_call_stages' => $this->transformStages(team: $team, stagesIds: $report->getDealAtCallStages()),\n 'current_deal_stages' => $this->transformStages(team: $team, stagesIds: $report->getCurrentDealStages()),\n 'recipients' => $this->transformRecipients($report->getRecipients()),\n 'created_by' => $this->transformCreator($report->getCreator()),\n 'additional_prompt_input' => $report->getAdditionalPromptInput(),\n 'custom_name' => $report->getCustomName(),\n 'created_at' => $report->getCreatedAt()->format('Y-m-d H:i:s'),\n 'updated_at' => $report->getUpdatedAt()->format('Y-m-d H:i:s'),\n 'deleted_at' => $report->getDeletedAt()?->format('Y-m-d H:i:s'),\n ];\n }\n\n private function transformAskJiminnyFields(AutomatedReport $report): array\n {\n $team = $report->getTeam();\n $creatorId = $report->getAttribute('created_by');\n $explicitUserIds = array_values(array_filter(\n $report->getRecipients()['users'] ?? [],\n static fn ($id) => $id !== $creatorId\n ));\n\n return [\n 'report_name' => $report->getCustomName(),\n 'enabled' => $report->getStatus(),\n 'share_teams' => $this->transformGroups(team: $team, groupsIds: $report->getGroups()),\n 'share_users' => $this->transformRecipients(['users' => $explicitUserIds]),\n 'saved_search' => $this->transformSafeSearch($report->getSavedSearch()),\n 'ask_jiminny_prompt' => $this->transformAskJiminnyPrompt($report->getAskAnythingPrompt()),\n 'expires_on' => $report->getExpiresAt()?->format('Y-m-d'),\n ];\n }\n\n private function transformOrganization(?Team $team): array\n {\n return [\n 'id' => $team?->getUuid(),\n 'name' => $team?->getName(),\n ];\n }\n\n private function transformReportType(string $type): array\n {\n foreach (self::ALL_TYPES as $typeItem) {\n if ($typeItem['id'] === $type) {\n return $typeItem;\n }\n }\n\n return [];\n }\n\n private function transformCallType(array $types): array\n {\n $result = [];\n $callTypes = [self::CALL_TYPE_CONFERENCE, self::CALL_TYPE_DIALER];\n\n foreach ($types as $type) {\n foreach ($callTypes as $callTypeItem) {\n if ($callTypeItem['id'] === $type) {\n $result[] = $callTypeItem;\n\n break;\n }\n }\n }\n\n return $result;\n }\n\n private function transformMediaTypes(AutomatedReport $report): array\n {\n $values = [];\n\n foreach ($report->getMediaTypes() as $mediaType) {\n if (! in_array($mediaType, self::MEDIA_TYPES, true)) {\n continue;\n }\n\n $values[] = match ($mediaType) {\n self::MEDIA_TYPE_PDF => self::MEDIA_TYPE_OBJECT_PDF,\n self::MEDIA_TYPE_PODCAST => self::MEDIA_TYPE_OBJECT_PODCAST,\n };\n }\n\n return $values;\n }\n\n private function transformFrequency(string $frequency): array\n {\n foreach (self::ALL_FREQUENCIES as $frequencyItem) {\n if ($frequencyItem['id'] === $frequency) {\n return $frequencyItem;\n }\n }\n\n return [];\n }\n\n public function transformDurationToMinutes(?int $duration): ?int\n {\n if (! $duration) {\n return null;\n }\n\n return (int) ($duration / 60);\n }\n\n private function transformGroups(?Team $team, array $groupsIds): array\n {\n if (empty($groupsIds) || ! $team) {\n return [];\n }\n\n $data = [];\n foreach ($groupsIds as $groupId) {\n $group = $team->groups()->where('id', $groupId)->first();\n\n if ($group) {\n $data[] = [\n 'id' => $group->getUuid(),\n 'name' => $group->getName(),\n 'photoUrl' => $group->getPhotoUrl(),\n ];\n }\n }\n\n return $data;\n }\n\n private function transformStages(?Team $team, array $stagesIds): array\n {\n if (empty($stagesIds) || ! $team) {\n return [];\n }\n\n $data = [];\n foreach ($stagesIds as $stageId) {\n $stage = $team->stages()->where('id', $stageId)->first();\n\n if ($stage) {\n $data[] = [\n 'id' => $stage->getUuid(),\n 'name' => $stage->getName(),\n ];\n }\n }\n\n return $data;\n }\n\n private function transformRecipients(array $recipients): array\n {\n $users = [];\n foreach ($recipients['users'] ?? [] as $userId) {\n $users[] = $this->transformUser($userId);\n }\n\n return $users;\n }\n\n private function transformCreator(?User $user): ?array\n {\n if ($user === null) {\n return null;\n }\n\n return $this->transformUser($user->getId());\n }\n\n private function transformAskJiminnyPrompt(?AskAnythingPrompt $prompt): ?array\n {\n if ($prompt === null) {\n return null;\n }\n\n return [\n 'id' => $prompt->getUuid(),\n 'name' => $prompt->getTitle(),\n ];\n }\n\n private function transformSafeSearch(?Search $search): ?array\n {\n if ($search === null) {\n return null;\n }\n\n return [\n 'id' => $search->getUuid(),\n 'name' => $search->getName(),\n ];\n }\n\n private function transformUser(int $userId): array\n {\n /* @var ?User $user */\n $user = $this->userRepository->find($userId);\n\n return [\n 'id' => $user?->getUuid(),\n 'name' => $user?->getName(),\n 'email' => $user?->getEmailAddress(),\n 'photoUrl' => $user?->getPhotoUrl(),\n ];\n }\n\n public function create(array $data): array\n {\n $validatedData = $this->validateAndTransformData($data);\n $validatedData['created_by'] = auth()->id();\n\n $automatedReport = $this->automatedReportsRepository->create($validatedData);\n\n $this->generateOneOffReport($automatedReport);\n\n return $this->transformReportFullView($automatedReport);\n }\n\n public function update(string $uuid, array $data): array\n {\n $validatedData = $this->validateAndTransformData($data);\n $report = $this->automatedReportsRepository->findByUuid($uuid);\n\n if (! $report) {\n throw new InvalidArgumentException('Report not found');\n }\n\n $oldCustomName = $report->getCustomName();\n\n $automatedReport = $this->automatedReportsRepository->update($report, $validatedData);\n\n if ($oldCustomName !== $automatedReport->getCustomName()) {\n $this->updateResultNames($automatedReport);\n }\n\n $this->generateOneOffReport($automatedReport);\n\n return $this->transformReportFullView($automatedReport);\n }\n\n /**\n * Create an Ask Jiminny report.\n */\n public function createAskJiminnyReport(array $data, User $creator): array\n {\n $validatedData = $this->validateAskJiminnyReportData($data, $creator);\n $validatedData['created_by'] = $creator->getId();\n\n $automatedReport = $this->automatedReportsRepository->create($validatedData);\n\n return $this->transformReportFullView($automatedReport);\n }\n\n /**\n * Update an Ask Jiminny report.\n */\n public function updateAskJiminnyReport(AutomatedReport $report, array $data, User $user): array\n {\n if (! $report->isAskJiminnyReport()) {\n throw new InvalidArgumentException('Report is not an Ask Jiminny report');\n }\n\n $validatedData = $this->validateAskJiminnyReportData($data, $user);\n\n $oldCustomName = $report->getCustomName();\n\n $automatedReport = $this->automatedReportsRepository->update($report, $validatedData);\n\n if ($oldCustomName !== $automatedReport->getCustomName()) {\n $this->updateResultNames($automatedReport);\n }\n\n return $this->transformReportFullView($automatedReport);\n }\n\n public function updateAskJiminnyReportStatus(AutomatedReport $report, bool $status): array\n {\n if ($status && $report->isAskJiminnyReport() && ! $report->canExecute()) {\n throw new InvalidArgumentException(\n 'This report is missing a saved search or prompt. ' .\n 'Edit the report to complete the setup before enabling it.'\n );\n }\n\n $this->automatedReportsRepository->update($report, ['status' => $status]);\n\n return $this->transformReportFullView($report->fresh());\n }\n\n /**\n * Validate and transform data for Ask Jiminny reports.\n */\n private function validateAskJiminnyReportData(array $data, User $user): array\n {\n // Validate name\n $name = trim($data['report_name'] ?? '');\n if (empty($name)) {\n throw new InvalidArgumentException('Report name is required');\n }\n if (mb_strlen($name) > 50) {\n throw new InvalidArgumentException('Report name must be 50 characters or less');\n }\n\n // Validate frequency (only daily, weekly, monthly for Ask Jiminny)\n $frequency = $data['frequency'] ?? null;\n $askJiminnyFrequencies = [self::FREQUENCY_DAILY, self::FREQUENCY_WEEKLY, self::FREQUENCY_MONTHLY];\n if (! in_array($frequency, $askJiminnyFrequencies, true)) {\n throw new InvalidArgumentException('Frequency must be daily, weekly, or monthly');\n }\n\n // Validate expiration date\n $expiresAt = $data['expires_on'] ?? null;\n if (empty($expiresAt)) {\n throw new InvalidArgumentException('Expiration date is required');\n }\n\n try {\n $expiresAtDate = Carbon::parse($expiresAt);\n } catch (InvalidFormatException $e) {\n throw new InvalidArgumentException('Expiration date format is invalid');\n }\n $maxExpiration = Carbon::now()->addYear()->endOfDay();\n if ($expiresAtDate->gt($maxExpiration)) {\n throw new InvalidArgumentException('Expiration date cannot be more than 1 year from now');\n }\n if ($expiresAtDate->isPast()) {\n throw new InvalidArgumentException('Expiration date cannot be in the past');\n }\n\n // Validate saved search\n $activitySearchId = $data['saved_search'] ?? null;\n if (empty($activitySearchId)) {\n throw new InvalidArgumentException('Saved search is required');\n }\n $savedSearch = $this->activitySearchRepository->findByUuidAndUser($activitySearchId, $user);\n if (! $savedSearch) {\n throw new InvalidArgumentException('Saved search not found or does not belong to you');\n }\n\n // Validate saved prompt\n $askAnythingPromptId = $data['ask_jiminny_prompt'] ?? null;\n if (empty($askAnythingPromptId)) {\n throw new InvalidArgumentException('Ask Jiminny prompt is required');\n }\n $prompt = $this->askAnythingRepository->getPromptByUuid($askAnythingPromptId);\n if (! $prompt) {\n throw new InvalidArgumentException('Ask Jiminny prompt not found');\n }\n\n // Validate status\n $status = $data['enabled'] ?? false;\n\n $recipientUserIds = [$user->getId()];\n\n if (! empty($data['share_users'])) {\n $sharedUserIds = $this->validateAndGetUserIdsByTeam(\n $user->team,\n (array) $data['share_users']\n );\n $recipientUserIds = array_merge($recipientUserIds, $sharedUserIds);\n }\n\n $sharedGroupIds = [];\n if (! empty($data['share_teams'])) {\n $sharedGroupIds = $this->validateAndGetGroupIds($user->team, (array) $data['share_teams']);\n }\n\n $recipientUserIds = array_values(array_unique($recipientUserIds));\n\n return [\n 'team_id' => $user->getTeamId(),\n 'type' => self::TYPE_ASK_JIMINNY,\n 'status' => (bool) $status,\n 'frequency' => $frequency,\n 'custom_name' => $name,\n 'activity_search_id' => $savedSearch->getId(),\n 'ask_anything_prompt_id' => $prompt->getId(),\n 'expires_at' => $expiresAtDate->toDateString(),\n 'media_types' => [self::MEDIA_TYPE_PDF],\n 'call_types' => [],\n 'recipients' => ['users' => $recipientUserIds],\n 'groups' => $sharedGroupIds,\n ];\n }\n\n public static function getAskJiminnyFrequencies(): array\n {\n return array_map(static function ($frequency) {\n return $frequency['id'];\n }, self::ASK_JIMINNY_FREQUENCIES);\n }\n\n public function getAskJiminnyReportFilters(User $user): array\n {\n $savedSearches = $this->activitySearchRepository->findByUserOrderedByName($user)\n ->map(fn (Search $search) => [\n 'id' => $search->getUuid(),\n 'name' => $search->getName(),\n ])\n ->values()->all();\n\n $prompts = collect(\n $this->askAnythingPromptService->get($user, AskAnythingPromptTarget::on_demand)\n )->map(fn (AskAnythingPromptDto $prompt) => [\n 'id' => $prompt->id,\n 'name' => $prompt->title,\n ])->values()->all();\n\n return [\n [\n 'id' => 'prompt',\n 'label' => 'Prompt',\n 'options' => $prompts,\n ],\n [\n 'id' => 'saved_search',\n 'label' => 'Saved Search',\n 'options' => $savedSearches,\n ],\n ];\n }\n\n public function getAskJiminnyReportFormData(User $user, ?AutomatedReport $report = null): array\n {\n $team = $user->getTeam();\n $userTimezone = $user->getTimezone();\n\n $savedSearches = $this->activitySearchRepository->findByUserOrderedByName($user)\n ->map(fn (Search $search) => [\n 'id' => $search->getUuid(),\n 'name' => $search->getName(),\n ])\n ->values()->all();\n\n $prompts = collect(\n $this->askAnythingPromptService->get($user, AskAnythingPromptTarget::on_demand)\n )->map(fn (AskAnythingPromptDto $prompt) => [\n 'id' => $prompt->id,\n 'name' => $prompt->title,\n ])->values()->all();\n\n $teamGroups = $this->groupRepository->getAllByTeam($team)->map(fn ($group) => [\n 'id' => $group->getUuid(),\n 'name' => $group->getName(),\n ])->values()->all();\n\n $shareUsers = $this->recipientsService->getRecipientsFieldData(team: $team)['options'] ?? [];\n\n $sharedTeamsValue = [];\n $sharedUsersValue = [];\n if ($report) {\n $sharedTeamsValue = $this->transformGroups($team, $report->getGroups());\n\n $recipientUserIds = $report->getRecipients()['users'] ?? [];\n $creatorId = $report->getAttribute('created_by');\n $sharedUserIds = array_values(array_filter(\n $recipientUserIds,\n static fn ($id) => $id !== $creatorId\n ));\n $sharedUsersValue = collect($sharedUserIds)\n ->map(fn ($id) => $this->userRepository->find((int) $id))\n ->filter()\n ->map(fn (User $u) => [\n 'id' => $u->getUuid(),\n 'name' => $u->getName(),\n ])\n ->values()\n ->all();\n }\n\n return [\n 'fields' => [\n [\n 'id' => 'enabled',\n 'inputType' => InputTypeEnum::TOGGLE,\n 'label' => '',\n 'value' => $report?->getStatus() ?? false,\n ],\n [\n 'id' => 'report_name',\n 'inputType' => InputTypeEnum::TEXT,\n 'label' => 'Name',\n 'placeholder' => 'Enter name',\n 'required' => true,\n 'validation' => ['maxLength' => 50],\n 'value' => $report?->getCustomName() ?? '',\n ],\n [\n 'id' => 'frequency',\n 'inputType' => InputTypeEnum::DROPDOWN,\n 'label' => 'Frequency',\n 'required' => true,\n 'placeholder' => 'Select',\n 'options' => self::ASK_JIMINNY_FREQUENCIES,\n 'value' => $report ? $this->transformFrequency($report->getFrequency()) : null,\n ],\n [\n 'id' => 'expires_on',\n 'inputType' => InputTypeEnum::DATE,\n 'label' => 'Expires on',\n 'required' => true,\n 'placeholder' => 'Select',\n 'validation' => [\n 'minDate' => now($userTimezone)->toDateString(),\n 'maxDate' => now($userTimezone)->addYear()->toDateString(),\n ],\n 'value' => $report?->getExpiresAt()?->toDateString(),\n ],\n [\n 'id' => 'share_teams',\n 'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,\n 'label' => 'Team',\n 'required' => false,\n 'placeholder' => 'Select',\n 'options' => $teamGroups,\n 'value' => $sharedTeamsValue,\n ],\n [\n 'id' => 'share_users',\n 'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,\n 'label' => 'Team member',\n 'required' => false,\n 'placeholder' => 'Select',\n 'groupLabelKey' => 'label',\n 'groupValuesKey' => 'users',\n 'optionLabelKey' => 'name',\n 'optionValueKey' => 'id',\n 'options' => $shareUsers,\n 'value' => $sharedUsersValue,\n ],\n [\n 'id' => 'saved_search',\n 'inputType' => InputTypeEnum::DROPDOWN,\n 'label' => 'Saved search',\n 'required' => true,\n 'placeholder' => 'Select',\n 'options' => $savedSearches,\n 'value' => $report && $report->getSavedSearch() ? [\n 'id' => $report->getSavedSearch()->getUuid(),\n 'name' => $report->getSavedSearch()->getName(),\n ] : null,\n ],\n [\n 'id' => 'ask_jiminny_prompt',\n 'inputType' => InputTypeEnum::DROPDOWN,\n 'label' => 'Ask Jiminny prompt',\n 'required' => true,\n 'placeholder' => 'Select',\n 'options' => $prompts,\n 'value' => $report && $report->getAskAnythingPrompt() ? [\n 'id' => $report->getAskAnythingPrompt()->getUuid(),\n 'name' => $report->getAskAnythingPrompt()->getTitle(),\n ] : null,\n ],\n ],\n ];\n }\n\n private function updateResultNames(AutomatedReport $automatedReport): void\n {\n $results = $this->automatedReportsRepository->getResultsByReport($automatedReport);\n\n foreach ($results as $result) {\n $result->update(['name' => $this->getReportFileName($result)]);\n }\n }\n\n public function updateStatus(string $uuid, array $data): array\n {\n $automatedReport = $this->automatedReportsRepository->findByUuid($uuid);\n\n if (! $automatedReport) {\n throw new ModelNotFoundException('Report not found');\n }\n\n $status = $this->validateReportStatus($data['report_enabled'] ?? null);\n $automatedReport->update([\n 'status' => $status,\n ]);\n\n $this->generateOneOffReport($automatedReport);\n\n return $this->transformReportFullView($automatedReport);\n }\n\n private function generateOneOffReport(AutomatedReport $automatedReport): void\n {\n // the scheduler handles all the other frequency types\n if ($automatedReport->getStatus() === false || $automatedReport->getFrequency() !== self::FREQUENCY_ONE_OFF) {\n return;\n }\n\n $this->dispatcher->dispatch(new RequestGenerateReportJob($automatedReport->getUuid()));\n }\n\n public function getReport(string $uuid, ?Partner $partner = null): AutomatedReport\n {\n $automatedReport = $this->automatedReportsRepository->findByUuid($uuid);\n\n if (! $automatedReport) {\n throw new ModelNotFoundException('Report not found');\n }\n\n if ($partner !== null && ! $partner->isDefaultPartner() && $automatedReport->team->partner_id !== $partner->getId()) {\n throw new ModelNotFoundException('Report not found');\n }\n\n return $automatedReport;\n }\n\n public function get(string $uuid, ?Partner $partner = null): array\n {\n $automatedReport = $this->getReport($uuid, $partner);\n\n return $this->transformReportFullView($automatedReport);\n }\n\n public function list(string $sortColumn = 'created_at', string $sortDirection = 'desc', ?Partner $partner = null): array\n {\n $results = [];\n $collection = $this->automatedReportsRepository->getAllStandardReports($sortColumn, $sortDirection, $partner);\n\n /** @var AutomatedReport $report */\n foreach ($collection as $report) {\n $results[] = $this->transformReportFullView($report);\n }\n\n return ['data' => $results];\n }\n\n public function listAskJiminnyReports(\n User $user,\n string $sortColumn = 'created_at',\n string $sortDirection = 'desc'\n ): array {\n $results = [];\n $collection = $this->automatedReportsRepository->getAskJiminnyReportsByUser($user, $sortColumn, $sortDirection);\n\n /** @var AutomatedReport $report */\n foreach ($collection as $report) {\n $results[] = $this->transformReportFullView($report);\n }\n\n return ['data' => $results];\n }\n\n public function delete(string $uuid): void\n {\n $automatedReport = $this->automatedReportsRepository->findByUuid($uuid);\n\n if (! $automatedReport) {\n throw new ModelNotFoundException('Report not found');\n }\n\n $automatedReport->delete();\n }\n\n public function createReportResult(AutomatedReport $automatedReport, array $data = []): AutomatedReportResult\n {\n return $this->automatedReportsRepository->createResult(\n array_merge(\n [\n 'report_id' => $automatedReport->getId(),\n 'status' => AutomatedReportResult::STATUS_DEFAULT,\n ],\n $data\n )\n );\n }\n\n public function getOrCreateReportResult(AutomatedReport $automatedReport, array $data = []): AutomatedReportResult\n {\n $existing = $this->automatedReportsRepository->findLatestSameDayDefaultOrFailedResult($automatedReport);\n\n if ($existing !== null) {\n $existing->update(['status' => AutomatedReportResult::STATUS_DEFAULT]);\n\n return $existing;\n }\n\n return $this->createReportResult($automatedReport, $data);\n }\n\n public function getReportResult(string $resultUuid): AutomatedReportResult\n {\n $report = $this->automatedReportsRepository->findResultByUuid($resultUuid);\n\n if (! $report) {\n throw new ModelNotFoundException('Report Result not found');\n }\n\n return $report;\n }\n\n public function findChildResult(AutomatedReportResult $result, string $type): ?AutomatedReportResult\n {\n return $this->automatedReportsRepository->findChildResult($result, $type);\n }\n\n // prophet API calls\n /**\n * @throws ApplicationException\n */\n public function getGenerateReportPayload(AutomatedReport $automatedReport, string $reportResultUuid): array\n {\n $period = $this->calculateFromAndToDate($automatedReport);\n $fromDate = $period['fromDate'];\n $toDate = $period['toDate'];\n\n return [\n 'team_id' => $automatedReport->getTeamId(),\n 'request_id' => $reportResultUuid,\n 'report_type' => $automatedReport->getType(),\n 'media_types' => $automatedReport->getMediaTypes(),\n 'from_date' => $fromDate->startOfDay()->format(DateTimeInterface::RFC3339),\n 'to_date' => $toDate->endOfDay()->format(DateTimeInterface::RFC3339),\n 'group_ids' => $automatedReport->getGroups(),\n 'call_deal_stage' => $automatedReport->getDealAtCallStages(),\n 'current_deal_stage' => $automatedReport->getCurrentDealStages(),\n 'deal_min_value' => $automatedReport->getDealValueMin(),\n 'deal_max_value' => $automatedReport->getDealValueMax(),\n 'call_types' => $automatedReport->getCallTypes(),\n 'call_duration_min_seconds' => $automatedReport->getCallDurationMin(),\n 'call_duration_max_seconds' => $automatedReport->getCallDurationMax(),\n 'special_requirements' => $automatedReport->getAdditionalPromptInput(),\n 'callback_url' => $this->getCallbackUrl(),\n 'report_period' => $this->formatReportPeriodName(\n $automatedReport->getFrequency(),\n $fromDate,\n $toDate,\n ),\n 'playbook_categories' => $automatedReport->getPlaybookCategories(),\n 'custom_name' => $automatedReport->getCustomName(),\n ];\n }\n\n // $inputPayload - FE payload structure\n public function getActivitiesCountPayload(array $inputPayload): array\n {\n // Use validateAndTransformData to validate and normalize input\n $validatedData = $this->validateAndTransformData($inputPayload);\n $period = $this->calculateFromAndToDatePeriod(\n $validatedData['frequency'],\n Carbon::parse($validatedData['from']),\n Carbon::parse($validatedData['to']),\n );\n $fromDate = $period['fromDate'];\n $toDate = $period['toDate'];\n\n // Create payload similar to getGenerateReportPayload\n return [\n 'team_id' => $validatedData['team_id'],\n 'group_ids' => $validatedData['groups'] ?? [],\n 'report_type' => $validatedData['type'],\n 'from_date' => $fromDate->format(DateTimeInterface::RFC3339),\n 'to_date' => $toDate->format(DateTimeInterface::RFC3339),\n 'call_deal_stage' => $validatedData['deal_at_call_stages'] ?? [],\n 'current_deal_stage' => $validatedData['current_deal_stages'] ?? [],\n 'deal_min_value' => $validatedData['deal_value_min'] ?? null,\n 'deal_max_value' => $validatedData['deal_value_max'] ?? null,\n 'call_types' => $validatedData['call_types'],\n 'call_duration_min_seconds' => $validatedData['call_duration_min'] ?? null,\n 'call_duration_max_seconds' => $validatedData['call_duration_max'] ?? null,\n 'special_requirements' => $validatedData['additional_prompt_input'] ?? null,\n 'playbook_categories' => $validatedData['playbook_categories'] ?? [],\n 'request_id' => null,\n 'callback_url' => null,\n ];\n }\n\n public function shouldSendReport(array $users, ?CarbonInterface $generatedAt = null): bool\n {\n if (empty($users)) {\n return false;\n }\n\n $earliestTz = collect($users)\n ->mapWithKeys(function (array $user) {\n $tz = new DateTimeZone($user['timezone']);\n $nowUtc = new DateTime('now', new DateTimeZone('UTC'));\n $offset = $tz->getOffset($nowUtc);\n\n return [$user['timezone'] => $offset];\n })\n ->sortDesc()\n ->keys()\n ->first();\n\n $now = Carbon::now($earliestTz);\n $isScheduledTime = (int) $now->format('H') === self::SENT_REPORT_AT_HOURS;\n\n if ($isScheduledTime) {\n return true;\n }\n\n return $this->hasPassedScheduledTime($generatedAt, $earliestTz);\n }\n\n public function hasPassedScheduledTime(?CarbonInterface $generatedAt, string $timezone): bool\n {\n if ($generatedAt === null) {\n return false;\n }\n\n $now = Carbon::now($timezone);\n $scheduledTime = $now->copy()->setTime(self::SENT_REPORT_AT_HOURS, 0, 0);\n\n if ($now->hour < self::SENT_REPORT_AT_HOURS) {\n $scheduledTime = $scheduledTime->subDay();\n }\n\n $scheduledTimeUtc = $scheduledTime->copy()->utc();\n $generatedAtUtc = $generatedAt->copy()->utc();\n $nowUtc = $now->copy()->utc();\n\n return $generatedAtUtc->lt($scheduledTimeUtc) && $nowUtc->gt($scheduledTimeUtc);\n }\n\n public function calculateFromAndToDatePeriod(\n string $frequency,\n ?Carbon $fromDate = null,\n ?Carbon $toDate = null,\n DateTimeZone|string|null $timezone = null,\n ): array {\n if ($frequency === self::FREQUENCY_ONE_OFF) {\n return [\n 'fromDate' => $fromDate,\n 'toDate' => $toDate,\n ];\n }\n\n $now = Carbon::now($timezone);\n\n return match ($frequency) {\n self::FREQUENCY_DAILY => [\n 'fromDate' => $now->copy()->subDay()->startOfDay(),\n 'toDate' => $now->copy()->subDay()->endOfDay(),\n ],\n self::FREQUENCY_WEEKLY => [\n 'fromDate' => $now->copy()->subWeek()->startOfWeek(CarbonInterface::MONDAY),\n 'toDate' => $now->copy()->subWeek()->endOfWeek(CarbonInterface::SUNDAY),\n ],\n self::FREQUENCY_MONTHLY => [\n 'fromDate' => $now->copy()->subMonthNoOverflow()->startOfMonth(),\n 'toDate' => $now->copy()->subMonthNoOverflow()->endOfMonth(),\n ],\n self::FREQUENCY_QUARTERLY => [\n 'fromDate' => $now->copy()->subQuarterNoOverflow()->startOfQuarter(),\n 'toDate' => $now->copy()->subQuarterNoOverflow()->endOfQuarter(),\n ],\n default => throw new InvalidArgumentException(\"Unsupported frequency: {$frequency}\"),\n };\n }\n\n private function calculateFromAndToDate(AutomatedReport $automatedReport): array\n {\n return $this->calculateFromAndToDatePeriod(\n $automatedReport->getFrequency(),\n $automatedReport->getFrom(),\n $automatedReport->getTo()\n );\n }\n\n public function getAskJiminnyGenerateReportPayload(\n AutomatedReport $automatedReport,\n AutomatedReportResult $reportResult,\n array $activityIds,\n ): array {\n return [\n 'user_question' => $automatedReport->getAskAnythingPrompt()?->getContent(),\n 'call_ids' => array_map('strval', $activityIds),\n 'team_id' => $automatedReport->getTeamId(),\n 'request_id' => $reportResult->getUuid(),\n 'callback_url' => $this->getCallbackUrl(),\n 'report_period' => $this->getReportPeriodName($reportResult),\n 'report_name' => $automatedReport->getCustomName(),\n ];\n }\n\n private function getCallbackUrl(): string\n {\n return $this->webhookService->route('jiminny.webhook.reports.ready');\n }\n\n /**\n * Validate and transform payload data for automated reports\n *\n * @param array $data\n *\n * @throws InvalidArgumentException\n *\n * @return array\n */\n private function validateAndTransformData(array $data): array\n {\n // Validate organization (team) and check feature\n $team = $this->validateOrganization($data['organization'] ?? null);\n\n $status = $this->validateReportStatus($data['report_enabled'] ?? null);\n $type = $this->validateReportType($data['report_type'] ?? null);\n $frequency = $this->validateFrequency($data['frequency'] ?? null);\n $additionalPromptInput = $this->validateAdditionalPromptInput(\n $data['additional_prompt_input'] ?? null\n );\n $customReportName = $this->validateCustomReportName($data['custom_name'] ?? null);\n\n // Prepare data for the database\n $reportData = [\n 'team_id' => $team->getId(),\n 'type' => $type,\n 'status' => $status,\n 'frequency' => $frequency,\n 'additional_prompt_input' => $additionalPromptInput,\n 'custom_name' => $customReportName,\n ];\n\n // Validate deal values\n $reportData = $this->validateDealValues($data, $reportData);\n\n // Validate date range\n $reportData = $this->validateDateRange($data, $reportData, $frequency);\n\n // Validate call durations\n $reportData = $this->validateCallDurations($data, $reportData);\n\n // Validate call types\n $reportData = $this->validateCallTypes($data, $reportData);\n\n // Validate media types\n $reportData = $this->validateMediaTypes($data, $reportData);\n\n // Validate groups\n if (isset($data['teams'])) {\n $reportData['groups'] = $this->validateAndGetGroupIds($team, $data['teams']);\n }\n\n // Validate deal stages\n $reportData = $this->validateDealStages($data, $reportData, $team, $type);\n\n // Validate playbook categories\n $reportData = $this->validatePlaybookCategories($data, $reportData, $team);\n\n // Validate recipients\n $reportData['recipients'] = [\n 'users' => $this->validateAndGetUserIdsByTeam($team, $data['recipients'] ?? []),\n ];\n\n if (isset($data['jiminny_recipients'])) {\n // Validate Jiminny recipients\n $reportData['jiminny_recipients'] = [\n 'users' => $this->validateAndGetJiminnyUserIds((array) $data['jiminny_recipients']),\n ];\n }\n\n return $reportData;\n }\n\n private function validateDealValues(array $data, array $reportData): array\n {\n if (isset($data['min_deal_value'])) {\n $reportData['deal_value_min'] = (int) $data['min_deal_value'];\n\n if ($reportData['deal_value_min'] > 4294967295 || $reportData['deal_value_min'] < 0) {\n throw new InvalidArgumentException('Min deal value should be between 0 and 4294967295');\n }\n }\n\n if (isset($data['max_deal_value'])) {\n $reportData['deal_value_max'] = (int) $data['max_deal_value'];\n\n if ($reportData['deal_value_max'] > 4294967295 || $reportData['deal_value_max'] < 0) {\n throw new InvalidArgumentException('Max deal value should be between 0 and 4294967295');\n }\n }\n\n if (isset($data['min_deal_value'], $data['max_deal_value'])\n && $data['min_deal_value'] > $data['max_deal_value']\n ) {\n throw new InvalidArgumentException('Min deal value cannot be greater than max deal value');\n }\n\n return $reportData;\n }\n\n private function validateDateRange(array $data, array $reportData, string $frequency): array\n {\n // Set date range only for one_off frequency\n if ($frequency === 'one_off') {\n if (isset($data['start_date_period'])) {\n $reportData['from'] = $this->parseDate($data['start_date_period']);\n }\n\n if (isset($data['end_date_period'])) {\n $reportData['to'] = $this->parseDate($data['end_date_period']);\n }\n\n if (empty($reportData['from']) || empty($reportData['to'])) {\n throw new InvalidArgumentException(\n 'Start date and end date are required for one_off frequency'\n );\n }\n } else {\n $reportData['from'] = null;\n $reportData['to'] = null;\n }\n\n return $reportData;\n }\n\n private function validateCallDurations(array $data, array $reportData): array\n {\n // Convert call durations from minutes to seconds\n if (isset($data['min_call_duration'])) {\n $reportData['call_duration_min'] = (int) $data['min_call_duration'] * 60;\n\n if ($reportData['call_duration_min'] > 4294967295 || $reportData['call_duration_min'] < 0) {\n throw new InvalidArgumentException('Min call duration should be between 0 and 4294967295');\n }\n }\n\n if (isset($data['max_call_duration'])) {\n $reportData['call_duration_max'] = (int) $data['max_call_duration'] * 60;\n\n if ($reportData['call_duration_max'] > 4294967295 || $reportData['call_duration_max'] < 0) {\n throw new InvalidArgumentException('Max call duration should be between 0 and 4294967295');\n }\n }\n\n return $reportData;\n }\n\n private function validateCallTypes(array $data, array $reportData): array\n {\n // Set call types\n $reportData['call_types'] = $data['call_type'] ?? [];\n if (empty($reportData['call_types'])) {\n $reportData['call_types'] = self::getCallTypes();\n }\n\n foreach ($reportData['call_types'] as $callType) {\n if (! in_array($callType, self::getCallTypes(), true)) {\n throw new InvalidArgumentException(sprintf('Call type %s is invalid', $callType));\n }\n }\n\n return $reportData;\n }\n\n private function validateMediaTypes(array $data, array $reportData): array\n {\n // Set media types from input data\n $reportData['media_types'] = $data['media_types'] ?? [];\n\n if (empty($reportData['media_types'])) {\n throw new InvalidArgumentException('Media types are required');\n }\n\n foreach ($reportData['media_types'] as $mediaType) {\n if (! in_array($mediaType, self::MEDIA_TYPES, true)) {\n throw new InvalidArgumentException(sprintf('Media type %s is invalid', $mediaType));\n }\n }\n\n return $reportData;\n }\n\n private function validateDealStages(array $data, array $reportData, Team $team, string $reportType): array\n {\n // Validate and set deal stages\n if (isset($data['deal_stage_at_call'])) {\n $reportData['deal_at_call_stages'] =\n $this->validateAndGetDealStageIds($team, $data['deal_stage_at_call'], 'Deal stage at call');\n }\n\n if (isset($data['current_deal_stage'])) {\n $reportData['current_deal_stages'] =\n $this->validateAndGetDealStageIds($team, $data['current_deal_stage'], 'Current deal stage');\n }\n\n // Ensure current_deal_stage is not provided for loss_analysis report type\n if ($reportType === self::TYPE_LOSS_ANALYSIS && ! empty($data['current_deal_stage'])) {\n throw new InvalidArgumentException('Current deal stage is not applicable for Loss Analysis reports');\n }\n\n return $reportData;\n }\n\n // transform uuid to id\n private function validatePlaybookCategories(array $data, array $reportData, Team $team): array\n {\n $key = 'playbook_categories';\n\n if (isset($data[$key])) {\n $payloadIds = $data[$key];\n $ids = [];\n\n foreach ($payloadIds as $uuid) {\n $uuid = (string) $uuid;\n\n try {\n $playbookCategory = $this->playbookCategoryRepository->findByUuid($uuid);\n } catch (Throwable $throwable) {\n Log::error(__METHOD__ . ' ' . $throwable->getMessage());\n\n throw new InvalidArgumentException(sprintf('Playbook category %s not found', $uuid));\n }\n\n if (! $playbookCategory) {\n throw new InvalidArgumentException(sprintf('Playbook category %s not found', $uuid));\n }\n\n if (! $playbookCategory->hasPlaybook()) {\n throw new InvalidArgumentException(sprintf('Playbook category %s has no playbook', $uuid));\n }\n\n if ($playbookCategory->getPlaybook()->getTeamId() !== $team->getId()) {\n throw new InvalidArgumentException(\n sprintf('Playbook category %s not found for team %s', $uuid, $team->getUuid())\n );\n }\n\n $ids[] = $playbookCategory->getId();\n }\n\n $reportData[$key] = $ids;\n }\n\n return $reportData;\n }\n\n private function validateReportStatus($status): bool\n {\n if (! in_array($status, [true, false], true)) {\n throw new InvalidArgumentException('Report status is invalid');\n }\n\n return $status;\n }\n\n private function validateReportType($type): string\n {\n if (! in_array($type, self::getTypes(), true)) {\n throw new InvalidArgumentException(sprintf('Report type is invalid: %s', $type));\n }\n\n return $type;\n }\n\n private function validateFrequency($frequency): string\n {\n if (! in_array($frequency, self::getFrequencies(), true)) {\n throw new InvalidArgumentException('Frequency is invalid');\n }\n\n return $frequency;\n }\n\n private function validateAdditionalPromptInput(?string $additionalPromptInput): ?string\n {\n if ($additionalPromptInput && strlen($additionalPromptInput) > 5000) {\n throw new InvalidArgumentException('Additional Prompt Input should be less than 5000 characters');\n }\n\n return $additionalPromptInput;\n }\n\n private function validateCustomReportName(?string $customReportName): ?string\n {\n if ($customReportName === null || $customReportName === '') {\n return null;\n }\n\n if (strlen($customReportName) > 70) {\n throw new InvalidArgumentException('Custom report name should be less than 70 characters');\n }\n\n return $customReportName;\n }\n\n private function validateOrganization(?string $organizationUuid): Team\n {\n if (! $organizationUuid) {\n throw new InvalidArgumentException('Organization is required');\n }\n\n $team = $this->teamRepository->idOrUuid($organizationUuid);\n\n if (! $team) {\n throw new InvalidArgumentException('Organization not found');\n }\n\n if (! $team->hasFeature(FeatureEnum::AUTOMATED_REPORTS)) {\n throw new InvalidArgumentException('Organization does not have the Automated Reports feature');\n }\n\n return $team;\n }\n\n private function validateAndGetGroupIds(Team $team, array $teamUuids): array\n {\n $groupIds = [];\n\n foreach ($teamUuids as $uuid) {\n $group = $this->groupRepository->findByUuid($uuid);\n\n if ($group === null || $group->getTeamId() !== $team->getId()) {\n throw new InvalidArgumentException(\n sprintf('Group %s not found for team %s', $uuid, $team->getUuid())\n );\n }\n\n $groupIds[] = $group->getId();\n\n }\n\n return $groupIds;\n }\n\n private function validateAndGetDealStageIds(Team $team, array $stageUuids, string $propertyLabel): array\n {\n $stageIds = [];\n\n foreach ($stageUuids as $uuid) {\n $stage = $this->stageRepository->findByUuid($uuid);\n\n if ($stage === null || $stage->getTeamId() !== $team->getId()) {\n throw new InvalidArgumentException(\n sprintf('Stage %s not found for team %s for %s', $uuid, $team->getUuid(), $propertyLabel)\n );\n }\n\n $stageIds[] = $stage->getId();\n }\n\n return $stageIds;\n }\n\n private function validateAndGetUserIds(array $userUuids, callable $teamCheck): array\n {\n if (empty($userUuids)) {\n return [];\n }\n\n $userIds = [];\n\n foreach ($userUuids as $uuid) {\n $user = $this->userRepository->findByUuid($uuid);\n\n if (! $user || ! $user->isStatusActive()) {\n throw new InvalidArgumentException(\n sprintf('User %s not found or is not active', $uuid)\n );\n }\n\n if (! $teamCheck($user)) {\n throw new InvalidArgumentException(\n sprintf('User %s does not belong to the allowed team(s)', $uuid)\n );\n }\n\n $userIds[] = $user->getId();\n }\n\n return $userIds;\n }\n\n private function validateAndGetUserIdsByTeam(Team $team, array $userUuids): array\n {\n return $this->validateAndGetUserIds($userUuids, fn ($user) => $user->getTeamId() === $team->getId());\n }\n\n private function validateAndGetJiminnyUserIds(array $userUuids): array\n {\n $allowedTeamIds = config('kiosk.teamIds', []);\n\n return $this->validateAndGetUserIds($userUuids, fn ($user) => in_array($user->getTeamId(), $allowedTeamIds, true));\n }\n\n private function parseDate(string $dateString): string\n {\n return date('Y-m-d H:i:s', strtotime($dateString));\n }\n\n private function generateReportResultViewUrl(AutomatedReportResult $result): string\n {\n $mediaResource = $this->getReportMediaRouteResource($result);\n\n return route('ai-reports.' . $mediaResource . '.view', ['uuid' => $result->getUuid()]);\n }\n\n private function generateReportResultDownloadUrl(AutomatedReportResult $result): string\n {\n $mediaResource = $this->getReportMediaRouteResource($result);\n\n return route('ai-reports.' . $mediaResource . '.download', ['uuid' => $result->getUuid()]);\n }\n\n private function getReportMediaRouteResource(AutomatedReportResult $result): string\n {\n if ($result->getMediaType() === self::MEDIA_TYPE_PDF) {\n return self::PDF_KEY;\n } elseif ($result->getMediaType() === self::MEDIA_TYPE_PODCAST) {\n return self::AUDIO_KEY;\n }\n\n throw new \\InvalidArgumentException('Unknown media type.');\n }\n\n public function getMediaPath(AutomatedReportResult $result): ?string\n {\n $url = match ($result->getMediaType()) {\n self::MEDIA_TYPE_PDF => $result->getPdfUrl(),\n self::MEDIA_TYPE_PODCAST => $result->getPodcastAudioUrl(),\n default => null,\n };\n\n if ($url === null) {\n return null;\n }\n\n $path = parse_url(trim($url, '\"\\''), PHP_URL_PATH);\n\n return $path ?: null;\n }\n\n public function getFilenameSuffix(AutomatedReportResult $result): ?string\n {\n return match ($result->getMediaType()) {\n self::MEDIA_TYPE_PODCAST => 'Podcast',\n default => null,\n };\n }\n\n public function getMailSubjectSuffix(AutomatedReportResult $result): string\n {\n return match ($result->getMediaType()) {\n self::MEDIA_TYPE_PDF => 'report',\n self::MEDIA_TYPE_PODCAST => 'podcast',\n default => '',\n };\n }\n\n public function getMediaTypeMetadata(AutomatedReportResult $result): array\n {\n return match ($result->getMediaType()) {\n self::MEDIA_TYPE_PODCAST => ['extension' => 'mp3', 'mime' => 'audio/mpeg'],\n self::MEDIA_TYPE_PDF => ['extension' => 'pdf', 'mime' => 'application/pdf'],\n default => ['extension' => null, 'mime' => null],\n };\n }\n\n public function deleteS3Files(AutomatedReportResult $result): void\n {\n $teamUuid = $result->getReport()->getTeam()->getUuid();\n $reportUuid = $result->getUuid();\n\n // delete all files for a report uuid no mather of pdf, podcast, or both\n // in case of both - the podcast files are linked to the pdf (parent) uuid\n // pdf and podcast date times should be close\n $path = sprintf('%s/%s/%s', $teamUuid, self::S3_DIR, $reportUuid);\n\n foreach (self::FILE_EXTENSIONS_VARIANTS as $extension) {\n $file = $path . '.' . $extension;\n\n if (Storage::exists($file)) {\n Storage::delete($file);\n Log::info('[Reports] Deleted S3 file', [\n 'path' => $file,\n ]);\n }\n }\n\n foreach (self::FILE_PODCAST_EXTENSIONS_VARIANTS as $extension) {\n $file = $path . '_podcast.' . $extension;\n\n if (Storage::exists($file)) {\n Storage::delete($file);\n Log::info('[Reports] Deleted Podcast S3 file', [\n 'path' => $file,\n ]);\n }\n }\n }\n\n /**\n *\n * @param int|null $teamId Optional team ID to filter results\n *\n * @return Collection<int, int> Collection of team IDs\n */\n public function getTeamIdsWithReportsResults(?int $teamId = null): Collection\n {\n return $this->automatedReportsRepository->getTeamIdsWithReportsResults($teamId);\n }\n\n /**\n * Core delete logic for report results using a query\n *\n * @param Builder $query\n * @param array $logContext\n *\n * @return int\n */\n private function deleteReportResultsByQuery(Builder $query, array $logContext = []): int\n {\n $deletedCount = 0;\n\n if ($query->exists()) {\n Log::info(\n 'Run delete report results',\n array_merge(\n $logContext,\n [\n 'service' => 'AutomatedReportsService',\n ]\n )\n );\n\n $query->chunkById(50, function ($results) use (&$deletedCount, $logContext) {\n foreach ($results as $result) {\n $this->deleteReportResult($result);\n $deletedCount++;\n\n Log::info(\n 'Deleted a report result',\n array_merge(\n $logContext,\n [\n 'result_id' => $result->getId(),\n 'report_id' => $result->getReportId(),\n ]\n )\n );\n }\n });\n }\n\n return $deletedCount;\n }\n\n /**\n * Delete report results for a team by retention period\n *\n * @param Team $team\n * @param CarbonImmutable $retentionDate\n *\n * @return int Number of deleted report results\n */\n public function deleteReportsResultsInRetentionPeriod(Team $team, CarbonImmutable $retentionDate): int\n {\n $reportIds = $this->automatedReportsRepository->getReportIdsByTeam($team);\n\n if ($reportIds->isEmpty()) {\n return 0;\n }\n\n $query = $this->automatedReportsRepository\n ->getReportResultsQueryForRetention($team, $retentionDate);\n\n return $this->deleteReportResultsByQuery($query, [\n 'team_id' => $team->getId(),\n 'retention_date' => $retentionDate->toDateTimeString(),\n ]);\n }\n\n /**\n * Delete ALL report results for a specific automated report\n *\n * @param string $uuid\n *\n * @return int\n */\n public function deleteReportResults(string $uuid): int\n {\n $report = $this->getReport($uuid);\n\n $query = $this->automatedReportsRepository->getResultsByReportQuery($report);\n\n return $this->deleteReportResultsByQuery($query, [\n 'report_uuid' => $uuid,\n 'report_id' => $report->getId(),\n ]);\n }\n\n public function deleteReportResult(AutomatedReportResult $result): void\n {\n $this->deleteS3Files($result);\n\n $result->delete();\n }\n\n /**\n * Get all reports for a specific team\n *\n * @param Team $team\n *\n * @return \\Illuminate\\Database\\Eloquent\\Collection\n */\n public function getTeamReports(Team $team): \\Illuminate\\Database\\Eloquent\\Collection\n {\n return $this->automatedReportsRepository->getReportsByTeam($team);\n }\n\n /**\n * Get all report results for a specific report\n *\n * @param AutomatedReport $report\n *\n * @return \\Illuminate\\Database\\Eloquent\\Collection\n */\n public function getReportResults(AutomatedReport $report): \\Illuminate\\Database\\Eloquent\\Collection\n {\n return $this->automatedReportsRepository->getResultsByReport($report);\n }\n\n public function deleteAllReportResults(AutomatedReport $report): void\n {\n $results = $this->getReportResults($report);\n\n /** @var AutomatedReportResult $result */\n foreach ($results as $result) {\n Log::info('Deleting result', [\n 'report' => $report->getId(),\n 'result' => $result->getId(),\n ]);\n\n $this->deleteReportResult($result);\n }\n }\n\n public function deleteAllData(Team $team): void\n {\n Log::info('Deleting automated report and results for team', [\n 'team' => $team->getId(),\n ]);\n\n $reports = $this->getTeamReports($team);\n\n /** @var AutomatedReport $report */\n foreach ($reports as $report) {\n Log::info('Deleting report', [\n 'team' => $team->getId(),\n 'report' => $report->getId(),\n ]);\n\n $this->deleteAllReportResults($report);\n\n $report->delete();\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.42785904,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.43650267,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.4474734,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.45611703,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.46476063,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.47573137,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"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.4867021,"top":0.09896249,"width":0.024268618,"height":0.01915403},"on_screen":true,"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.51329786,"top":0.09896249,"width":0.008643617,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"bounds":{"left":0.5242686,"top":0.09896249,"width":0.029587766,"height":0.01915403},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"bounds":{"left":0.70611703,"top":0.09896249,"width":0.02825798,"height":0.01915403},"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"21","depth":4,"bounds":{"left":0.66921544,"top":0.123703115,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.68085104,"top":0.123703115,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"18","depth":4,"bounds":{"left":0.69015956,"top":0.123703115,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"2","depth":4,"bounds":{"left":0.7017952,"top":0.123703115,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"6","depth":4,"bounds":{"left":0.7117686,"top":0.123703115,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.72140956,"top":0.12210695,"width":0.00731383,"height":0.018355945},"on_screen":true,"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.7287234,"top":0.12210695,"width":0.006981383,"height":0.018355945},"on_screen":true,"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\n\nselect sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id\nwhere u.team_id = 1;\nSELECT * FROM social_accounts WHERE sociable_id = 1635;\nSELECT * FROM users WHERE id = 1635;\n\nselect * from teams where id = 1;\nselect * from users where team_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 activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;\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\nSELECT * FROM automated_reports where id = 71;\nSELECT * FROM automated_report_results where report_id = 71;\nUPDATE automated_reports set playbook_categories = NULL 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 `automated_report_results`.* FROM `automated_report_results`\nINNER JOIN `automated_reports`\n ON `automated_report_results`.`report_id` = `automated_reports`.`id`\nWHERE 1=1\n AND `automated_report_results`.`generated_at` IS NOT NULL\n# AND `automated_report_results`.`sent_at` IS NOT NULL\n AND `automated_reports`.`team_id` = 1\n AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$.\"users\"')\n;\n\nSELECT * FROM automated_reports where id = 67;\nSELECT * FROM automated_reports where id = 42;\nSELECT * FROM users WHERE id = 143; # group 28\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;\n\nselect * from leads;\n\nSELECT * FROM activities WHERE uuid_to_bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid; # 422003\nSELECT * FROM activities WHERE id IN (16,422003);\nSELECT * FROM activities where status = 'failed';\n\nSELECT * FROM tracks WHERE activity_id = 422003;\n\nSELECT\n a.*\nFROM activities a\nJOIN users u ON a.user_id = u.id\nWHERE\n a.status = 'completed'\n AND uuid_to_bin('641f1acb-16b8-42d1-8726-df52979dad0e') = u.uuid\n AND a.deleted_at IS NULL\n AND EXISTS (\n SELECT 1 FROM tracks t\n WHERE t.activity_id = a.id\n AND t.type IN ('audio', 'video')\n )\nORDER BY a.actual_start_time DESC\nLIMIT 25;\n\nselect * from teams where id = 19;\nselect * from crm_configurations where provider = 'pipedrive';\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 = 19 and sa.provider = 'pipedrive';\n\nSELECT * FROM social_accounts WHERE id = 1116;\n\nUPDATE social_accounts SET provider_user_token = 'v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA',\nprovider_refresh_token = '5034113:19555731:87c14258f0c813d02767ee975f6044d46b6b2bfc',\nexpires = 1779091997,\nstate = 'connected'\nWHERE id = 1116;\n\n \"provider_user_token\": \"v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA\",\n \"provider_refresh_token\": \"5034113:19555731:87c14258f0c813d02767ee975f6044d46b6b2bfc\",\n \"expires\": 1779091997,","depth":4,"on_screen":true,"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\n\nselect sa.* from users u JOIN social_accounts sa on u.id = sa.sociable_id\nwhere u.team_id = 1;\nSELECT * FROM social_accounts WHERE sociable_id = 1635;\nSELECT * FROM users WHERE id = 1635;\n\nselect * from teams where id = 1;\nselect * from users where team_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 activities WHERE uuid_to_bin('e916569b-086c-4bd1-94d7-5e3802c27ccf') = uuid;\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\nSELECT * FROM automated_reports where id = 71;\nSELECT * FROM automated_report_results where report_id = 71;\nUPDATE automated_reports set playbook_categories = NULL 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 `automated_report_results`.* FROM `automated_report_results`\nINNER JOIN `automated_reports`\n ON `automated_report_results`.`report_id` = `automated_reports`.`id`\nWHERE 1=1\n AND `automated_report_results`.`generated_at` IS NOT NULL\n# AND `automated_report_results`.`sent_at` IS NOT NULL\n AND `automated_reports`.`team_id` = 1\n AND JSON_CONTAINS(`automated_reports`.`recipients`, 143, '$.\"users\"')\n;\n\nSELECT * FROM automated_reports where id = 67;\nSELECT * FROM automated_reports where id = 42;\nSELECT * FROM users WHERE id = 143; # group 28\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;\n\nselect * from leads;\n\nSELECT * FROM activities WHERE uuid_to_bin('f43cf158-e60d-46e5-92f8-c4e0594a3219') = uuid; # 422003\nSELECT * FROM activities WHERE id IN (16,422003);\nSELECT * FROM activities where status = 'failed';\n\nSELECT * FROM tracks WHERE activity_id = 422003;\n\nSELECT\n a.*\nFROM activities a\nJOIN users u ON a.user_id = u.id\nWHERE\n a.status = 'completed'\n AND uuid_to_bin('641f1acb-16b8-42d1-8726-df52979dad0e') = u.uuid\n AND a.deleted_at IS NULL\n AND EXISTS (\n SELECT 1 FROM tracks t\n WHERE t.activity_id = a.id\n AND t.type IN ('audio', 'video')\n )\nORDER BY a.actual_start_time DESC\nLIMIT 25;\n\nselect * from teams where id = 19;\nselect * from crm_configurations where provider = 'pipedrive';\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 = 19 and sa.provider = 'pipedrive';\n\nSELECT * FROM social_accounts WHERE id = 1116;\n\nUPDATE social_accounts SET provider_user_token = 'v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA',\nprovider_refresh_token = '5034113:19555731:87c14258f0c813d02767ee975f6044d46b6b2bfc',\nexpires = 1779091997,\nstate = 'connected'\nWHERE id = 1116;\n\n \"provider_user_token\": \"v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:rYyABXmXsBhEdYU_dfmDH8GF-vzSseJXE5bds_zAyVdAwlTXOPdTl9i4PS4jVofLvpq7IRgvEt2BzGhR6cWiQXHHD0AtayQOkZm262ClFCsMYtKGfep0Jq1n0eiRIVqT9gAY7rWvhpEDF8oAlgnRGmqx-euIkpzE79sPXh4OjNx_yUIaanjyplGpBBJ_NiACd1sMlZmseyUyyU_gldqlCBAuK9hhATc9icgg7zuoc7nKBBrlg49tRtzEagDh6xbFBpzfCp7kE_7n4TLWfWHLPMzu-bktjwA969G9sFRmoH1GjPA0a2odDT4dk1_1ouBrB1NcTT2hQUqH-_RzDW2nWmeoVHA\",\n \"provider_refresh_token\": \"5034113:19555731:87c14258f0c813d02767ee975f6044d46b6b2bfc\",\n \"expires\": 1779091997,","role_description":"text entry area","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextField","text":"Socket fail to connect to host:address=(host=localhost)(port=3306)(type=primary). Connection refused","depth":3,"bounds":{"left":0.42652926,"top":0.41580206,"width":0.29321808,"height":0.013567438},"on_screen":true,"value":"Socket fail to connect to host:address=(host=localhost)(port=3306)(type=primary). Connection refused","role_description":"text field","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXStaticText","text":"Project","depth":3,"on_screen":false,"role_description":"text"},{"role":"AXButton","text":"Project","depth":3,"bounds":{"left":0.011968086,"top":0.047885075,"width":0.024268618,"height":0.024740623},"on_screen":true,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"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},"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1751808696220340334
|
1126710648141684156
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
JY-20676-delete-report-re Project: faVsco.js, menu
JY-20676-delete-report-related-objects, menu
Start Listening for PHP Debug Connections
AskAnythingPromptServiceTest
Run 'AskAnythingPromptServiceTest'
Debug 'AskAnythingPromptServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
100
3
34
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Services\Kiosk\AutomatedReports;
use Carbon\CarbonImmutable;
use Carbon\CarbonInterface;
use Carbon\Exceptions\InvalidFormatException;
use DateTime;
use DateTimeInterface;
use DateTimeZone;
use Illuminate\Contracts\Bus\Dispatcher as BusDispatcher;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Carbon;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Facades\Storage;
use Jiminny\Component\ActivitySearch\FilterDefinition\InputTypeEnum;
use Jiminny\Component\AskAnything\AskAnythingPromptService;
use Jiminny\Component\AskAnything\Dtos\AskAnythingPromptDto;
use Jiminny\Component\UrlGenerator\Webhook;
use Jiminny\Contracts\Repositories\PlaybookCategoryRepository;
use Jiminny\Contracts\Repositories\TeamRepository;
use Jiminny\Contracts\Repositories\UserRepository;
use Jiminny\Exceptions\ApplicationException;
use Jiminny\Exceptions\InvalidArgumentException;
use Jiminny\Exceptions\ModelNotFoundException;
use Jiminny\Jobs\AutomatedReports\RequestGenerateReportJob;
use Jiminny\Models\Activity\Search;
use Jiminny\Models\AskAnything\AskAnythingPrompt;
use Jiminny\Models\AskAnything\AskAnythingPromptTarget;
use Jiminny\Models\AutomatedReport;
use Jiminny\Models\AutomatedReportResult;
use Jiminny\Models\Contracts\UserContract;
use Jiminny\Models\Feature\FeatureEnum;
use Jiminny\Models\Partner;
use Jiminny\Models\Team;
use Jiminny\Models\User;
use Jiminny\Repositories\AskAnythingRepository;
use Jiminny\Repositories\AutomatedReportsRepository;
use Jiminny\Repositories\GroupRepository;
use Jiminny\Repositories\SearchRepository;
use Jiminny\Repositories\StageRepository;
use Throwable;
class AutomatedReportsService
{
public const string TYPE_LOSS_ANALYSIS = 'loss_analysis';
public const string TYPE_ASK_JIMINNY = 'ask_jiminny';
/**
* Standard report types (used by kiosk for existing automated reports).
*/
// @TODO this will add filter, however if we need to control feature by FF we need conditional logic
public const array TYPES = [
['id' => 'exec_summary', 'name' => 'Exec Summary'],
['id' => 'coaching_profiles', 'name' => 'Coaching Profiles'],
['id' => 'product_feedback', 'name' => 'Product Feedback'],
['id' => self::TYPE_LOSS_ANALYSIS, 'name' => 'Loss Analysis'],
// ['id' => 'questions', 'name' => 'Questions'],
// ['id' => 'statistical_quant', 'name' => 'Statistical Quantitative'],
];
public const array ALL_TYPES = [
...self::TYPES,
['id' => self::TYPE_ASK_JIMINNY, 'name' => 'Ask Jiminny'],
];
public const string FREQUENCY_DAILY = 'daily';
public const string FREQUENCY_WEEKLY = 'weekly';
public const string FREQUENCY_MONTHLY = 'monthly';
public const string FREQUENCY_QUARTERLY = 'quarterly';
public const string FREQUENCY_ONE_OFF = 'one_off';
/**
* Frequencies for standard (non-Ask Jiminny) reports.
*/
public const array FREQUENCIES = [
['id' => self::FREQUENCY_WEEKLY, 'name' => 'Weekly'],
['id' => self::FREQUENCY_MONTHLY, 'name' => 'Monthly'],
['id' => self::FREQUENCY_QUARTERLY, 'name' => 'Quarterly'],
['id' => self::FREQUENCY_ONE_OFF, 'name' => 'One-off'],
];
/**
* Frequencies for Ask Jiminny reports.
*/
public const array ASK_JIMINNY_FREQUENCIES = [
['id' => self::FREQUENCY_DAILY, 'name' => 'Daily'],
['id' => self::FREQUENCY_WEEKLY, 'name' => 'Weekly'],
['id' => self::FREQUENCY_MONTHLY, 'name' => 'Monthly'],
];
public const string MEDIA_TYPE_PDF = 'pdf';
public const string MEDIA_TYPE_PODCAST = 'podcast';
public const array MEDIA_TYPES = [self::MEDIA_TYPE_PDF, self::MEDIA_TYPE_PODCAST];
public const array MEDIA_TYPE_OBJECT_PDF = ['id' => self::MEDIA_TYPE_PDF, 'name' => 'PDF'];
public const array MEDIA_TYPE_OBJECT_PODCAST = ['id' => self::MEDIA_TYPE_PODCAST, 'name' => 'Podcast'];
public const array MEDIA_TYPE_OBJECTS = [self::MEDIA_TYPE_OBJECT_PDF, self::MEDIA_TYPE_OBJECT_PODCAST];
public const array CALL_TYPE_CONFERENCE = ['id' => 'conference', 'name' => 'Conference'];
public const array CALL_TYPE_DIALER = ['id' => 'dialer', 'name' => 'Dialer'];
public const int SENT_REPORT_AT_HOURS = 5;
public const string PDF_KEY = 'pdf';
public const string AUDIO_KEY = 'audio';
private const array ALL_FREQUENCIES = [
['id' => self::FREQUENCY_DAILY, 'name' => 'Daily'],
['id' => self::FREQUENCY_WEEKLY, 'name' => 'Weekly'],
['id' => self::FREQUENCY_MONTHLY, 'name' => 'Monthly'],
['id' => self::FREQUENCY_QUARTERLY, 'name' => 'Quarterly'],
['id' => self::FREQUENCY_ONE_OFF, 'name' => 'One-off'],
];
private const string S3_DIR = 'reports';
private const array FILE_EXTENSIONS_VARIANTS = ['html', 'MD', 'pdf'];
private const array FILE_PODCAST_EXTENSIONS_VARIANTS = ['json', 'mp3', 'ssml'];
public function __construct(
private readonly TeamRepository $teamRepository,
private readonly GroupRepository $groupRepository,
private readonly UserRepository $userRepository,
private readonly StageRepository $stageRepository,
private readonly DealStagesService $dealStagesService,
private readonly RecipientsService $recipientsService,
private readonly AutomatedReportsRepository $automatedReportsRepository,
private readonly Webhook $webhookService,
private readonly BusDispatcher $dispatcher,
private readonly ActivityTypeService $activityTypeService,
private readonly PlaybookCategoryRepository $playbookCategoryRepository,
private readonly AskAnythingPromptService $askAnythingPromptService,
private readonly SearchRepository $activitySearchRepository,
private readonly AskAnythingRepository $askAnythingRepository,
) {
}
public static function getTypes(): array
{
$types = self::TYPES;
return array_map(static function ($type) {
return $type['id'];
}, $types);
}
public static function getCallTypes(): array
{
return array_map(static function ($callType) {
return $callType['id'];
}, [self::CALL_TYPE_CONFERENCE, self::CALL_TYPE_DIALER]);
}
public static function getFrequencies(): array
{
return array_map(static function ($frequency) {
return $frequency['id'];
}, self::FREQUENCIES);
}
// front-facing structure
public function getReportEnabledFieldData(bool $value = false): array
{
return [
'id' => 'report_enabled',
'label' => '',
'inputType' => InputTypeEnum::TOGGLE,
'value' => $value,
];
}
// Organizations = Teams
public function getOrganizationFieldData(?string $value = null, bool $shortVersion = false, ?Partner $partner = null): array
{
$options = $this->getTeams(partner: $partner);
if ($shortVersion) {
return [
'id' => 'organization',
'label' => 'Organization',
'options' => $options,
];
}
return [
'id' => 'organization',
'label' => 'Organization',
'inputType' => InputTypeEnum::DROPDOWN,
'required' => true,
'placeholder' => 'Select',
'options' => $options,
'value' => $value,
'dependencies' => [
'teams',
'deal_stage_at_call',
'current_deal_stage',
'recipients',
ActivityTypeService::PLAYBOOK_CATEGORIES_KEY,
],
'dependsOn' => [],
];
}
// Teams = Groups
public function getTeamFieldData(array $options = [], array $value = [], bool $shortVersion = false): array
{
if ($shortVersion) {
return [
'id' => 'teams',
'label' => 'Team',
'options' => $options,
];
}
return [
'id' => 'teams',
'label' => 'Team',
'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,
'required' => false,
'placeholder' => 'Select',
'options' => $options,
'value' => $value, // value should be an array of objects {id, name}
'dependencies' => [ActivityTypeService::PLAYBOOK_CATEGORIES_KEY],
'dependsOn' => [],
];
}
public function getReportTypeFieldData(?string $value = null, bool $shortVersion = false, ?Team $team = null): array
{
$types = [];
if ($team instanceof Team) {
if ($team->hasFeature(FeatureEnum::AUTOMATED_REPORTS)) {
$types = self::TYPES;
}
if ($team->hasFeature(FeatureEnum::ASK_JIMINNY_REPORTS)) {
$types[] = ['id' => self::TYPE_ASK_JIMINNY, 'name' => 'Ask Jiminny'];
}
} else {
$types = self::TYPES;
}
if ($shortVersion) {
return [
'id' => 'report_type',
'label' => 'Report Type',
'options' => $types,
];
}
return [
'id' => 'report_type',
'label' => 'Report Type',
'inputType' => InputTypeEnum::DROPDOWN,
'required' => true,
'placeholder' => 'Select',
'options' => $types,
'value' => $value,
'dependencies' => [],
'dependsOn' => [],
];
}
public function getFrequencyFieldData(?string $value = null): array
{
return [
'id' => 'frequency',
'label' => 'Frequency',
'inputType' => InputTypeEnum::DROPDOWN,
'required' => true,
'placeholder' => 'Select',
'options' => self::FREQUENCIES,
'value' => $value,
'dependencies' => ['period'],
'dependsOn' => [],
];
}
public function getPeriodFieldData(?string $valueStartDate = null, ?string $valueEndDate = null): array
{
return [
'id' => 'period',
'label' => 'Select one-off period',
'inputType' => InputTypeEnum::DATE_RANGE,
'required' => true,
'placeholder' => 'Select',
'value' => ['startDate' => $valueStartDate, 'endDate' => $valueEndDate],
'queryParams' => [
'startDate' => 'start_date_period',
'endDate' => 'end_date_period',
],
'dependencies' => [],
'dependsOn' => ['frequency'],
];
}
public function getActivityTypesFieldData(?Team $team = null, array $value = [], array $teamsFilter = []): array
{
return $this->activityTypeService->getActivityTypeFieldData(team: $team, value: $value, groupIds: $teamsFilter);
}
public function getDealStageAtCallFieldData(?Team $team = null, array $value = []): array
{
return $this->dealStagesService->getDealStageAtCallFieldData(team: $team, value: $value);
}
public function getCurrentDealStageFieldData(?Team $team = null, array $value = []): array
{
return $this->dealStagesService->getCurrentDealStageFieldData(team: $team, value: $value);
}
public function getDealValueFieldData(?int $valueMin = null, ?int $valueMax = null): array
{
return [
'id' => 'deal_value',
'label' => 'Deal Value',
'inputType' => InputTypeEnum::INTEGER_RANGE,
'required' => false,
'value' => ['min' => $valueMin, 'max' => $valueMax],
'queryParams' => [
'min' => 'min_deal_value',
'max' => 'max_deal_value',
],
'dependencies' => [],
'dependsOn' => [],
];
}
public function getCallTypeFieldData(bool $conferenceOn = false, bool $dialerOn = false): array
{
$value = [];
$conferenceOn && $value[] = self::CALL_TYPE_CONFERENCE;
$dialerOn && $value[] = self::CALL_TYPE_DIALER;
return [
'id' => 'call_type',
'label' => 'Call Type',
'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,
'required' => true,
'options' => [
self::CALL_TYPE_CONFERENCE,
self::CALL_TYPE_DIALER,
],
'value' => $value,
'dependencies' => [],
'dependsOn' => [],
];
}
public function getMediaTypeFieldData(?AutomatedReport $report = null): array
{
$value = [];
if ($report) {
$value = $this->transformMediaTypes($report);
}
return [
'id' => 'media_types',
'label' => 'Export as',
'inputType' => InputTypeEnum::DROPDOWN_MULTIPLE,
'required' => true,
'options' => self::MEDIA_TYPE_OBJECTS,
'value' => $value,
'dependencies' => [],
'dependsOn' => [],
];
}
public function getCallDurationFieldData(?int $valueMin = null, ?int $valueMax = null): array
{
return [
'id' => 'call_duration',
'label' => 'Call Duration',
'inputType' => InputTypeEnum::INTEGER_RANGE,
'required' => false,
'value' => ['min' => $valueMin, 'max' => $valueMax],
'queryParams' => [
'min' => 'min_call_duration',
'max' => 'max_call_duration',
],
'dependencies' => [],
'dependsOn' => [],
];
}
public function getRecipientsFieldData(?Team $team = null, array $value = []): array
{
return $this->recipientsService->getRecipientsFieldData(team: $team, value: $value);
}
public function getJiminnyRecipientsFieldData(array $value = []): array
{
return $this->recipientsService->getJiminnyRecipientsFieldData($value);
}
public function getAdditionalPromptInputFieldData(?string $value = null): array
{
return [
'id' => 'additional_prompt_input',
'label' => 'Special requirements',
'inputType' => InputTypeEnum::TEXTAREA,
'required' => false,
'placeholder' => 'What should be the focus of the report?',
'value' => $value,
'dependencies' => [],
'dependsOn' => [],
];
}
public function getCustomReportNameFieldData(?string $value = null): array
{
return [
'id' => 'custom_name',
'label' => 'Custom report name',
'inputType' => InputTypeEnum::TEXT,
'required' => false,
'placeholder' => 'Enter custom name',
'value' => $value,
'dependencies' => [],
'dependsOn' => [],
];
}
// data providers
public function getTeams(?Partner $partner = null): array
{
$teams = $this->teamRepository->getTeamsForKiosk(status: Team::STATUS_ACTIVE, partner: $partner);
$teamData = [];
foreach ($teams as $team) {
if (! $team->hasFeature(FeatureEnum::AUTOMATED_REPORTS)) {
continue;
}
$teamData[] = $this->transformTeam($team);
}
return $teamData;
}
public function getTeamGroups(string $teamUuid): array
{
$data = [];
$team = $this->getTeam($teamUuid);
if ($team !== null) {
$groups = $team->groups()->get();
foreach ($groups as $group) {
$data[] = [
'id' => $group->getUuid(),
'name' => $group->getName(),
];
}
}
return $data;
}
public function getTeamsGroupsOptions(array $filterTeamUuids = [], ?Partner $partner = null): array
{
$data = [];
$teams = $this->getTeams(partner: $partner);
foreach ($teams as $team) {
if (! empty($filterTeamUuids) && ! in_array($team['id'], $filterTeamUuids, true)) {
continue;
}
$data[] = [
'label' => $team['name'],
'groups' => $this->getTeamGroups($team['id']),
];
}
return $data;
}
public function getTeam(string $teamUuid): ?Team
{
return $this->teamRepository->idOrUuid($teamUuid);
}
public function getTeamById(int $teamId): ?Team
{
return $this->teamRepository->find($teamId);
}
public function getGroupsUuids(AutomatedReport $report): array
{
$uuids = [];
$reportGroups = $report->getGroups();
foreach ($reportGroups as $groupId) {
if ($group = $this->groupRepository->find($groupId)) {
$uuids[] = $group->getUuid();
}
}
return $uuids;
}
public function getPlaybookCategoriesUuids(AutomatedReport $report): array
{
$uuids = [];
$playbookCategories = $report->getPlaybookCategories();
foreach ($playbookCategories as $id) {
if ($category = $this->playbookCategoryRepository->find($id)) {
$uuids[] = $category->getUuid();
}
}
return $uuids;
}
public function getDealAtCallStagesUuids(AutomatedReport $report): array
{
$uuids = [];
$reportStages = $report->getDealAtCallStages();
foreach ($reportStages as $id) {
if ($stage = $this->stageRepository->find($id)) {
$uuids[] = $stage->getUuid();
}
}
return $uuids;
}
public function getCurrentDealStagesUuids(AutomatedReport $report): array
{
$uuids = [];
$reportStages = $report->getCurrentDealStages();
foreach ($reportStages as $id) {
if ($stage = $this->stageRepository->find($id)) {
$uuids[] = $stage->getUuid();
}
}
return $uuids;
}
public function getUsersUuids(AutomatedReport $report): array
{
return $this->extractUserUuids($report->getRecipients());
}
public function getJiminnyUsersUuids(AutomatedReport $report): array
{
return $this->extractUserUuids($report->getJiminnyRecipients());
}
/**
* @param array<string, mixed> $recipients
*/
private function extractUserUuids(array $recipients): array
{
$userIds = $recipients['users'] ?? [];
return collect($userIds)
->map(fn ($id) => $this->userRepository->find((int) $id))
->filter()
->map(fn (UserContract $user) => $user->getUuid())
->values()
->all();
}
// get mail data
public function getRecipientUsers(AutomatedReport $report): array
{
return $this->buildRecipientUsers($report->getRecipients());
}
/**
* @return array<UserContract>
*/
public function getRecipientUserObjects(AutomatedReport $report): array
{
$userIds = $report->getRecipients()['users'] ?? [];
return collect($userIds)
->map(fn ($id) => $this->userRepository->find((int) $id))
->filter()
->values()
->all();
}
private function getJiminnyRecipientUsers(AutomatedReport $report): array
{
return $this->buildRecipientUsers($report->getJiminnyRecipients());
}
/**
* @param array<string, mixed> $recipients
*/
private function buildRecipientUsers(array $recipients): array
{
$userIds = $recipients['users'] ?? [];
return collect($userIds)
->map(fn ($id) => $this->userRepository->find((int) $id))
->filter()
->map(fn (UserContract $user) => [
'email' => $user->getEmailAddress(),
'name' => $user->getName(),
'timezone' => $user->getTimezone()->getName(),
])
->values()
->all();
}
public function getValidRecipientUsers(AutomatedReport $report, bool $includeJiminny = false): array
{
if ($report->isAskJiminnyReport()) {
$recipients = $this->resolveAskJiminnyRecipients($report);
} else {
$recipients = $this->getRecipientUsers($report);
if ($includeJiminny) {
$recipients = array_merge($recipients, $this->getJiminnyRecipientUsers($report));
}
}
$emails = [];
return array_values(array_filter(
$recipients,
static function ($recipient) use (&$emails) {
if (empty($recipient['email']) || in_array($recipient['email'], $emails, true)) {
return false;
}
$emails[] = $recipient['email'];
return true;
}
));
}
private function resolveAskJiminnyRecipients(AutomatedReport $report): array
{
$recipients = [];
$creator = $report->getCreator();
if ($creator !== null) {
$recipients[] = [
'email' => $creator->getEmailAddress(),
'name' => $creator->getName(),
'timezone' => $creator->getTimezone()->getName(),
];
}
return array_merge(
$recipients,
$this->buildRecipientUsers($report->getRecipients()),
$this->getGroupRecipientUsers($report),
);
}
private function getGroupRecipientUsers(AutomatedReport $report): array
{
$users = [];
foreach ($report->getGroups() as $groupId) {
$group = $this->groupRepository->find($groupId);
if ($group === null) {
continue;
}
foreach ($group->getMembers() as $member) {
$users[] = [
'email' => $member->getEmailAddress(),
'name' => $member->getName(),
'timezone' => $member->getTimezone()->getName(),
];
}
}
return $users;
}
public function getReportTypeName(AutomatedReportResult $report): string
{
$type = $report->getReport()->getType();
$getType = $this->transformReportType($type);
return $getType['name'];
}
public function getReportPeriodName(AutomatedReportResult $report): string
{
$from = $report->getFromDate();
$to = $report->getToDate();
$frequency = $report->getReport()->getFrequency();
if ($from === null || $to === null) {
if (! $report->getReport()->isAskJiminnyReport()) {
$invalidPeriod = $from === null ? 'from' : 'to';
throw new ApplicationException('Report period is invalid: ' . $invalidPeriod);
}
$timezone = $report->getReport()->getCreator()?->getTimezone();
$period = $this->calculateFromAndToDatePeriod($frequency, timezone: $timezone);
$from = $period['fromDate'];
$to = $period['toDate'];
}
return $this->formatReportPeriodName($frequency, $from, $to);
}
private function formatReportPeriodName(string $frequency, Carbon $from, Carbon $to): string
{
$fromYear = $from->format('Y');
$toYear = $to->format('Y');
$differentYears = $fromYear !== $toYear;
switch ($frequency) {
case self::FREQUENCY_DAILY:
return $from->format('j M Y');
case self::FREQUENCY_QUARTERLY:
// 'Jan-Mar 2025' or 'Nov 2024-Jan 2025' if years differ
$startMonth = $from->format('M');
$endMonth = $to->copy()->subMonth();
$endMonthName = $endMonth->format('M');
$endMonthYear = $endMonth->format('Y');
if ($differentYears) {
return "{$startMonth} {$fromYear} - {$endMonthName} {$endMonthYear}";
}
return "{$startMonth} - {$endMonthName} {$toYear}";
case self::FREQUENCY_MONTHLY:
// 'May 2025' - monthly reports are always within the same year
return $from->format('M Y');
case self::FREQUENCY_WEEKLY:
// '4 - 8 Aug 2025', '27 Oct - 3 Nov 2025', or '28 Dec 2024 - 3 Jan 2025' if years differ
$startDay = $from->format('j');
$endDay = $to->format('j');
$startMonth = $from->format('M');
$endMonth = $to->format('M');
if ($differentYears) {
return "{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}";
}
if ($startMonth !== $endMonth) {
return "{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}";
}
return "{$startDay} - {$endDay} {$endMonth} {$toYear}";
case self::FREQUENCY_ONE_OFF:
// '2 May-31 May 2025' or '15 Dec 2024-15 Jan 2025' if years differ
$startDay = $from->format('j');
$startMonth = $from->format('M');
$endDay = $to->format('j');
$endMonth = $to->format('M');
// If same month and year, use a format like '2-31 May 2025'
if ($startMonth === $endMonth && ! $differentYears) {
return "{$startDay} - {$endDay} {$startMonth} {$toYear}";
}
// If different years, include both years
if ($differentYears) {
return "{$startDay} {$startMonth} {$fromYear} - {$endDay} {$endMonth} {$toYear}";
}
// Same year but different months
return "{$startDay} {$startMonth} - {$endDay} {$endMonth} {$toYear}";
default:
// Default format for unknown frequencies
return $from->format('j M Y') . ' - ' . $to->format('j M Y');
}
}
public function getReportTeamsName(AutomatedReportResult $report): string
{
$groups = $report->getGroups();
if (empty($groups)) {
return 'All';
}
// Get group names from repository
$groupNames = [];
foreach ($groups as $groupId) {
$group = $this->groupRepository->find($groupId);
if ($group) {
$groupNames[] = $group->getName();
}
}
if (count($groupNames) === 1) {
// Single team format
$teamsName = $groupNames[0];
} else {
// Multiple teams format
$teamsName = implode(', ', $groupNames);
}
return $teamsName;
}
public function getReportFileName(AutomatedReportResult $report): string
{
$customName = $report->getReport()->getCustomName();
$periodName = $this->getReportPeriodName($report);
$filenameSuffix = $this->getFilenameSuffix($report);
if ($customName) {
if ($filenameSuffix) {
$customName .= " {$filenameSuffix}";
}
return $this->sanitizeFileName("{$customName} - {$periodName}");
}
$baseName = $this->getReportTypeName($report);
if ($filenameSuffix) {
$baseName .= " {$filenameSuffix}";
}
return $this->sanitizeFileName("{$baseName} - {$periodName} - {$this->getReportTeamsName($report)}");
}
public function getReportFileNameWithExtension(AutomatedReportResult $result): string
{
$extension = $this->getMediaTypeMetadata($result)['extension'];
return $this->getReportFileName($result) . '.' . $extension;
}
public function sanitizeFileName(string $fileName): string
{
return str_replace(['/', '\\'], '-', $fileName);
}
public function isUserRecipientOfReport(User $user, AutomatedReport $report): bool
{
$recipientIds = array_map('intval', $report->getRecipients()['users'] ?? []);
if (in_array($user->getId(), $recipientIds, true)) {
return true;
}
if ($report->isAskJiminnyReport()) {
$groupId = $user->getGroupId();
if ($groupId !== null && in_array($groupId, $report->getGroups(), true)) {
return true;
}
}
return false;
}
public function transformReportResults(Collection $automatedReportResults): array
{
$data = [];
foreach ($automatedReportResults as $automatedReportResult) {
/** @var AutomatedReportResult $automatedReportResult */
$report = $automatedReportResult->getReport();
$createdBy = $report->getCreator();
$creator = [
'id' => $createdBy?->getUuid(),
'name' => $createdBy?->getName(),
'email' => $createdBy?->getEmailAddress(),
'photoUrl' => $createdBy?->getPhotoUrl(),
];
$data[] = [
'id' => $automatedReportResult->getUuid(),
'name' => $automatedReportResult->getName(),
'frequency' => $this->transformFrequency($report->getFrequency()),
'recipients' => $this->buildRecipients($report),
'report_type' => $this->transformReportType($report->getType()),
'media_type' => $automatedReportResult->getMediaType(),
'downloadUrl' => $this->generateReportResultDownloadUrl($automatedReportResult),
'viewUrl' => $this->generateReportResultViewUrl($automatedReportResult),
'generated_at' => $automatedReportResult->getGeneratedAt()?->toIso8601String(),
'creator' => $creator,
];
}
return $data;
}
private function buildRecipients(AutomatedReport $report): array
{
$creatorUuid = $report->getCreator()?->getUuid();
$recipients = array_values(array_filter(
$this->transformRecipients($report->getRecipients()),
static fn (array $recipient): bool => $recipient['id'] !== $creatorUuid,
));
if (! $report->isAskJiminnyReport()) {
return $recipients;
}
return [
...array_values($this->transformGroups(team: $report->getTeam(), groupsIds: $report->getGroups())),
...$recipients,
];
}
public function hasCallTypeConference(AutomatedReport $report): bool
{
return in_array(self::CALL_TYPE_CONFERENCE['id'], $report->getCallTypes(), true);
}
public function hasCallTypeDialer(AutomatedReport $report): bool
{
return in_array(self::CALL_TYPE_DIALER['id'], $report->getCallTypes(), true);
}
// transformers
private function transformTeam(Team $team): array
{
if (! $team->hasFeature(FeatureEnum::AUTOMATED_REPORTS)) {
return [];
}
return [
'id' => $team->getUuid(),
'name' => $team->getName(),
];
}
private function transformReportFullView(AutomatedReport $report): array
{
$base = $this->transformReportBase($report);
return $report->getType() === self::TYPE_ASK_JIMINNY
? $base + $this->transformAskJiminnyFields($report)
: $base + $this->transformStandardReportFields($report);
}
private function transformReportBase(AutomatedReport $report): array
{
return [
'id' => $report->getUuid(),
'organization' => $this->transformOrganization(team: $report->getTeam()),
'report_type' => $this->transformReportType($report->getType()),
'frequency' => $this->transformFrequency($report->getFrequency()),
];
}
private function transformStandardReportFields(AutomatedReport $report): array
{
$team = $report->getTeam();
return [
'report_enabled' => $report->getStatus(),
'start_date_period' => $report->getFrom()?->format('Y-m-d H:i:s'),
'end_date_period' => $report->getTo()?->format('Y-m-d H:i:s'),
'deal_value_min' => $report->getDealValueMin(),
'deal_value_max' => $report->getDealValueMax(),
'call_types' => $this->transformCallType($report->getCallTypes()),
'media_types' => $this->transformMediaTypes($report),
'call_duration_min' => $this->transformDurationToMinutes($report->getCallDurationMin()),
'call_duration_max' => $this->transformDurationToMinutes($report->getCallDurationMax()),
'teams' => $this->transformGroups(team: $team, groupsIds: $report->getGroups()),
'deal_at_call_stages' => $this->transformStages(team: $team, stagesIds: $report->getDealAtCallStages()),
'current_deal_stages' => $this->transformStages(team: $team, stagesIds: $report->getCurrentDealStages()),
'recipients' => $this->transformRecipients($report->getRecipients()),
'created_by' => $this->transformCreator($report->getCreator()),
'additional_prompt_input' => $report->getAdditionalPromptInput(),
'custom_name' => $report->getCustomName(),
'created_at' => $report->getCreatedAt()->format('Y-m-d H:i:s'),
'updated_at' => $report->getUpdatedAt()->format('Y-m-d H:i:s'),
'deleted_at' => $report->getDeletedAt()?->format('Y-m-d H:i:s'),
];
}
private function transformAskJiminnyFields(AutomatedReport $report): array
{
$team = $report->getTeam();
$creatorId = $report->getAttribute('created_by');
$explicitUserIds = array_values(array_filter(
$report->getRecipients()['users'] ?? [],
static fn ($id) => $id !== $creatorId
));
return [
'report_name' => $report->getCustomName(),
'enabled' => $report->getStatus(),
'share_teams' => $this->transformGroups(team: $team, groupsIds: $report->getGroups()),
'share_users' => $this->transformRecipients(['users' => $explicitUserIds]),
'saved_search' => $this->transformSafeSearch($report->getSavedSearch()),
'ask_jiminny_prompt' => $this->transformAskJiminnyPrompt($report->getAskAnythingPrompt()),
'expires_on' => $report->getExpiresAt()?->format('Y-m-d'),
];
}
private function transformOrganization(?Team $team): array
{
return [
'id' => $team?->getUuid(),
'name' => $team?->getName(),
];
}
private function transformReportType(string $type): array
{
foreach (self::ALL_TYPES as $typeItem) {
if ($typeItem['id'] === $type) {
return $typeItem;
}
}
return [];
}
private function transformCallType(array $types): array
{
$result = [];
$callTypes = [self::CALL_TYPE_CONFERENCE, self::CALL_TYPE_DIALER];
foreach ($types as $type) {
foreach ($callTypes as $callTypeItem) {
if ($callTypeItem['id'] === $type) {
$result[] = $callTypeItem;
break;
}
}
}
return $result;
}
private function transformMediaTypes(AutomatedReport $report): array
{
$values = [];
foreach ($report->getMediaTypes() as $mediaType) {
if (! in_array($mediaType, self::MEDIA_TYPES, true)) {
continue;
}
$values[] = match ($mediaType) {
self::MEDIA_TYPE_PDF => self::MEDIA_TYPE_OBJECT_PDF,
self::MEDIA_TYPE_PODCAST => self::MEDIA_TYPE_OBJECT_PODCAST,
};
}
return $values;
}
private function transformFrequency(string $frequency): array
{
foreach (self::ALL_FREQUENCIES as $frequencyItem) {
if ($frequencyItem['id'] === $frequency) {
return $frequencyItem;
}
}
return [];
}
public function transformDurationToMinutes(?int $duration): ?int
{
if (! $duration) {
return null;
}
return (int) ($duration / 60);
}
private function transformGroups(?Team $team, array $groupsIds): array
{
if (empty($groupsIds) || ! $team) {
return [];
}
$data = [];
foreach ($groupsIds as $groupId) {
$group = $team->groups()->where('id', $groupId)->first();
if ($group) {
$data[] = [
'id' => $group->getUuid(),
'name' => $group->getName(),
'photoUrl' => $group->getPhotoUrl(),
];
}
}
return $data;
}
private function transformStages(?Team $team, array $stagesIds): array
{
if (empty($stagesIds) || ! $team) {
return [];
}
$data = [];
foreach ($stagesIds as $stageId) {
$stage = $team->stages()->where('id', $stageId)->first();
if ($stage) {
$data[] = [
'id' => $stage->getUuid(),
'name' => $stage->getName(),
];
}
}
return $data;
}
private function transformRecipients(array $recipients): array
{
$users = [];
foreach ($recipients['users'] ?? [] as $userId) {
$users[] = $this->transformUser($userId);
}
return $users;
}
private function transformCreator(?User $user): ?array
{
if ($user === null) {
return null;
}
return $this->transformUser($user->getId());
}
private function transformAskJiminnyPrompt(?AskAnythingPrompt $prompt): ?array
{
if ($prompt === null) {
return null;
}
return [
'id' => $prompt->getUuid(),
'name' => $prompt->getTitle(),
];
}
private function transformSafeSearch(?Search $search): ?array
{
if ($search === null) {
return null;
}
return [
'id' => $search->getUuid(),
'name' => $search->getName(),
];
}
private function transformUser(int $userId): array
{
/* @var ?User $user */
$user = $this->userRepository->find($userId);
return [
'id' => $user?->getUuid(),
'name' => $user?->getName(),
'email' => $user?->getEmailAddress(),
'photoUrl' => $user?->getPhotoUrl(),
];
}
public function create(array $data): array
{
$validatedData = $this->validateAndTransformData($data);
$validatedData['created_by'] = auth()->id();
$automatedReport = $this->automatedReportsRepository->create($validatedData);
$this->generateOneOffReport($automatedReport);
return $this->transformReportFullView($automatedReport);
}
public function update(string $uuid, array $data): array
{
$validatedData = $this->validateAndTransformData($data);
$report = $this->automatedReportsRepository->findByUuid($uuid);
if (! $report) {
throw new InvalidArgumentException('Report not found');
}
$oldCustomName = $report->getCustomName();
$automatedReport = $this->automatedReportsRepository->update($report, $validatedData);
if ($oldCustomName !== $automatedReport->getCustomName()) {
$this->updateResultNames($automatedReport);
}
$this->generateOneOffReport($automatedReport);
return $this->transformReportFullView($automatedReport);
}
/**
* Create an Ask Jiminny report.
*/
public function createAskJiminnyReport(array $data, User $creator): array
{
$validatedData = $this->validateAskJiminnyReportData($data, $creator);
$validatedData['created_by'] = $creator->getId();
$automatedReport = $this->automatedReportsRepository->create($validatedData);
return $this->transformReportFullView($automatedReport);
}
/**
* Update an Ask Jiminny report.
*/
public function updateAskJiminnyReport(AutomatedReport $report, array $data, User $user): array
{
if (! $report->isAskJiminnyReport()) {
throw new InvalidArgumentException('Report is not an Ask Jiminny report');
}
$validatedData = $this->validateAskJiminnyReportData($data, $user);
$oldCustomName = $report->getCustomName();
$automatedReport = $this->automatedReportsRepository->update($report, $validatedData);
if ($oldCustomName !== $automatedReport->getCustomName()) {
$this->updateResultNames($automatedReport);
}
return $this->transformReportFullView($automatedReport);
}
public function updateAskJiminnyReportStatus(AutomatedReport $report, bool $status): array
{
if ($status && $report->isAskJiminnyReport() && ! $report->canExecute()) {
throw new InvalidArgumentException(
'This report is missing a saved search or prompt. ' .
'Edit the report to complete the setup before enabling it.'
);
}
$this->automatedReportsRepository->update($report, ['status' => $status]);
return $this->transformReportFullView($report->fresh());
}
/**
* Validate and transform data for Ask Jiminny reports.
*/
private function validateAskJiminnyReportData(array $data, User $user): array
{
// Validate name
$name = trim($data['report_name'] ?? '');
if (empty($name)) {
throw new InvalidArgumentException('Report name is required');
}
if (mb_strlen($name) > 50) {
throw new InvalidArgumentException('Report name must be 50 characters or less');
}
// Validate frequency (only daily, weekly, monthly for Ask Jiminny)
$frequency = $data['frequency'] ?? null;
$askJiminnyFrequencies = [self::FREQUENCY_DAILY, self::FREQUENCY_WEEKLY, self::FREQUENCY_MONTHLY];
if (! in_array($frequency, $askJiminnyFrequencies, true)) {
throw new InvalidArgumentException('Frequency must be daily, weekly, or monthly');
}
// Validate expiration date
$expiresAt = $data['expires_on'] ?? null;
if (empty($expiresAt)) {
throw new InvalidArgumentException('Expiration date is required');
}
try {
$expiresAtDate = Carbon::parse($expiresAt);
} catch (InvalidFormatException $e) {
throw new InvalidArgumentException('Expiration date format is invalid');
}
$maxExpiration = Carbon::now()->addYear()->endOfDay();
if ($expiresAtDate->gt($maxExpiration)) {
throw new InvalidArgumentException('Expiration date cannot be more than 1 year from now');
}
if ($expiresAtDate->isPast()) {
throw new InvalidArgumentException('Expiration date cannot be in the past');
}
// Validate saved search
$activitySearchId = $data['saved_search'] ?? null;
if (empty($activitySearchId)) {
throw new InvalidArgumentException('Saved search is required');
}
$savedSearch = $this->activitySearchRepository->findByUuidAndUser($activitySearchId, $user);
if (! $savedSearch) {
throw new InvalidArgumentException('Saved search not found or does not belong to you');
}
// Validate saved prompt
$askAnythingPromptId = $data['ask_jiminny_prompt'] ?? null;
if (empty($askAnythingPromptId)) {
throw new InvalidArgumentException('Ask Jiminny prompt is required');
}
$prompt = $this->askAnythingRepository->getPromptByUuid($askAnythingPromptId);
if (! $prompt) {
throw new InvalidArgumentException('Ask Jiminny prompt not found');
}
// Validate status
$status = $data['enabled'] ?? false;
$recipientUserIds = [$user->getId()];
if (! empty($data['share_users'])) {
$sharedUserIds = $this->validateAndGetUserIdsByTeam(
$user->team,
(array) $data['share_users']
);
$recipientUserIds = array_merge($recipientUserIds, $sharedUserIds);
}
$sharedGroupIds = [];
if (! empty($data['share_teams'])) {
$sharedGroupIds = $this->validateAndGetGroupIds($user->team, (array) $data['share_teams']);
}
$recipientUserIds = array_values(array_unique($recipientUserIds));
return [
'team_id' => $user->getTeamId(),
'type' => self::TYPE_ASK_JIMINNY,
'status' => (bool) $status,
'frequency' => $frequency,
'custom_name' => $name,
'activity_search_id' => $savedSearch->getId(),
'ask_anything_prompt_id' => $prompt->getId(),
'expires_at' => $expiresAtDate->toDateString(),
'media_types' => [self::MEDIA_TYPE_PDF],
'call_types' => [],
'recipients' => ['users' => $recipientUserIds],
'groups' => $sharedGroupIds,
];
}
public static function getAskJiminnyFrequencies(): array
{
return array_map(static function ($frequency) {
return $frequency['id'];
}, self::ASK_JIMINNY_FREQUENCIES);
}
public function getAskJiminnyReportFilters(User $user): array
{
$savedSearches = $this->activitySearchRepository->findByUserOrderedByName($user)
->map(fn (Search $search) => [
'id' => $search->getUuid(),
'name' => $search->getName(),
])
->values()->all();
$prompts = collect(
$this->askAnythingPromptService->get($user, AskAnythingPromptTarget::on_demand)
)->map(fn (AskAnythingPromptDto $prompt) => [
'id' => $prompt->id,
'name' => $prompt->title,
])->values()->all();
return [
[
'id' => 'prompt',
'label' => 'Prompt',
'options' => $prompts,
],
[
'id' => 'saved_search',
'label' => 'Saved Search',
'options' => $savedSearches,
],
];
}
public function getAskJiminnyReportFormData(User $user, ?AutomatedReport $report = null): array
{
$team = $user->getTeam();
$userTimezone = $user->getTimezone();
$savedSearches = $this->activitySearchRepository->findByUserOrderedByName($user)
->map(fn (Search $search) => [
'id' => $search->getUuid(),
'name' => $search->getName(),
])
->values()->all();
$prompts = collect(
$this->askAnythingPromptService->get($user, AskAnythingPromptTarget::on_demand)
)->map(fn (AskAnythingPromptDto $prompt) => [
'id' => $prompt->id,
'name' => $prompt->title,
])->values()->all();
$teamGroups = $this->groupRepository->getAllByTeam($team)->map(fn ($group) => [
'id' => $group->getUuid(),
'name' => $group->getName(),
])->values()->all();
$shareUsers = $this->recipientsService->getRecipientsFieldData(team: $team)['options'] ?? [];
$sharedTeamsValue = [];
$sharedUsersValue = [];
if ($report) {
$sharedTeamsValue = $this->transformGroups($team, $report->getGroups());
$recipientUserIds = $report->getRecipients()['users'] ?? [];
$creatorId = $report->getAttribute('created_by');
$sharedUserIds = array_values(array_filter(
$recipientUserIds,
static fn ($id) => $id !== $creatorId
));
$sharedUsersValue = collect($sharedUserIds)
->map(fn ($id) => $this->userRepository->find((int) $id))
->filter()
->map(fn (User $u) => [
'id' => $u->getUuid(),
'name' => $u->getName(),
])
->values()
->all();
}
return [
'fields' => [
[
'id' => 'enabled',
'inputType' => InputTypeEnum::TOGGLE,
'label' => '',
'value' => $report?->getStatus() ?? false,
],
[
'id' => 'report_name',
'inputType' => InputTypeEnum::TEXT,
'label' => 'Name',
'placeholder' => 'Enter name',
'required' => true,
'validation' => ['maxLength' => 50],
'value' => $report?->getCustomName() ?? '',
...
|
57864
|
NULL
|
NULL
|
NULL
|