|
53350
|
1871
|
46
|
2026-05-18T12:03:20.856022+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779105800856_m2.jpg...
|
PhpStorm
|
faVsco.js – CoreUserRequest.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormVIewINavigarecodeLaravelKeractorWindowmelp PhostormVIewINavigarecodeLaravelKeractorWindowmelpFV faVsco.js?9 master kProledeyC ActivityController.ong© HelperTruncateCoachingTables.phpocoreuserkequest.onpo seimrrovisionine.onp© CoreUser.php© HubspotJournalPollingCommand.php© HubspotWebhookServiceCommand.phpoImpontkecoraing.onp© ImportUsersFromCsvFile.phpk?phpoIssuemeslokencommane.one© IterateUsersCommand.phpnamespace Jiminny DTO SCIM AAD Request*) Jiminnycacheclearcommana.pngC) JiminnyDeougCommand.pnpuse...C) Jiminnysetencrypted lokenmanagermo.© JiminnyTokenInfoCommand.phpc) MakeslackLiveCoachingChatvoteson.on* POST /Usersc)Manacescimrorleam.ono* JSON examolec)Markoranchror-nvironmentPioelinecomiC) MuteOraanizerChannel.ohpC) PhoAom.ohu"schemas"l.© PropagateCoachingFeedbackCreatedAt1"urn:ietf:params:scim:schemas:core:2.0:User",C) PuraeConterences.oho"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"],C) PurdeSorDeleted@ooortunitiescomman"externalId": "0a21f0f2-8d2a-4f8e-bf98-7363c4aed4ef",©)PurdesvncBatchescommand.ono"userName": "Test_User_ab6490ee-1e48-479e-a20b-2d77186b5dd1" .© RecalculateDealRisksCommand.php(C) RemoveDeleteMarkersCommand.oho"active": true,© RemoveExpiredNudgesCommand.php"emails": [{"primary": true,(C) RemoveUnusedParticioantSoeechesCon"tupe". "Work",(C) Reset=lasticSearch.ohn"value": "[EMAIL]"(c) RoctoreActivitvCrmProviderldCommandr© RestoreActivityTypeCommand.php© RunAiCallScoringForUntypedActivitiesCo"resourceType": "User"(C) SoedActivities nhn(C) SendNudaeSynirationWarninasCommand"name":© SyncActivity.php© Tracklmported.php"fomiluName": "familuName".C) WhichWorkerlsWorkingOnWhichJob.pnp> @ Scheduling© Kernel.php"roles". fimcontracts0 DomainDDTOclass CorelserRequest extends Request0 Activity_ customerApExterna Serviceintedrations• Primaru attrihuteslmoortcalll>M InvitationZ usagesRolesprivate SuserName:n SCIMVDAADprivate Sactivev M Requestz usages(c) CoreGrounRequest nhnlprivate $emailPrimaryWork:•) CoreliserRequect nhn.Z usages(C) GetGrounRvQuerv nhn i© GetUserByQuery.phpmivate SemailOthecs edits +Accept File &+X Reject File 4%€ + 1 of 8 files →" hac heon rectored Il Pollback II Confiaure (12 minutes aaol-laravel.log4 SF jiminny@localhost]A console (STAGING) *•.0 .where crm_configuration_id = 1 and pl.playbook_id = 175:« console [PROD]# console [euyGo jiminny_jupiter5545583 888832834438,- 568569570V571579— 574-57"579)570)seel—5818. 3,3-585cori•coo-589— 590|-591593)595019 A19 V17 ^ VSELECT r.* FROM automated_ reports rjoin teams t on r.team id = t.idhckE r.trequency = "dally'AND t.status = 'active'AND (r.expices.at >= now() OR r.expices._at IS NULL);automated_ report results where report id IN (18, 33)select * from users where team_id = 1 and id = 1047;SELECT * FROMsocial_accounts WHERE sociable_ id = 1047:select * from activity_searches where id = 10932;select * from activity_search_filters where activity_search_id = 10932;select * fromenorts order by id desctomated renort results order by id desclautomated nenonts wherp 1d TN (550pcilts whenp id TN ((81)1usens whene id TN (1A633 13087. 11985)•WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;SELECT + FROM atonated repore t wit e uta (2 -a6 (75-286425076 -3-42-39-0405-+67679 -653) = ud:select * from accounts where team_10 = 1select * from crm contiqurations where provider = 'pipedrive'sSELECTCONCAT(u.id, CASE WHEN U.id = t.owner_id THEN• (owner) ' ELSE 1• END) AS user idlsa.*t.owner_id FROM social_accounts saJJOuN users u on u.id= sa.sociable idiIOTN teans +1.nk->1: on + id = u.team idWHEPE uteam id = 1029 and sa-nnoviden = 'ninednive'.Husen idil. "03460 (owner)"supoont Dally • now100% S2• Mon 18 May 15:03:20AskJiminnyReportActivityServiceTest vCascadeImplement Trial OwneFixing Redis Rate LimSalestorce Token FalliSClM Role Manageme+0 ..inp on LineWARN Metadata found iin doc-comment for method9/ 10 tacke doneWrite unit tests for SCIM role management10) Contact Mario to vodate customer10 / 10 tasks doneselm role managementtor leamtallor has been successtully implemented. Here's what was completed:Implementation Summary:1. CoreUserRequest DTO - Added role parsina from SCIM requests2. SCIM Constants - Added META ROLES and USER_PATCH_ATTR_ ROLES constants3. RoleAttr Mutator - Created mutator for handlina role assianments via SCIM PATCH operations4. ScimProvisioning - Updated to handle roles during user creation with proper validation5. ListenerRoleCannotHaveAdminOrManagerPermissionRule - Created validation rule to prevent listener role fromhaving admin/manager permissions6. CoreUser Response - Updated to include roles in SClM responses7. Unit Tests - Created comprehensive tests for the validation ruleKey Features:• Customers can now assign roles via SCIM (recorder, recorder & voice, analyst, listener, admin, manager)• Validation ensures listener role is onlv assianable if the LISTENER ROLE feature flaa is enabledl•LIstener role cannot de comolned with aamin or manager permissions• Uses existing UpdateUserRolesAction for role syncing and logging• Follows platform validation rules (DependentRolesRule, ListenerRoleRequiresListenerFeatureRule)Next Step: Please contact Mario to update the customer that SCIM role management is now available for Teamtailorintearationposwtn chaten vapp/Component/SClM/ Constants.php +3app/Component/SCIM/ ® ScimProvisioning.php +85-15nse/ CoreUser.php +21ann/Comnonent/SCIM/Mutatore/Attributes/Ucer/M PoleAttr.nho 417ites/User/ ẞ RoleAttrTest.nhn +224Ask anvthing 884-D)« Code SWF-1.6* Reiect alliiAccent allW Windsurf Teams 1:1 UTF-8io 4 spaces...
|
NULL
|
-4310109292152580504
|
NULL
|
visual_change
|
ocr
|
NULL
|
PhostormVIewINavigarecodeLaravelKeractorWindowmelp PhostormVIewINavigarecodeLaravelKeractorWindowmelpFV faVsco.js?9 master kProledeyC ActivityController.ong© HelperTruncateCoachingTables.phpocoreuserkequest.onpo seimrrovisionine.onp© CoreUser.php© HubspotJournalPollingCommand.php© HubspotWebhookServiceCommand.phpoImpontkecoraing.onp© ImportUsersFromCsvFile.phpk?phpoIssuemeslokencommane.one© IterateUsersCommand.phpnamespace Jiminny DTO SCIM AAD Request*) Jiminnycacheclearcommana.pngC) JiminnyDeougCommand.pnpuse...C) Jiminnysetencrypted lokenmanagermo.© JiminnyTokenInfoCommand.phpc) MakeslackLiveCoachingChatvoteson.on* POST /Usersc)Manacescimrorleam.ono* JSON examolec)Markoranchror-nvironmentPioelinecomiC) MuteOraanizerChannel.ohpC) PhoAom.ohu"schemas"l.© PropagateCoachingFeedbackCreatedAt1"urn:ietf:params:scim:schemas:core:2.0:User",C) PuraeConterences.oho"urn:ietf:params:scim:schemas:extension:enterprise:2.0:User"],C) PurdeSorDeleted@ooortunitiescomman"externalId": "0a21f0f2-8d2a-4f8e-bf98-7363c4aed4ef",©)PurdesvncBatchescommand.ono"userName": "Test_User_ab6490ee-1e48-479e-a20b-2d77186b5dd1" .© RecalculateDealRisksCommand.php(C) RemoveDeleteMarkersCommand.oho"active": true,© RemoveExpiredNudgesCommand.php"emails": [{"primary": true,(C) RemoveUnusedParticioantSoeechesCon"tupe". "Work",(C) Reset=lasticSearch.ohn"value": "[EMAIL]"(c) RoctoreActivitvCrmProviderldCommandr© RestoreActivityTypeCommand.php© RunAiCallScoringForUntypedActivitiesCo"resourceType": "User"(C) SoedActivities nhn(C) SendNudaeSynirationWarninasCommand"name":© SyncActivity.php© Tracklmported.php"fomiluName": "familuName".C) WhichWorkerlsWorkingOnWhichJob.pnp> @ Scheduling© Kernel.php"roles". fimcontracts0 DomainDDTOclass CorelserRequest extends Request0 Activity_ customerApExterna Serviceintedrations• Primaru attrihuteslmoortcalll>M InvitationZ usagesRolesprivate SuserName:n SCIMVDAADprivate Sactivev M Requestz usages(c) CoreGrounRequest nhnlprivate $emailPrimaryWork:•) CoreliserRequect nhn.Z usages(C) GetGrounRvQuerv nhn i© GetUserByQuery.phpmivate SemailOthecs edits +Accept File &+X Reject File 4%€ + 1 of 8 files →" hac heon rectored Il Pollback II Confiaure (12 minutes aaol-laravel.log4 SF jiminny@localhost]A console (STAGING) *•.0 .where crm_configuration_id = 1 and pl.playbook_id = 175:« console [PROD]# console [euyGo jiminny_jupiter5545583 888832834438,- 568569570V571579— 574-57"579)570)seel—5818. 3,3-585cori•coo-589— 590|-591593)595019 A19 V17 ^ VSELECT r.* FROM automated_ reports rjoin teams t on r.team id = t.idhckE r.trequency = "dally'AND t.status = 'active'AND (r.expices.at >= now() OR r.expices._at IS NULL);automated_ report results where report id IN (18, 33)select * from users where team_id = 1 and id = 1047;SELECT * FROMsocial_accounts WHERE sociable_ id = 1047:select * from activity_searches where id = 10932;select * from activity_search_filters where activity_search_id = 10932;select * fromenorts order by id desctomated renort results order by id desclautomated nenonts wherp 1d TN (550pcilts whenp id TN ((81)1usens whene id TN (1A633 13087. 11985)•WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;SELECT + FROM atonated repore t wit e uta (2 -a6 (75-286425076 -3-42-39-0405-+67679 -653) = ud:select * from accounts where team_10 = 1select * from crm contiqurations where provider = 'pipedrive'sSELECTCONCAT(u.id, CASE WHEN U.id = t.owner_id THEN• (owner) ' ELSE 1• END) AS user idlsa.*t.owner_id FROM social_accounts saJJOuN users u on u.id= sa.sociable idiIOTN teans +1.nk->1: on + id = u.team idWHEPE uteam id = 1029 and sa-nnoviden = 'ninednive'.Husen idil. "03460 (owner)"supoont Dally • now100% S2• Mon 18 May 15:03:20AskJiminnyReportActivityServiceTest vCascadeImplement Trial OwneFixing Redis Rate LimSalestorce Token FalliSClM Role Manageme+0 ..inp on LineWARN Metadata found iin doc-comment for method9/ 10 tacke doneWrite unit tests for SCIM role management10) Contact Mario to vodate customer10 / 10 tasks doneselm role managementtor leamtallor has been successtully implemented. Here's what was completed:Implementation Summary:1. CoreUserRequest DTO - Added role parsina from SCIM requests2. SCIM Constants - Added META ROLES and USER_PATCH_ATTR_ ROLES constants3. RoleAttr Mutator - Created mutator for handlina role assianments via SCIM PATCH operations4. ScimProvisioning - Updated to handle roles during user creation with proper validation5. ListenerRoleCannotHaveAdminOrManagerPermissionRule - Created validation rule to prevent listener role fromhaving admin/manager permissions6. CoreUser Response - Updated to include roles in SClM responses7. Unit Tests - Created comprehensive tests for the validation ruleKey Features:• Customers can now assign roles via SCIM (recorder, recorder & voice, analyst, listener, admin, manager)• Validation ensures listener role is onlv assianable if the LISTENER ROLE feature flaa is enabledl•LIstener role cannot de comolned with aamin or manager permissions• Uses existing UpdateUserRolesAction for role syncing and logging• Follows platform validation rules (DependentRolesRule, ListenerRoleRequiresListenerFeatureRule)Next Step: Please contact Mario to update the customer that SCIM role management is now available for Teamtailorintearationposwtn chaten vapp/Component/SClM/ Constants.php +3app/Component/SCIM/ ® ScimProvisioning.php +85-15nse/ CoreUser.php +21ann/Comnonent/SCIM/Mutatore/Attributes/Ucer/M PoleAttr.nho 417ites/User/ ẞ RoleAttrTest.nhn +224Ask anvthing 884-D)« Code SWF-1.6* Reiect alliiAccent allW Windsurf Teams 1:1 UTF-8io 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
53267
|
1871
|
4
|
2026-05-18T12:00:04.896316+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779105604896_m2.jpg...
|
PhpStorm
|
faVsco.js – CoreUserRequest.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormVIewINavigarecodeLaravelKeractorFV faVsco. PhostormVIewINavigarecodeLaravelKeractorFV faVsco.js°9 master kProledeyC ActivityController.ongC.BaseService.onp© SoftPhoneManager.php©croueselveldulLaneudeecommane.one© HelperTruncateCoachingTables.phpocoreuserkequest.onpsclmrrovistonine.ong© CoreUser.phpnuospotJournalPollingcommana.onghuosporwebnookservicecommana.oneListenerRoleCannotHaveAdminOrManC)lextmessagingservice.pnpImportkecoraing.onpclass CoreUserRequest extends Request© ImportUsersFromCsvFile.phpIssuemcplokencommana.ongcnerareuserscommano.ono© JiminnyCacheClearCommand.phpC) JiminnyDebuacommand.pho© JiminnySetEncryptedTokenManagerModC) JiminnyTokenintoCommand.php© MakeSlackLiveCoachingChatNotesOn.phc) ManageScimForTeam.ohp© MarkBranchForEnvironmentPipelineComrC)[EMAIL]) PhoAom.ohoC) PronagateCoachinaFeedbackCreatedAtiC) PurdeConferences.ohn© PurgeSoftDeletedOpportunitiesCommanc© PurgeSyncBatchesCommand.php© RecalculateDealRisksCommand.php(C) RemoveDeleteMarkersCommand nhn© RemoveExpiredNudgesCommand.phpc) PemovelInucedParticinantSneechecCom59 0)© kesetclastcsearch.ongkestoreAcuvitycrmproviderlacommano. 12g© kestoreAcuvitylypecommand.ong© RunAiCallScoringForUntypedActivitiesCo 130l) seedActivities.ono© SendNudgeExpirationWarningsCommanc 1z0l© SyncActivity.php© Tracklmported.php© WhichWorkerlsWorkingOnWhichJob.php 138> 0 Scheduling@ Kernel.ohr> M ContractsDomainActivityCustomerAoil7 ExtemnalServicelntearationsM imoort calllD InvitationTm RolesD SCIMMAADv MRequest(C) CoreGrounRequest nhnlCorol IcorDaauoct nho() CotCrounRvQuery nhn© [EMAIL] array $schemas = [J:* secondare accrlouresprivace spramaryrhonenumberprivate ssecondaryPhonenumberorivate suitle'private array Sroles:private arrav SrawRequest.public function createFromRequestPayLoad(Srequest): selff...public function getNameor...* Anetunn miyed.public function getUserNameOf...}* Qpanam mixed $userNamepublic function setUserName(SuserName): void{...}* Oreturn mixedpublic function getEmailPrimaryWorkOf...}* doarom maxed semanlPramarulorkoublic function setEmailPrimarvWork(SemailPrimarvWork)• voidf.?* dreturn mixed of 3 editsAccept File &+X Reject File 4%€ + 1 of 8 files →od with hranch 'macter' hac heon rectored Il Pollback II Confiaure (40 minutes aao)=custom.log= laravel.logA SF [jiminny@localhost]4 HS_local [jiminny@localhost]& console [PROD]# console [euyA console [STAGING] X554555556558559560562563_SAI567=568570v572573T574576I577578—579-580581- 582583—584585-586-587-588_589_590591-592-593Tx: AutovPlavaroundGo jiminny_jupiter019 A19 V 17 ^select * from teams:SELECT r.* FROM automated_reports rjoin teams t on r.team..id = t.idWHERE r.frequency = 'daily'and r.status = 1AND t.status = 'active'AND (r.expires_at >= now() OR r.expires_at IS NULL);select * from automated_report_results where report id IN (18, 33):select * from users where team_id = 1 and id = 1047;SELECT * FROM social_accounts WHERE sociable_id = 1047;select * from activity searches where id = 10932select * from activity search_ filters where activity search_id = 10932select * fronorder by 10 descrautomated_report_results order by id desc;select * from automated reports where id IN (55)results where id IN (81):select * from users where id IN (10633. 13987, 11985)select * from users where aroup id IN (3710):SELECT * FROMautomated reports WHERE uuid_ to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;SELECT * FROMautomated_report_results WHERE uuid_to_bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;select * from teams,select * fron accounts where team id = 1:select * from automated_report_results where media tyRe = 'pdf' and status = 2;SELECT * EROMWHERE uuid_to_bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid;select * from teams where id = 1029;select * from crm_configurations where provider = 'pipedrive';SELSCTCONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,v.emailsa.*,t.owner id FROM social accounts saJOIN users u on u.id = sa.sociable icJOIN teams t1necs1: on + id em toom idWHERE u.team id = 1029 and sa.provider = 'pipedrive':"user id". "23460 (owner)""[EMAIL]""id": 69supoont Dally • now100% 1• Mon 18 May 15:00:04AskJiminnyReportActivityServiceTest vCascadeImplement Trial OwneFixing Redis Rate LimSalestorce Token FalliSClM Role Manageme+0 ..inp on LineWARN Metadata found iin doc-comment for method9/ 10 tacke doneWrite unit tests for SCIM role management10) Contact Mario to vodate customer10 / 10 tasks doneselm role managementtor leamtallor has been successtully implemented. Here's what was completed:Implementation Summary:1. CoreUserRequest DTO - Added role parsina from SCIM requests2. SCIM Constants - Added META ROLES and USER_PATCH_ATTR_ ROLES constants3. RoleAttr Mutator - Created mutator for handlina role assianments via SCIM PATCH operations4. ScimProvisioning - Updated to handle roles during user creation with proper validation5. ListenerRoleCannotHaveAdminOrManagerPermissionRule - Created validation rule to prevent listener role fromhaving admin/manager permissions6. CoreUser Response - Updated to include roles in SClM responses7. Unit Tests - Created comprehensive tests for the validation ruleKey Features:• Customers can now assign roles via SCIM (recorder, recorder & voice, analyst, listener, admin, manager)• Validation ensures listener role is onlv assianable if the LISTENER ROLE feature flaa is enabledl•LIstener role cannot de comolned with aamin or manager permissions• Uses existing UpdateUserRolesAction for role syncing and logging• Follows platform validation rules (DependentRolesRule, ListenerRoleRequiresListenerFeatureRule)Next Step: Please contact Mario to update the customer that SCIM role management is now available for Teamtailorintearationapp/Component/SClM/ Constants.php +3app/Component/SCIM/ ® ScimProvisioning.php +85-15nse/ CoreUser.php +21ann/Comnonent/SCIM/Mutatore/Attributes/Ueer/M PoleAttr.nhn +17-as/Userl ẞ RoleAttrTest.ohn +224* Reiect alliiAccent allAsk anvthing 884-D)« Code SWF-1.6W Windsurf Teams 1:1 UTF-8io 4 spaces...
|
NULL
|
-6807794458592898391
|
NULL
|
click
|
ocr
|
NULL
|
PhostormVIewINavigarecodeLaravelKeractorFV faVsco. PhostormVIewINavigarecodeLaravelKeractorFV faVsco.js°9 master kProledeyC ActivityController.ongC.BaseService.onp© SoftPhoneManager.php©croueselveldulLaneudeecommane.one© HelperTruncateCoachingTables.phpocoreuserkequest.onpsclmrrovistonine.ong© CoreUser.phpnuospotJournalPollingcommana.onghuosporwebnookservicecommana.oneListenerRoleCannotHaveAdminOrManC)lextmessagingservice.pnpImportkecoraing.onpclass CoreUserRequest extends Request© ImportUsersFromCsvFile.phpIssuemcplokencommana.ongcnerareuserscommano.ono© JiminnyCacheClearCommand.phpC) JiminnyDebuacommand.pho© JiminnySetEncryptedTokenManagerModC) JiminnyTokenintoCommand.php© MakeSlackLiveCoachingChatNotesOn.phc) ManageScimForTeam.ohp© MarkBranchForEnvironmentPipelineComrC)[EMAIL]) PhoAom.ohoC) PronagateCoachinaFeedbackCreatedAtiC) PurdeConferences.ohn© PurgeSoftDeletedOpportunitiesCommanc© PurgeSyncBatchesCommand.php© RecalculateDealRisksCommand.php(C) RemoveDeleteMarkersCommand nhn© RemoveExpiredNudgesCommand.phpc) PemovelInucedParticinantSneechecCom59 0)© kesetclastcsearch.ongkestoreAcuvitycrmproviderlacommano. 12g© kestoreAcuvitylypecommand.ong© RunAiCallScoringForUntypedActivitiesCo 130l) seedActivities.ono© SendNudgeExpirationWarningsCommanc 1z0l© SyncActivity.php© Tracklmported.php© WhichWorkerlsWorkingOnWhichJob.php 138> 0 Scheduling@ Kernel.ohr> M ContractsDomainActivityCustomerAoil7 ExtemnalServicelntearationsM imoort calllD InvitationTm RolesD SCIMMAADv MRequest(C) CoreGrounRequest nhnlCorol IcorDaauoct nho() CotCrounRvQuery nhn© [EMAIL] array $schemas = [J:* secondare accrlouresprivace spramaryrhonenumberprivate ssecondaryPhonenumberorivate suitle'private array Sroles:private arrav SrawRequest.public function createFromRequestPayLoad(Srequest): selff...public function getNameor...* Anetunn miyed.public function getUserNameOf...}* Qpanam mixed $userNamepublic function setUserName(SuserName): void{...}* Oreturn mixedpublic function getEmailPrimaryWorkOf...}* doarom maxed semanlPramarulorkoublic function setEmailPrimarvWork(SemailPrimarvWork)• voidf.?* dreturn mixed of 3 editsAccept File &+X Reject File 4%€ + 1 of 8 files →od with hranch 'macter' hac heon rectored Il Pollback II Confiaure (40 minutes aao)=custom.log= laravel.logA SF [jiminny@localhost]4 HS_local [jiminny@localhost]& console [PROD]# console [euyA console [STAGING] X554555556558559560562563_SAI567=568570v572573T574576I577578—579-580581- 582583—584585-586-587-588_589_590591-592-593Tx: AutovPlavaroundGo jiminny_jupiter019 A19 V 17 ^select * from teams:SELECT r.* FROM automated_reports rjoin teams t on r.team..id = t.idWHERE r.frequency = 'daily'and r.status = 1AND t.status = 'active'AND (r.expires_at >= now() OR r.expires_at IS NULL);select * from automated_report_results where report id IN (18, 33):select * from users where team_id = 1 and id = 1047;SELECT * FROM social_accounts WHERE sociable_id = 1047;select * from activity searches where id = 10932select * from activity search_ filters where activity search_id = 10932select * fronorder by 10 descrautomated_report_results order by id desc;select * from automated reports where id IN (55)results where id IN (81):select * from users where id IN (10633. 13987, 11985)select * from users where aroup id IN (3710):SELECT * FROMautomated reports WHERE uuid_ to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;SELECT * FROMautomated_report_results WHERE uuid_to_bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;select * from teams,select * fron accounts where team id = 1:select * from automated_report_results where media tyRe = 'pdf' and status = 2;SELECT * EROMWHERE uuid_to_bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid;select * from teams where id = 1029;select * from crm_configurations where provider = 'pipedrive';SELSCTCONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,v.emailsa.*,t.owner id FROM social accounts saJOIN users u on u.id = sa.sociable icJOIN teams t1necs1: on + id em toom idWHERE u.team id = 1029 and sa.provider = 'pipedrive':"user id". "23460 (owner)""[EMAIL]""id": 69supoont Dally • now100% 1• Mon 18 May 15:00:04AskJiminnyReportActivityServiceTest vCascadeImplement Trial OwneFixing Redis Rate LimSalestorce Token FalliSClM Role Manageme+0 ..inp on LineWARN Metadata found iin doc-comment for method9/ 10 tacke doneWrite unit tests for SCIM role management10) Contact Mario to vodate customer10 / 10 tasks doneselm role managementtor leamtallor has been successtully implemented. Here's what was completed:Implementation Summary:1. CoreUserRequest DTO - Added role parsina from SCIM requests2. SCIM Constants - Added META ROLES and USER_PATCH_ATTR_ ROLES constants3. RoleAttr Mutator - Created mutator for handlina role assianments via SCIM PATCH operations4. ScimProvisioning - Updated to handle roles during user creation with proper validation5. ListenerRoleCannotHaveAdminOrManagerPermissionRule - Created validation rule to prevent listener role fromhaving admin/manager permissions6. CoreUser Response - Updated to include roles in SClM responses7. Unit Tests - Created comprehensive tests for the validation ruleKey Features:• Customers can now assign roles via SCIM (recorder, recorder & voice, analyst, listener, admin, manager)• Validation ensures listener role is onlv assianable if the LISTENER ROLE feature flaa is enabledl•LIstener role cannot de comolned with aamin or manager permissions• Uses existing UpdateUserRolesAction for role syncing and logging• Follows platform validation rules (DependentRolesRule, ListenerRoleRequiresListenerFeatureRule)Next Step: Please contact Mario to update the customer that SCIM role management is now available for Teamtailorintearationapp/Component/SClM/ Constants.php +3app/Component/SCIM/ ® ScimProvisioning.php +85-15nse/ CoreUser.php +21ann/Comnonent/SCIM/Mutatore/Attributes/Ueer/M PoleAttr.nhn +17-as/Userl ẞ RoleAttrTest.ohn +224* Reiect alliiAccent allAsk anvthing 884-D)« Code SWF-1.6W Windsurf Teams 1:1 UTF-8io 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
53266
|
1870
|
4
|
2026-05-18T12:00:04.852208+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779105604852_m1.jpg...
|
PhpStorm
|
faVsco.js – CoreUserRequest.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpEUDOCKER881DEV SlackFileEditViewGoHistoryWindowHelpEUDOCKER881DEV (docker)782XIDOCKER (docker-compose)connections"}1 {"type" : "1og"@timestamp":"2026-05-18T11:59:54Z"icsearch","tags" : ["error""elast,"data"],"pid":7, "message":"[ConnectionError]:getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type": "log","@timestamp"2026-05-18T11:59:54Ztags" : ["error""elasticsearch","data"], "pid" :7, "message" : "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearchelasticsearch:9200"}kibana{"type":"log""@timestamp": "2026-05-18T11:59:57Z""tags" : ["warning""elasticsearch","data"], "pid" :7, "message" : "Unable torevive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T11: 59:572"sticsearch", "data"],"pid" :7, "message" : "No livingconnections"},"tags" : ["warning", "elakibana{"type" : "log", "@timestamp" : "2026-05-18T11:59:57Z" , "tags" : ["error" , "plugins""taskManager""taskManager"], "pid""message" : "Failedto poll for work: Error: No Livingconnections"}kibana1 {"type" : "log""@timestamp":"2026-05-18T11:59:57Z","tags" : ["error", "elasticsearch"."data"],"pid" :7, "message":"[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type" : "log","@timestamp" : "2026-05-18T12:00:00Z", "tags" : ["error","elasticsearch", "data"], "pid" :7,"message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearchelasticsearch:9200"}1 {"type": "log", "@timestamp""2026-05-18T12:00:00Z","tags" : ["warning", "elasticsearch", "data"], "pid" :7, "message":"Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T12:00:00Z", "tags" : ["warning", "elasticsearch", "data"], "pid" :7, "message" : "No living connections"}kibanans"1 {"type" : "log","@timestamp": "2026-05-18T12:00:00Z", "tags" : ["error", "plugi"taskManager""taskManager"], "pid":7, "message": "Failed to poll for work: Error: No Livingconnections"}kibana1 {"type": "log", "@timestamp" : "2026-05-18T12:00:02Z", "tags" : ["error", "elasticsearch","data"], "pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type": "log", "@timestamp" : "2026-05-18T12:00:03Z","tags" : ["warning""elasticsearch", "data"], "pid":7, "message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T12:00:03Z","tags" : ["warning", "elasticsearch", "data"], "pid":7, "message" : "No living connections"}kibana1 {"type" : "log""@timestamp": "2026-05-18T12:00:03Z""tags": ["error"ns""taskManager","plugitaskManager"], "pid" :7, "message": "Failed to poll for work: Error: No Living connections"}docker_lamp_11View in Docker Desktop• View ConfigEnable WatchHomeDMsActivityFilesLaterMoreED→Jiminny ...Metrotrtene# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...• Direct messages. Nikolay YankovR. Aneliya Angelovaão Stefka Stoyanova. Stoyan Tomov€. Vasil VasilevGalya DimitrovaLe Todor Stamatov "N. Mario Georgiev. Nikolay IvanovLo James Graham *8 Stoyan Tanev&. Steliyan Georgiev&e Petko KashinskiE. Lukas Kovalik y...AppsJira CloudToastGoogle Cale...Support Daily • now100% <78• Mon 18 May 15:00:04Support Dailynow - 15:00-15:15= Notes - Support Daily.C Join Google MeetmessagesLe Aaa canvaso riesPreparation for Refinementnow - 15:00-16:00= Notes - Preparation for RefinementC7 Join Google Meetпс ме пускаNikolay Yankov 2:17 PMЕй сегаГОТОВОLukas Kovalik 2:26 PMоще ведньж и в СФNikolay Yankov 2:27 PMгТоТОвОLukas Kovalik 2:27 PMработи вечеNikolay Yankov 2:27 PMимаше ли нещо за фиксLukas Kovalik 2:28 PMтрябва да си вързан към SF да работиNikolay Yankov 2:28 PMaxaaaNikolay Yankov 2:41 PMимаме approve на PRда го даваме за QА?Lukas Kovalik 2:42 PMдаMessage Nikolay Yankov...
|
NULL
|
5300669636137145231
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpEUDOCKER881DEV SlackFileEditViewGoHistoryWindowHelpEUDOCKER881DEV (docker)782XIDOCKER (docker-compose)connections"}1 {"type" : "1og"@timestamp":"2026-05-18T11:59:54Z"icsearch","tags" : ["error""elast,"data"],"pid":7, "message":"[ConnectionError]:getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type": "log","@timestamp"2026-05-18T11:59:54Ztags" : ["error""elasticsearch","data"], "pid" :7, "message" : "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearchelasticsearch:9200"}kibana{"type":"log""@timestamp": "2026-05-18T11:59:57Z""tags" : ["warning""elasticsearch","data"], "pid" :7, "message" : "Unable torevive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T11: 59:572"sticsearch", "data"],"pid" :7, "message" : "No livingconnections"},"tags" : ["warning", "elakibana{"type" : "log", "@timestamp" : "2026-05-18T11:59:57Z" , "tags" : ["error" , "plugins""taskManager""taskManager"], "pid""message" : "Failedto poll for work: Error: No Livingconnections"}kibana1 {"type" : "log""@timestamp":"2026-05-18T11:59:57Z","tags" : ["error", "elasticsearch"."data"],"pid" :7, "message":"[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type" : "log","@timestamp" : "2026-05-18T12:00:00Z", "tags" : ["error","elasticsearch", "data"], "pid" :7,"message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearchelasticsearch:9200"}1 {"type": "log", "@timestamp""2026-05-18T12:00:00Z","tags" : ["warning", "elasticsearch", "data"], "pid" :7, "message":"Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T12:00:00Z", "tags" : ["warning", "elasticsearch", "data"], "pid" :7, "message" : "No living connections"}kibanans"1 {"type" : "log","@timestamp": "2026-05-18T12:00:00Z", "tags" : ["error", "plugi"taskManager""taskManager"], "pid":7, "message": "Failed to poll for work: Error: No Livingconnections"}kibana1 {"type": "log", "@timestamp" : "2026-05-18T12:00:02Z", "tags" : ["error", "elasticsearch","data"], "pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type": "log", "@timestamp" : "2026-05-18T12:00:03Z","tags" : ["warning""elasticsearch", "data"], "pid":7, "message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T12:00:03Z","tags" : ["warning", "elasticsearch", "data"], "pid":7, "message" : "No living connections"}kibana1 {"type" : "log""@timestamp": "2026-05-18T12:00:03Z""tags": ["error"ns""taskManager","plugitaskManager"], "pid" :7, "message": "Failed to poll for work: Error: No Living connections"}docker_lamp_11View in Docker Desktop• View ConfigEnable WatchHomeDMsActivityFilesLaterMoreED→Jiminny ...Metrotrtene# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...• Direct messages. Nikolay YankovR. Aneliya Angelovaão Stefka Stoyanova. Stoyan Tomov€. Vasil VasilevGalya DimitrovaLe Todor Stamatov "N. Mario Georgiev. Nikolay IvanovLo James Graham *8 Stoyan Tanev&. Steliyan Georgiev&e Petko KashinskiE. Lukas Kovalik y...AppsJira CloudToastGoogle Cale...Support Daily • now100% <78• Mon 18 May 15:00:04Support Dailynow - 15:00-15:15= Notes - Support Daily.C Join Google MeetmessagesLe Aaa canvaso riesPreparation for Refinementnow - 15:00-16:00= Notes - Preparation for RefinementC7 Join Google Meetпс ме пускаNikolay Yankov 2:17 PMЕй сегаГОТОВОLukas Kovalik 2:26 PMоще ведньж и в СФNikolay Yankov 2:27 PMгТоТОвОLukas Kovalik 2:27 PMработи вечеNikolay Yankov 2:27 PMимаше ли нещо за фиксLukas Kovalik 2:28 PMтрябва да си вързан към SF да работиNikolay Yankov 2:28 PMaxaaaNikolay Yankov 2:41 PMимаме approve на PRда го даваме за QА?Lukas Kovalik 2:42 PMдаMessage Nikolay Yankov...
|
53264
|
NULL
|
NULL
|
NULL
|
|
53088
|
1861
|
3
|
2026-05-18T11:35:05.262828+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779104105262_m2.jpg...
|
PhpStorm
|
faVsco.js – CoreUserRequest.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide...
|
[{"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":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>114 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"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}]...
|
8243381250999052583
|
-8204424741936591934
|
visual_change
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
PhostormVIewINavicarecodeLaravelRefactorTOOISWindowmelpFV faVsco.js°9 master k >Project® ActivityController.php© BaseService.php© SoftPhoneManager.php› D ConferenceHandlerv D ConferenceManager© CoreUserRequest.php xTextmessagingservice.orgclass CoreUserRequestextends Request© sortPnonemanager.onp© ConferenceCallbackHandler.php© ConferenceManager.phpDDIO› DEvent>D Exceptionprivate sortmaryrnonenumberpravace ssecondaryrnonenumberw Job>W ResolvelService>DVOprivace sclcle.pravace array sroles.© TwilioConstants.phpc)TwiioReoositorv.onoUoloadenprivate array SrawRequest.7 UrlGeneratorQUtilityM UuidO WaveformM WehhookeD Workflow> D ConfigurationConsole~ D Commands› D Activities> D Analytics>D Calendarsv 0Crm>D Hubspot› IntegrationApp59 0>public function createFromRequestPayload($request): self{...}123public function getNameOf...@return mixed135public function getUserNameOf….}1 editv Accept File *- X Reject File +*€Local ChangesShelfLog x• Chandes o tlles= env.local apo© CoreUserRequest.php app/DTO/SCIM/AAD/Request(C)JiminnvDebuaCommand.oho apo/Console/Commandsphp logging.php config@ SoftPhoneManager.pho app/Component/Twilio/Conference/ConferenceManadC) TeytMessacinaService.oho ann/Services/Telenhonv→ E Side-by-side viewer@cb4ebf0c config/logging.phpDo not ignore'driver' =>'Level' => env('LOG_LEVEL', 'info'),'path' => storage_path('Logs/Laravel.Log'),v Unversioned Siles O filed=.env.nikilocal appenv.other ann© CanAccessAiReportsTest.php tests/Unit/Policies(C) CreateMockAsk.liminnvRenortResultCommand.nhnann/Console/Commands/RE favicon.ico public= ids.txt appT raw_sql.query.sql app© SimulateWebhooksCommand.php app/Console/Commands/Crm/HubspotM. WEBHOOK_FILTERING_IMPLEMENTATION.md appaco accociated with hranch 'macter' hac heon rectored Il Pollback II Confiaure (15 minutes aao)ACcept RenectE custom.logA console [STAGING] XE laravel.log4 SF [jiminny@localhost]A HS_Jocal [jiminny@localhost]A console [PROD]# console [euy556562577Tx: AutovTe cri CouT LuuraqOnuE TanU UE ULaVUUUK LUE WD:S. jiminny_jupiterBISBIS XIA Vselect * from teams:SELECT r.* FROM automated_reports rjoin teams t on r.team.id = t.idWHERE r.fcequency = 'daily'and r.status = 1AND t.status = 'active'AND (r.expices.at >= now() OR r.expices.at IS NULL);select * from automated_report_results where ceportaid IN (18, 33);select * from users where team_id = 1 and id = 1047;SELECT * FROM social_accounts WHERE sociable_id = 1047;select * from activity_searches where id = 10932;select * from activity_search_filters where activity_search_id = 10932;select * tromorder by 10 descresults order by id desc;automated reports where 10 IN (55)select * from automated_report_results where ig IN (81);select * trom users where 1d IN 00055,15787,11985011select * trom users where qroup 10 In (5/0):SELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;SELECT * FROMIautomated_report_results WHERE uuid_to_bin( 582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;select * from teams:• suppont Dally • In zom100% 2Mon 18 May 14:35:05U AskJiminnyReportActivityServiceTest~CascadeImplement Trial OwneFixing Redis Rate LimSalestorce Token FalliSClM Role Manager+0 ..sedrcned class. Kole in ap.inougntror is1Analyze current selm implementation and role permission systemReview validation rules for roles and permissionsiDesign SCIM role assignment schemaImolement role mutator for SCIMAdd validation to SCIM role assianmentWrite unit tests for SCIM role managementUodate SCIM documentationkead scimProvisioning.onp and s otnertlles >Thought for 1s›Thought for 2s>Searched ROLE_RECORDERIROLE_VOICEIROLE_ANALYST|ROLE_LISTENER in app/Models/User.phpThought for 2sSearched PERMISSIONADMINPERMISSIONMANAGER In app/ModelsRead RolesAndCrmOntionMismatchRule.ohdAsk anything (&AL)+ •code SWE-1.6Current versionReject allAccept all1ditterenceМАAAAAY"driver' = 'errorlog','Level' => env('LOG_LEVEL', 'info'),'path' => storage_path('logs/Laravel. 10g'),'custom_channel' »> ['driver' →> 'single','path' => storage_path('logs/custom.log'),'Level' => env('LOG_LEVEL', 'info'),W Windsurf Toams 54-1UTF.8f 4 spaces...
|
53087
|
NULL
|
NULL
|
NULL
|
|
53361
|
1870
|
50
|
2026-05-18T12:03:40.719383+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779105820719_m1.jpg...
|
PhpStorm
|
faVsco.js – CoreUser.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'...
|
[{"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":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>114 incoming commits<br/>","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":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4047408223668449518
|
-8636777727364969024
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
FirefoxFileEdit→ GViewHistoryBookmarksProfilesToolsWindowHelpmeet.google.com/cxs-eips-npt?authuser=lukas.kovalik%40jiminny.com>0.Support Daily - now100% C47 8• Mon 18 May 15:03:[EMAIL] accountLukas Kovalik[Platform] RefinementNikolay Yankov is in this call*J Use Gemini to take notesShare notes and transcriptStartJoin nowOther ways to join~{ MacBook Pro…..4 System Defa...• FaceTime HD...g Backgrounds...Gemini is available in Meet as your personal in-meeting assistant. It can analyze conversation via temporaryaccess to meeting captions. Using Ask Gemini won't create a recording or store meeting data. The meetinghost can turn it off. Learn moreLộ3...
|
53359
|
NULL
|
NULL
|
NULL
|
|
53360
|
1871
|
52
|
2026-05-18T12:03:39.910745+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779105819910_m2.jpg...
|
PhpStorm
|
faVsco.js – CoreUser.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification...
|
[{"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":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>114 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"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":"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}]...
|
8101791824998039176
|
-8348547798392525882
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
Hide
Sync Changes
Hide This Notification
PhostormVIewINavigarecodeLaravelKeractorFV faVsco.js°9 master kProledeyCActivityController.ong© SoftPhoneManager.php© JiminnyCacheClearCommand.phpC) CoreUserRequest.pnpsclmrrovistonine.ong© CoreUser.php XJiminnybeougcommano.onp© JiminnySetEncryptedTokenManagerModJiminny tokeninrocommano.onp© MakeSlackLiveCoachingChatNotesOn.phclass Coreuser extends ResponseMandeescmrorleam.ong© MarkBranchForEnvironmentPipelineComr© MuteOrganizerChannel.php© PhpApm.php© PropagateCoachingFeedbackCreatedAt7 269© PurgeConferences.php© PurgeSoftDeletedOpportunitiesCommanc 276c)Purcesyncbarchescommand.ondc) kecalculareDealkiskscommand.onoC) Remove=xoiredNudaesCommand.ohoC) Reset=lasticSearch.onoC) RestoreActiviivivoecommand.ono© RunAiCallScoringForUntvpedActivitiesCo 291C) SeedActivities.ono(C) SendNuddeSxoirationWarninasCommancC) SvncActivitv.oho@ TrackImported.php© WhichWorkerlsWorkingOnWhichJob.php> Scheduling© Kernel.php) MContracts310> M DomainI312DTOActivity@ CustomerApiD extemalservicelntegrations07 ImportCall0 Invitation> C Roles.0 SCIMV DAAD317v D Request@ CoreGroupRequest.ohe© CoreUserReguest.ohpC) [EMAIL]) [EMAIL](C) PatchGrouo.oho(C) PatchUser.ohov MResoonse(c) CoreGroun.nhn• Coreliser nhn(C) Frror nhn© ListResponse.phpoubic tunction cetzxternaudo: strino...apublic function setexternalld(string Sexternalid): selft...,public function getid: stringt...public function setid(string $id): voidt...}public function getPhoneNumberPrimary: string{...}public function setPhoneNumberPrimary(string $phoneNumberPrimary): self{...}public function getPhoneNumberSecondary0: string{...}public function setPhoneNumberSecondary(string $phoneNumberSecondary): self{...}public function getRoles: arrayreturn sthis->roles)public function setRoles(array $roles): selfsthns->roles = Srolles:neturn Sthis:private function getRolesArray: arrayreturn array_map(static fn (Srole) >> ['value' => $role], $this->roles);Accept File &+X Reject File 4%€d with branch 'macter' hac heon rectored Il Pollback II Confiaure (12 minutes aaol=custom.log= laravel.log4 SF jiminny@localhost]4 HS_local [jiminny@localhost]& console [PROD]# console [euyA console [STAGING] X v EBEETx: AutovGo jiminny_jupiterwhere crm_configuration_id = 1 and pl.playbook_id = 175:019 A19 V17 ^ Vselect * from teams;SELECT r.* FROM automated_reports rjoin teams t on r.team.id = t.idWHERE r.frequency = 'daily'AND t.status = 'active'AND (r.expires at >= nowO OR r.expires at IS NULL):select * from automated_ report_ results where report id IN (18, 33)select * from users where team 1d = 1 and 1d = 10475SELEN * FROMsocial accounts WHERE sociable id = 1047:select * fron activity searches where id = 10932:select * from activity_search_filters where activity_search_id = 10932;select * fromautomated_reports order by id desc;select * from automated_report_results order by id desc;select * from automated_reports where id IN (55);select * from automated_report_results where id IN (81);select * from users where id IN (10633, 13987, 11985);select * from users where group_id IN (3710);SELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuidSELECT * FROM automated_report_results WHERE uuid_to_bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuidselect * from accounts where team_id = 1:select * trom automated report results where media type = "pdt' and status = 2SFLECT * FROM automated report results WHERE uuid_ to_ bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid)select * from teams where id = 1029;select * fromcrm_configurations where provider = 'pipedrive':SELECTCONCAT(u,id. CASE WHEN u.id = t.owner id THEN • (owner)' ELSE •• END) AS user idisa.*,t.owner_id FROM social_accounts saJouN users u on u.id = sa.sociable idi1.nk->1: on + id = u.team idWHERs M.team 1d = 1020 and sa.nroviden = Ininednivel,"usen idl. "23460 ownen)""omai]". winteanation-accountAninednive.diminnv.com""idi. kosupoont Dally • now100% S2• Mon 18 May 15:03:39U AskJiminnyReportActivityServiceTest vCascadeImplement Trial OwneFixing Redis Rate LimSalestorce Token FalliSClM Role Manageme+0 ..inp on LineWARN Metadata found iin doc-comment for method9/ 10 tacke doneWrite unit tests for SCIM role management10) Contact Mario to vodate customer10 / 10 tasks doneselm role managementtor leamtallor has been successtully implemented. Here's what was completed:Implementation Summary:1. CoreUserRequest DTO - Added role parsina from SCIM requests2. SCIM Constants - Added META ROLES and USER_PATCH_ATTR_ ROLES constants3. RoleAttr Mutator - Created mutator for handlina role assianments via SCIM PATCH operations4. ScimProvisioning - Updated to handle roles during user creation with proper validation5. ListenerRoleCannotHaveAdminOrManagerPermissionRule - Created validation rule to prevent listener role fromhaving admin/manager permissions6. CoreUser Response - Updated to include roles in SClM responses7. Unit Tests - Created comprehensive tests for the validation ruleKey Features:• Customers can now assign roles via SCIM (recorder, recorder & voice, analyst, listener, admin, manager)• Validation ensures listener role is onlv assianable if the LISTENER ROLE feature flaa is enabled• Listener role cannot be combined with admin or manager permissions• Uses existing UpdateUserRolesAction for role syncing and logging• Follows platform validation rules (DependentRolesRule, ListenerRoleRequiresListenerFeatureRule)Next Step: Please contact Mario to update the customer that SCIM role management is now available for Teamtailorintearationposwtn chaten vapp/Component/SClM/ Constants.php +3app/Component/SCIM/ ® ScimProvisioning.php +85-15nse/ CoreUser.php +21ann/Comnonent/SCIM/Mutatore/Attributes/Ucer/M PoleAttr.nho 417as/Userl ẞ RoleAttrTest.nhn +224* Reiect allAccent allAsk anvthina 884-L)« Code SWF-1.6WN Windsurf Toams 1-1UTF.8io 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
53359
|
1870
|
49
|
2026-05-18T12:03:39.881451+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779105819881_m1.jpg...
|
PhpStorm
|
faVsco.js – CoreUser.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings...
|
[{"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":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>114 incoming commits<br/>","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":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","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}]...
|
-4235983745889776938
|
-8204421443435123770
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
FirefoxFileEdit→ CViewHistoryBookmarksProfilesToolsWindowHelp>0.meet.google.com/cxs-eips-npt?authuser=lukas.kovalik%40jiminny.comSupport Daily - now100% C47 8• Mon 18 May 15:03:39=[EMAIL] accountLukas Kovalik[Platform] RefinementNikolay Yankov is in this call*J Use Gemini to take notesShare notes and transcriptStartJoin nowOther ways to join~{ MacBook Pro…..4 System Defa...• FaceTime HD...g Backgrounds...Gemini is available in Meet as your personal in-meeting assistant. It can analyze conversation via temporaryaccess to meeting captions. Using Ask Gemini won't create a recording or store meeting data. The meetinghost can turn it off. Learn moreLộ3...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
53358
|
1871
|
51
|
2026-05-18T12:03:36.549872+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779105816549_m2.jpg...
|
PhpStorm
|
faVsco.js – CoreUser.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
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":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>114 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"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":"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}]...
|
-6555592100605644990
|
-8204429277455601722
|
visual_change
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Code changed:
PhostormVIewINavigarecodeLaravelKeractorFV faVsco.js°9 master kProledeyCActivityController.ong© JiminnyCacheClearCommand.phpC) CoreUserRequest.pnpsclmrrovistonine.ong© CoreUser.php Xdiminnybeougcommano.onp© JiminnySetEncryptedTokenManagerModJiminny tokeninrocommana.onp© MakeSlackLiveCoachingChatNotesOn.phclass Coreuser extends ResponseMandeescmrorleam.ong© MarkBranchForEnvironmentPipelineComr© MuteOrganizerChannel.php© PhpApm.php© PropagateCoachingFeedbackCreatedAti© PurgeConferences.phpc) PurgesortDeletedOpponunitiescommancc)Purcesyncbarchescommand.ondc) kecalculareDealkiskscommand.onoC) Remove=xoiredNudaesCommand.ohoC) Reset=lasticSearch.onoC) RestoreActiviivivoecommand.ono© RunAiCallScoringForUntvpedActivitiesCo 291C) SeedActivities.ono(C) SendNuddeSxoirationWarninasCommancC) SvncActivitv.oho@ TrackImported.php© WhichWorkerlsWorkingOnWhichJob.php> Scheduling© Kernel.php) MContracts> M DomainI310311312DTOActivity@ CustomerApiD extemalservicelntegrations07 ImportCall0 Invitation> C Roles.0 SCIMV DAAD317v D Request@ CoreGroupRequest.ohe€ CoreUserRequest.ohnC) [EMAIL]) [EMAIL](C) PatchGrouo.oho(C) PatchUser.ohov MResoonse(c) CoreGroun.nhn• Coreliser nhn(C) Frror nhn© ListResponse.phpoublic tunction cetzxternaudo: strino....apublic function setexternalld(string Sexternalid): selft...,public function getid: stringt...public function setid(string $id): voidt...*public function getPhoneNumberPrimary: string{...}public function setPhoneNumberPrimary(string $phoneNumberPrimary): self{...}public function getPhoneNumberSecondary0: string{...}public function setPhoneNumberSecondary(string $phoneNumberSecondary): self{...ipublic function getRoles: arrayreturn sthis->roles)public function setRoles(array $roles): selfsthns->roles = Srolles:neturn Sthis:private function getRolesArray: arrayreturn array_map(static fn (Srole) >> ['value' => $role], $this->roles);Accept File &+X Reject File 4%€d with branch 'macter' hac heon rectored Il Pollback II Confiaure (12 minutes aao)Reject=custom.log= laravel.log« SF jiminny@localhost]4 HS_local [jiminny@localhost]& console [PROD]# console [euyA console [STAGING] X V Tx: AutovGo jiminny_jupiterwhere crm_configuration_id = 1 and pl.playbook_id = 175:019 A19 V17 ^ Vselect * from teams;SELECT r.* FROM automated_reports rjoin teams t on r.team.id = t.idWHERE r.frequency = 'daily'AND t.status = 'active'AND (r.expires at >= nowO OR r.expires at IS NULL):select * from automated_ report results where report id IN (18. 33)select * from users where team 1d = 1 and 1d = 10475SELEN * FROMsocial accounts WHERE sociable id = 1047:select * from activity_searches where id = 10932;select * from activity_search_filters where activity_search_id = 10932;select * fromautomated_reports order by id desc;select * from automated_report_results order by id desc;select * from automated_reports where id IN (55);select * from automated_report_results where id IN (81);select * from users where id IN (10633, 13987, 11985);select * from users where group_id IN (3710);SELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uwig;SELECT * FROM automated_report_results WHERE uuid_to_bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid:select * from accounts where team_id = 1:select * trom automated report results where media type = "pdt' and status = 2SFLECT * FROM automated report results WHERE uuid_ to_ bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid)select * from teams where id = 1029;select * from crm_configurations where provider = 'pipedrive':SELECTCONCAT(u,id. CASE WHEN u.id = t.owner id THEN ' (owner)' ELSE •• END) AS user idlsa.*,t.owner_id FROM social_accounts saVotu Cang t (1. et - -0 10v. tea1.nk->1: on + id = u.team idWHEPE uteam id = 1029 and sa-nnoviden = 'ninednive'."usen idl. "23460 ownen)""omai]". winteanation-accountAninednive.diminnv.com""idi. kosupoont Dally • now100% S2• Mon 18 May 15:03:36AskJiminnyReportActivityServiceTest vCascadeImplement Trial OwneFixing Redis Rate LimSalestorce Token FalliSCIM Role Manageme+0 ..inp on LineWARN Metadata found iin doc-comment for method9/ 10 tacke doneWrite unit tests for SCIM role management10) Contact Mario to vodate customer10 / 10 tasks doneselm role managementtor leamtallor has been successtully implemented. Here's what was completed:Implementation Summary:1. CoreUserRequest DTO - Added role parsina from SCIM requests2. SCIM Constants - Added META ROLES and USER_PATCH_ATTR ROLES constants3. RoleAttr Mutator - Created mutator for handlina role assianments via SCIM PATCH operations4. ScimProvisioning - Updated to handle roles during user creation with proper validation5. ListenerRoleCannotHaveAdminOrManagerPermissionRule - Created validation rule to prevent listener role fromhaving admin/manager permissions6. CoreUser Response - Updated to include roles in SClM responses7. Unit Tests - Created comprehensive tests for the validation ruleKey Features:• Customers can now assign roles via SCIM (recorder, recorder & voice, analyst, listener, admin, manager)• Validation ensures listener role is onlv assianable if the LISTENER ROLE feature flaa is enabled• Listener role cannot be combined with admin or manager permissions• Uses existing UpdateUserRolesAction for role syncing and logging• Follows platform validation rules (DependentRolesRule, ListenerRoleRequiresListenerFeatureRule)Next Step: Please contact Mario to update the customer that SCIM role management is now available for Teamtailorintearationposwtn chaten vapp/Component/SClM/ Constants.php +3app/Component/SCIM/ ® ScimProvisioning.php +85-15nse/ CoreUser.php +21ann/Comnonent/SCIM/Mutatore/Attributes/Ueer/M PoleAttr.nhn +17-tes/Userl ẞ RoleAttrTest ohn +224* Reiect allAccent alliAsk anvthina 884-L)« Code SWF-1.6WN Windsurf Toams 1-1UTF.8io 4 spaces...
|
53357
|
NULL
|
NULL
|
NULL
|
|
53103
|
1861
|
11
|
2026-05-18T11:38:35.278028+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779104315278_m2.jpg...
|
PhpStorm
|
faVsco.js – CoreUser.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings...
|
[{"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":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>114 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"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}]...
|
-4235983745889776938
|
-8204421443435123770
|
idle
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
PhostormVIewINavicarecodeLaravelKeractorFV faVsco.js°9 master k >roledeyC ActivityController.ongC BaseService.php© SoftPhoneManager.php© SendNudgeExpirationWarningsCommanc(C) CoreUserRequest.onpscimProvistoning.ong© CoreUser.php X© SyncActivity.php© Tracklmported.phpclass loreuser excenas kesponsewhichworkerisworkingOnwnichJoo.ong> C Scheduling(C) Kernel.phppubuic carbon supadtea.ae,public string $externalId;> 0 Contracts• Domainpublic string $phoneNumberPrimary:v DDTOActivitypublic string $phoneNumberSecondary:a customerAopubuic suring sclcler1 Externa ServicelntedrationspubLic scring $107 imoortCallipubuic array sroles"InvitationRolespublic function createFromUser(User Suser): self{...}M SCIMV AAD106 6t>public function createResponse@: arrav....v MRequast© CoreGroupRequest.phppublic function getintleo: strino...(c) CoreUserRequest.one© GetGroupByQuery.phppublic function setiitle(string stitle): CoreUsert...,© GetUserByQuery.php© PatchGroup.php1 usaae© PatchUser.phpprivate function getPhoneNumbersArrayO: arrayt...,vm Docnancog coreGroup.onpcoreuser.onoprivate function getEmailsArrayO: arrayt...eError.php© ListResponse.php* 1of Aedite J,Accept File ** X Reject File 02€+ AofAfiloc →A Doauoct nhnlLocal ChangesShelLOg x• Chandes & tlles= env.local apo→ E Side-by-side viewer@cb4ebf0c config/logging.php@ Constants.php app/Component/SCIM(C) CoreUser.oho aoo/DTO/SCIMIAAD/ResoonseIdnivent =slennonloa!@ CoreUserRequest.pho app/DTO/SCIMIAAD/Request'level' => env('LOG _LEVEL', 'info'),(C)JiminnvDebuaCommand.oho apo/Console/Commands'path' => storage_path('logs/Laravel.log').pho logdina.nho confidC) ScimProvisioning.ohnann/comnonent/sclM@) SoftPhoneManager.nhnann/Comnonent/Twilio/Conference/ConferenceManad(C) TeytMessaainaService.nhn ann/Services/TelenhonviUnversioned Files 11 files= env nikilocal annl= .env.other app© CanAccessAiReportsTest.php tests/Unit/Policies(©) CrostoMockAck liminnvDanartDocultCommand.nhnann/Concolo/Commandc/DF0 favicon ico nublidEids.txt appListenerRoleCannotHaveAdminOrManagerPermissionRule.php app/RulesTa raw sal query.sal app@DoloAtrnhn snnlfamnanont/CAIlA/Mutotoro/Atributoo/lloorWorkcnace accociated with hranch 'macter' hac heon rectored Il Pollback II Confiaure (18 minutec aao)Accept Renectsupoont Dally • In z4m100% 2• Mon 18 May 14:38:34AskJiminnyReportActivityServiceTest vFixing Redis Rate LimSalestorce Token FalliSClM Role Manager+0 ..=custom.log= laravel.log4 SF jiminny@localhost]4 HS_local [jiminny@localhost]A console [STAGING] X554556558565567568570571573Sa32aTx: AutovTe cri CouT LuuraqOnuE TanU UEULaVUUUK LUE WD:select * from teams:SELECT r.* FROM automated_reports rjoin teams t on r.team..id = t.idWHERE r.freguency = 'daily'and r.status = 1AND t.status = 'active'AND (r.expires_at >= now OR r.expires_at IS NULL);select * from automated_report_results where report id IN (18, 33):select * from users where team_id = 1 and id = 1047;SELECT * FROM social_accounts WHERE sociable_id = 1047;|select * from activity searches where id = 10932select * trom activity search tilters where activity search 10 = 10952*select * tromorder by 10 descresults order by id desc;automated reports where 10 IN (55* from automated report results where id IN (81):select * trom users where 1d IN 00055,15787,11985071select * trom users where qroup 10 In (5/0):SELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;SELECT * FROMIautomated_report_results WHERE uuid_to_bin( 582d4b50-8cd3-42a9-9819-d676ff8f3b43) = uuid;select * from teams:& console [PROD]& console [EU]CascadeImplement Trial OwneGo jiminny_jupiter019 A19 V17 ^ V• CoreUser.phpThoughts• CoreUser.phpInougnt tor 1s>• CoreUser.php• CoreUser.pheThouaht for 1s )8 10 tasks done• Uodate CoreUser response to include roles© Write unit tests for SCIM role managementThaucht for 1c• ListenerRoleCannotHaveAdminOrManAsk anvthina (%4L)+ @code SWE-1.6Reject allAccept all1ditterenceCurrent vercion'driver' => 'errorlog','level' => env('LOG_LEVEL', 'info'),'path' => storage_path('logs/Laravel.log').'custom channel' => ['driver' => 'single','path' => storage_path('loqs/custom.l0g')'level' => env('LOG LEVEL', 'info').W Windsurf Teams 74:1 UTF-8 P 4 spaces...
|
53101
|
NULL
|
NULL
|
NULL
|
|
53102
|
1860
|
9
|
2026-05-18T11:38:30.735998+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779104310735_m1.jpg...
|
PhpStorm
|
faVsco.js – CoreUser.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings...
|
[{"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":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>114 incoming commits<br/>","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":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","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}]...
|
-4235983745889776938
|
-8204421443435123770
|
idle
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
SlackFileEditViewGoHistoryWindowHelpEU (IDOCKER81DEV (docker)₴2DOCKER (docker-compose)"pid":7, "message":"[ConnectionError]: getaddrinfo ENOTFOUND elasticseelasticsearch:9200"}{"type" : "log""@timestamp": "2026-05-18T11:38:22Z", "tags" : ["warning", "elasticsearch", "data"],"pid" :7,"message": "Unable to revive connection: [URL_WITH_CREDENTIALS] "tags" : ["warning"asticsearch", "data"], "pid" :7,"message" : "No livingconnections"}1 {"type": "log""@timestamp": "2026-05-18T11:38:22Z""tags": ["error", "taskManager", "taskManager"], "pid":7, "message":"Failed to pollfor work: Error: NoLiving connections"}docker_lamp_16s DONEdocker_lamp_1'telus'1 '/usr/local/bin/php' 'artisan'activity:sync 'ringcentral' 'avaya''talkdesk'--from='2026-05-18 11:21:00'--to='2026-05-18 11:37:00' > */proc/1/fd/1'2>&1docker_lamp_1docker_lamp_1run_artisan_schedule: Done waiting for schedule:runkibana{"type" : "log","@timestamp": "2026-05-18T11:38:24Z", "tags" : ["error", "elasticsearch","data"], "pid" :7,"message" : "[ConnectionError]: getaddrinfo ENOTFOUND elasticseelasticsearch:9200"}1 {"type": "log","@timestamp" : "2026-05-18T11:38:25Z", "tags" : ["warning"asticsearch", "data"], "pid":7, "message" : "Unableto revive connection: [URL_WITH_CREDENTIALS] "tags" : ["warning", "elasticsearch", "data"], "pid" :7, "message": "No living connections"}1 {"type": "log"!"@timestamp": "2026-05-18T11:38:25Z""tags" : ["error","plug, "taskManager","taskManager"], "pid" :7, "message" : "Failed to poll for work: Error: NoLiving connections"}{"type": "log""@timestamp": "2026-05-18T11:38:26Z", "tags" : ["error"ticsearch", "data"], "pid":7, "message" : "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch: 9200"}{"type" :"log""@timestamp": "2026-05-18T11:38:28Z""tags" : ["warning", "elasticsearch", "data"], "pid" :7, "message": "Unable to revive connection: [URL_WITH_CREDENTIALS] "2026-05-18T11:38:28Z", "tags" : ["warning", "elasticsearch", "data"],"pid":7,"message": "No livingconnections"}kibana1 {"type" : "log"!ins","@timestamp": "2026-05-18T11:38:28Z""tags" : ["error","taskManager""taskManager"], "pid":7, "message": "Failed to poll for work: Error: NoLiving connections"}kibana1 {"type": "log", "@timestamp": "2026-05-18T11:38:29Z", "tags" : ["error", "elasticsearch", "data"],"pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}View in Docker Desktop• View ConfigEnable WatchHomeDMsActivityFilesLaterMore→Jiminny ...Metrorrtence# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...0 Direct messages. Nikolay YankovR. Aneliya Angelovaão Stefka Stoyanova. Stoyan Tomov€. Vasil Vasilev% Galya DimitrovaLa Todor Stamatov ". Mario Georgiev. Nikolay IvanovLo James Graham *8 Stoyan TanevR. Steliyan Georgiev&e Petko KashinskiLukas Kovalik y…..AppsJira CloudToastSupport Daily • in 22 m100% <7Describe what you are looking forNikolay YankovMessagesAdd canvas• Add language |TodayCONNECT/SYNC SETTINGSImport Email Conversations'OLet's Get Started:8• Mon 18 May 14:38:306 0O Files+Sign in with Googleне ме пускаNikolay Yankov 2:17 PMЕй сегаГОТОВОLukas Kovalik 2:26 PMоще ведньж и в СФNikolay Yankov 2:27 PMГТОТОВОLukas Kovalik 2:27 PMработи вечеNikolay Yankov 2:27 PMимаше ли нещо за фиксLukas Kovalik 2:28 PMтрябва да си вързан към SF да работиNikolay Yankov 2:28 PMaxaaaMessage Nikolay Yankov...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
53101
|
1861
|
10
|
2026-05-18T11:38:03.142479+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779104283142_m2.jpg...
|
PhpStorm
|
faVsco.js – CoreUser.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormVIewINavicarecodeLaravelKeractorWindowFV f PhostormVIewINavicarecodeLaravelKeractorWindowFV faVsco.js°9 master k >ProiectC ActivityController.ongC BaseService.php© SoftPhoneManager.php© PhoneNumberSecondaryAttr.ph© PrimaryEmailAttr.php© RoleAttr.php© SecondaryEmailAttr.phpC CoreUserRequest.phpsclmrrovistonine.on.© CoreUser.php X© TitleAttr.phppublic string $phoneNumberPrimary:c usernameAuur.ono© GroupMutator.phppublic string $phoneNumberSecondary:C UserMutator.phpc) GroupPatchOperation.phppublic string $title;C) UserPatchOperation.phpc) constants.ohppublic string $id;Scimintertace.ohpc) ScimProvisionina.onopublic array Sroles:SeedenD Sentry17 Serializenpublic function createFromUser(User Suser): self{...}• SettingsN SidekickiM Slacknubuic tunction createresoonse@: arrav...."M TeaminsiahtsTimeMemoryMapperTranscrintionpublic function cetintleo: strino....-D TranscriptionSummaryM Twiliolv MConferencopublic function setintle strina Stitle): Corelsen-...• M conferenceHandler• MconferenceManager8) SoftPhoneManager.phgprivate function getPhoneNumbersArrayO: arrayt...,ConferenceCallbackHandler.onp1611 editAccept File & X Reject File 0%€+ 6 of 6 files →@ conferenceManager.phpLocal ChangesConsole XL0g x• Chandes & tlles→ E Side-by-side viewer= env.local apo@cb4ebf0c config/logging.php@ Constants.php app/Component/SCIM(C) CoreUser.oho aoo/DTO/SCIMIAAD/Resoonse@ CoreUserRequest.ohp app/DTO/SCIMIAAD/RequestIdnivent =s(C)JiminnvDebuaCommand.oho apo/Console/Commands'level' => env('LOG _LEVEL', 'info'),'path' => storage_path('logs/Laravel.log').pho logdina.nho confidC) ScimProvisioning.ohnann/comnonent/sclMФ) SoftPhoneManager.pho app/Component/Twilio/Conference/ConferenceManag ]:(C) TeytMessaainaService.nhn ann/Services/TelenhonviUnversioned Files 11 files= env nikilocal annl= onv othor ann© CanAccessAiReportsTest.php tests/Unit/Policies(©) CrostoMockAck liminnvDanartDocultCommand.nhnann/Concolo/Commandc/DF0 favicon ico nublid=ids.txt appListenerRoleCannotHaveAdminOrManagerPermissionRule.php app/RulesTa raw sal query.sal app@DoloAtrnhn onnlfamnanont/CAIlA/Mutotoro/Atributoo/lloorWorkcnace accociated with hranch 'macter' hac heon rectored Il Pollback II Confiaure (18 minutec aao)supoont Dally • In z4m100% 2• Mon 18 May 14:38:02U AskJiminnyReportActivityServiceTest vFixing Redis Rate LimSalestorce Token FalliSClM Role Manager+0 ..Aссeрс кепесс=custom.log= laravel.log« SF jiminny@localhost]4 HS_local [jiminny@localhost]& console [PROD]& console [EU]A console [STAGING] X556558562563565567568577579Tx: Auto vGo jiminny_jupiterTe cri CouT LuuraqOnuE TanU UE ULaVUUUK LUE 1D:019 A19 V17 ^ Vselect * from teams:SELECT r.* FROM automated_reports rjoin teams t on r.team..id = t.idWHERE r.freguency = 'daily'and r.status = 1AND t.status = 'active'AND (r.expires_at >= now OR r.expires_at IS NULL);select * from automated_report_results where report id IN (18, 33):select * from users where team_id = 1 and id = 1047:SELECT * FROM social_accounts WHERE sociable_id = 1047;select * from activity searches where id = 10932select * trom activity search tilters where activity search 10 = 10952*select * tromorder by 10 descresults order by id desc;automated reports where 10 IN (55select * from automated report results where id IN (81):select * trom users where 1d IN 00055,15787,11985071select * trom users where qroup 10 IN (5/00:SELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;SELECT * FROMIautomated_report_results WHERE uuid_to_bin( 582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;select * from teams:CascadeImplement Trial Owne" RoleAttr.ohotnougnis• RoleAttr.phpScimProvisioning.phpThoughts• ScimProvisioning.php7110 tacke done6 more• Add validation for SCIM role ascianment (listener + admin/manader rectriction)• Update CoreUser response to include rolesInoughts• CoreUser.phpAsk anvthina (%4L)+ @code SWE-1.6Reject allAccept all1ditterenceCurrent vercion'driver' => 'errorlog','level' => env('LOG_LEVEL', 'info'),'path' => storage_path('logs/Laravel.log').'custom channel' => ['driver' => 'single','path' => storage_path('loqs/custom.l0g')'level' => env('LOG LEVEL', 'info').W Windsurf Teams 74:1 UTF-8 P 4 spaces...
|
NULL
|
-6520636623520542305
|
NULL
|
visual_change
|
ocr
|
NULL
|
PhostormVIewINavicarecodeLaravelKeractorWindowFV f PhostormVIewINavicarecodeLaravelKeractorWindowFV faVsco.js°9 master k >ProiectC ActivityController.ongC BaseService.php© SoftPhoneManager.php© PhoneNumberSecondaryAttr.ph© PrimaryEmailAttr.php© RoleAttr.php© SecondaryEmailAttr.phpC CoreUserRequest.phpsclmrrovistonine.on.© CoreUser.php X© TitleAttr.phppublic string $phoneNumberPrimary:c usernameAuur.ono© GroupMutator.phppublic string $phoneNumberSecondary:C UserMutator.phpc) GroupPatchOperation.phppublic string $title;C) UserPatchOperation.phpc) constants.ohppublic string $id;Scimintertace.ohpc) ScimProvisionina.onopublic array Sroles:SeedenD Sentry17 Serializenpublic function createFromUser(User Suser): self{...}• SettingsN SidekickiM Slacknubuic tunction createresoonse@: arrav...."M TeaminsiahtsTimeMemoryMapperTranscrintionpublic function cetintleo: strino....-D TranscriptionSummaryM Twiliolv MConferencopublic function setintle strina Stitle): Corelsen-...• M conferenceHandler• MconferenceManager8) SoftPhoneManager.phgprivate function getPhoneNumbersArrayO: arrayt...,ConferenceCallbackHandler.onp1611 editAccept File & X Reject File 0%€+ 6 of 6 files →@ conferenceManager.phpLocal ChangesConsole XL0g x• Chandes & tlles→ E Side-by-side viewer= env.local apo@cb4ebf0c config/logging.php@ Constants.php app/Component/SCIM(C) CoreUser.oho aoo/DTO/SCIMIAAD/Resoonse@ CoreUserRequest.ohp app/DTO/SCIMIAAD/RequestIdnivent =s(C)JiminnvDebuaCommand.oho apo/Console/Commands'level' => env('LOG _LEVEL', 'info'),'path' => storage_path('logs/Laravel.log').pho logdina.nho confidC) ScimProvisioning.ohnann/comnonent/sclMФ) SoftPhoneManager.pho app/Component/Twilio/Conference/ConferenceManag ]:(C) TeytMessaainaService.nhn ann/Services/TelenhonviUnversioned Files 11 files= env nikilocal annl= onv othor ann© CanAccessAiReportsTest.php tests/Unit/Policies(©) CrostoMockAck liminnvDanartDocultCommand.nhnann/Concolo/Commandc/DF0 favicon ico nublid=ids.txt appListenerRoleCannotHaveAdminOrManagerPermissionRule.php app/RulesTa raw sal query.sal app@DoloAtrnhn onnlfamnanont/CAIlA/Mutotoro/Atributoo/lloorWorkcnace accociated with hranch 'macter' hac heon rectored Il Pollback II Confiaure (18 minutec aao)supoont Dally • In z4m100% 2• Mon 18 May 14:38:02U AskJiminnyReportActivityServiceTest vFixing Redis Rate LimSalestorce Token FalliSClM Role Manager+0 ..Aссeрс кепесс=custom.log= laravel.log« SF jiminny@localhost]4 HS_local [jiminny@localhost]& console [PROD]& console [EU]A console [STAGING] X556558562563565567568577579Tx: Auto vGo jiminny_jupiterTe cri CouT LuuraqOnuE TanU UE ULaVUUUK LUE 1D:019 A19 V17 ^ Vselect * from teams:SELECT r.* FROM automated_reports rjoin teams t on r.team..id = t.idWHERE r.freguency = 'daily'and r.status = 1AND t.status = 'active'AND (r.expires_at >= now OR r.expires_at IS NULL);select * from automated_report_results where report id IN (18, 33):select * from users where team_id = 1 and id = 1047:SELECT * FROM social_accounts WHERE sociable_id = 1047;select * from activity searches where id = 10932select * trom activity search tilters where activity search 10 = 10952*select * tromorder by 10 descresults order by id desc;automated reports where 10 IN (55select * from automated report results where id IN (81):select * trom users where 1d IN 00055,15787,11985071select * trom users where qroup 10 IN (5/00:SELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;SELECT * FROMIautomated_report_results WHERE uuid_to_bin( 582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;select * from teams:CascadeImplement Trial Owne" RoleAttr.ohotnougnis• RoleAttr.phpScimProvisioning.phpThoughts• ScimProvisioning.php7110 tacke done6 more• Add validation for SCIM role ascianment (listener + admin/manader rectriction)• Update CoreUser response to include rolesInoughts• CoreUser.phpAsk anvthina (%4L)+ @code SWE-1.6Reject allAccept all1ditterenceCurrent vercion'driver' => 'errorlog','level' => env('LOG_LEVEL', 'info'),'path' => storage_path('logs/Laravel.log').'custom channel' => ['driver' => 'single','path' => storage_path('loqs/custom.l0g')'level' => env('LOG LEVEL', 'info').W Windsurf Teams 74:1 UTF-8 P 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
45491
|
1628
|
21
|
2026-05-14T14:39:50.649366+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769590649_m2.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
ActivityFilesLaterJiminny... ~@ jiminny-x-integrat ActivityFilesLaterJiminny... ~@ jiminny-x-integrati& platform-inner-team© Channels# ai-chapter# alertsi backend# bugscontusion-cllnia# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the people of iimi..• Direct messages8. A...• A3 62P. Galya Dimitrova Mvasil Vasilevf. Stefka Stoyanova%: Todor Stamatovf. Mario GeorgievP. Nikolay Ivanov2o James Graham "2. Stoyan Tanev. Steliyan Georgiev. Petko Kashinski*. Lukas Kovali...a: Apps® ToastS lira Gloud6 Huddle with Aneliya Angelova& R. Aneliya Angelova •• Messagest Add canvasur FilesAneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук,нали?пои останалите скМі тоябва оъчно ла се въвелат.Lukas Kovalik 2:47 PMтряова да се за всички, някьде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova @ 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725X Preview insackt[HubSpot] Optimise CRM rematctC OpenReady for QA- MediumAA Aneliya AngelovaAs of today at 4:00 PM RetreshOpen in Jira+ SummariseLukas Kovalik 4:02 PMzean-iurwiniareelYou joined the huddle LIVE 4:06 PMAneliva Angelova is here toolAneliya Angelova 4:44 PM11512582Lukas Kovalik O 5:16 PMcurl --location "httns:ani.hubani.com/crm/v3/obiects/contacts/search--header 'Content-Type: application/json'\--header "Authorization: BearerC|Kvma?iMx7OINOM8kOFwrAowAcAkUAhIR24?A05D?xiVrIYMILuP6SA01Kwcmhr=n.v2 hytorDniMvDalYck-CMalovolNOM9kOFwrAUAcrkcaws-ThwRARIRAOF-ATFSAOFRAO-ROIEBAQUBEggBAQEBAYICFIґ7Au8O2Nwal9YW2CbCCxYvwngmSgNldTFSAFoAYABoAHAAeAA'\--data "{ "limit", 13'Message Aneliva Angelova+ AaIđ 0Pm~ (Q SearchDate ModifiedYesterday at 13.3Yesterday at 13:36Yesterday at 13:36Yesterday at 13.30Yesterday at 13:35Yesterday at 13:34Yesterday at 13:34Yesterdav at 13:3kYesterday at 13:33Yesterday at 13.32Yesterday at 13:31resterday at 15:30Yesterdav at 13:30Yesterday at 13:29Yesterday at 13:29Yesterday at 13:28Yesterday at 13:28resterday at 13-21Yesterdav at 13:26Yesterday at 13:26Yesterday at 13:25Yesterday at 13:25Yesterday at 13:24Yesterday at 13.23Yesterdav at 13:22resterady al 15.clYesterday at 13:20Yesterday at 13.19Yecterdav at 12:19Yesterday at 13:18Yesterday at 13-1/Yesterdav at 13:17Yesterday at 13:16Yesterday at 13:15Yecterdav at 12:15Yesterday at 13.14Yecterdav at 13:10Yesterday at 13:13Yesterday at 13:12Yesterday at 13:11Yesterday at 13.10Yecterdav at 12:10Yesterday at 13:09Yesterdav at 13:08v SizeMPEG-4 movie23 KBMPEG-4 movie9 KB13 Kb16 KEMPEG-4 movieMPEG-4 movie17 KB29 KBMPE0"4 movie16 K:12 KBMPEG-4 movie9 KBIKBnMP2G-4 movie8 KBMPEG-4 movie37 KB10 KBMPEG"4 movie7 KEMPEG-4 movie8 KBMPEG-4 movie9 KB8 KB1MPEG-4 movie72 KBMPEG-4 movie14 KB13 KBMPEG-4 movie9 KEMPEG-4 movie18 KBMPEG-4 movie12 KB10 KBIMPEG-4 movie16 KBMPEG-4 movie6 KB6KBMPEG-4 movie12 KEMPEG-4 movie23 KBMPEG-4 movie8 KBMPEG-4 movie16 K:6 KBMPEG-4 movie11 KBMPEG-4 movie20 KPMPEG-4 movie34 KBMPEG-4 movie10 KB7 K:MPEG-4 movie5 KBMPEG-4 movie11 KB26 KB111 KCMPEG-4 movieMDEG-A movia102 KB88 KBMPEG-4 movie59 KB1MPEG-A movie98 KB MPEG-4 movie97 KB66 K3AAKPMPEG-4 movieMPEG-4 movie93 KB/8 KBMPEG-4 movie50 KгMDEG-A movid58 KBMPEG-4 movie27 KB7KBMPEG-4 movieAl Notes: OffLeave• 0FavouritesE jiminny© Recents* ApplicationsiCloudiCloud Drive228 Sync folderQ DXP4800PLUS-B5FA@ Network|• CRMI• Orange• Red• Yellow• Green• Purple•) All lags..lohlDownloadsNameLoom.pkgAlfred copv.alfredoreterencesB KeychronAssist-1.0.2 (1).dmgA Keychron Assist-1.0.2.dmgmazanoke-images-ywJo.ziPhotos-3-001.zipD Transcript.pdf→mage U.loge1 Orioninstaller.dmaimage.jpg- image (2).1pc• ПО-22221726037035-004-001_ORGES.pdf• %D0%9F%D0%9E-22221726037035-004-001_archive.zipПO-22221726037035-004-001_archive (1).zip• repon 4).XmAltred copy2.altredoreterences05012026_0000000026574472_ SWIFT_OB70501260015890.pdf27022026_0000000026574472_SWIFT_OB72702260049200.pdf= 03042026 [CREDIT_CARD] SWIFT [CREDIT_CARD].001B reporti) xm=pdt.odipdf-1.pdfD pdf-2.pdf-pdf-5.pd1= ndf-1 ndipdf-3.pdfKoválik Family Tree.gedbitwarden export 20251031122528.isonKoválik Family Tree.zip*macOS Storage_Cleanup.mdal favicon icofirst_aid_notes_complete.docxrenortl2).esvconfig.ymlIteration run Search HS.postman_collection.jsonm licence bettertouchtoalMariusHosting Config.json1ooks-891a6503-bbb7-4b2b-9c3.csv•Alfredmazanoke-images-YWJ6ана Ковалик.jpg•искане даниел Ковалик..pg• Фактура Март Даниел Ковалик.jрс• Фактура Април Даниел Ковалик.jpg• Dhotac 2.001Q SearchKind00,4 MDinstdlle..dckage55.9 MBAlfred...ferences10,1 MBDisk Image10,1 MBDisk ImageIL MBLiP archive6,6 MBZIP archive2,5 MB PDF Document2,5 MBJreo lmage2.2 MBDisk Image2,2 MB PDF Document2 MBJPEG image1,9 MBJPEG imaqe192 KBPDF Document140 KbZIP archive148 KВZIP archivel148 KBZIP archive122 KBXML document111 KBAlfred...ferences94 KBPDF Document92 KBPDr DocumentK:91 KB91 KB30 KB29 KBPDF DocumentXML documentPDF Document28 KBPDF Document28 KR28 KB27 KB14 KB11 KB6 KB6KBPDE DocumentDocumentJSONICSV DocumentZIP archiveMarkdo…..ument5KRWindo...n image4 KB3 KBword ..cumentCSV Document2 KBYAML document1 KBcSV Document928 byteshttlicence183 bytesZero butesJSONAlfred.. ferencesZero bytesFolde1,9 MB1,8 MB17 MB1,7 MBColdorJPEG imageJPEG ImageIPEG imadeJPEG imageColdo1 of 58 selected, 8.43 GB availabld• Inu 14 May 1/.39:00Date AddedIs Mdl ZUzo dl 19:4530 Jan 2026 at 12:3617 Mar 2026 at 20:2717 Mar 2026 at 20:26Z3 Aor 2020 al 13:0229 Jan 2026 at 15:2019 Dec 2025 at 10:1619 Dec 2025 at 12:238 Aor 2026 at 20:3519 Dec 2025 at 10:2919 Dec 2025 at 12:1819 Dec 2025 at 12:4026 Mar 2026 at 11:2410 May 2026 at 13:5326 Mar 2026 at 11:2426 Mar 2026 at 11:2426 Mar 2026 at 11:2310 May 2026 at 14:3730 Jan 2026 at 12:3713 Feb 2026 at 11:54Z3 Apr 2026 at 13.0823 Aor 2026 at 13:0810 May 2026 at 13:5410 May 2026 at 14:3710 May 2026 at 13:4910 May 2026 at 13:5010 May 2026 at 13:5110 Mav 2026 at 12:51110 May 2026 at 13:5019 Dec 2025 at 11:3431 Oct 2025 at 12:2525 Nov 2025 at 17:596 Mar 2026 at 11.2224 Anr 2026 at 16:5220 Oct 2025 at 11:0218 Mar 2026 at 15:29• Mav 2026 at 11:09129 Oct 2025 at 19:329 May 2026 at 10:0418 Mar 2026 at 11:5510 May 2026 at 13:5712 Jun 2025 at 19:0430 Jan 2026 at 12:3630 Jan 2026 at 12:3616 Oct 2025 aт 16:0123 Apr 2026 at 13:0223 Apr 2026 at 13:0223 Apr 2026 at 13:0222 Anr 2026 at 12:0223 Apr 2026 at 13:0229 Jan 2026 at 15:20...
|
NULL
|
-1000071101893616046
|
NULL
|
click
|
ocr
|
NULL
|
ActivityFilesLaterJiminny... ~@ jiminny-x-integrat ActivityFilesLaterJiminny... ~@ jiminny-x-integrati& platform-inner-team© Channels# ai-chapter# alertsi backend# bugscontusion-cllnia# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the people of iimi..• Direct messages8. A...• A3 62P. Galya Dimitrova Mvasil Vasilevf. Stefka Stoyanova%: Todor Stamatovf. Mario GeorgievP. Nikolay Ivanov2o James Graham "2. Stoyan Tanev. Steliyan Georgiev. Petko Kashinski*. Lukas Kovali...a: Apps® ToastS lira Gloud6 Huddle with Aneliya Angelova& R. Aneliya Angelova •• Messagest Add canvasur FilesAneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук,нали?пои останалите скМі тоябва оъчно ла се въвелат.Lukas Kovalik 2:47 PMтряова да се за всички, някьде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova @ 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725X Preview insackt[HubSpot] Optimise CRM rematctC OpenReady for QA- MediumAA Aneliya AngelovaAs of today at 4:00 PM RetreshOpen in Jira+ SummariseLukas Kovalik 4:02 PMzean-iurwiniareelYou joined the huddle LIVE 4:06 PMAneliva Angelova is here toolAneliya Angelova 4:44 PM11512582Lukas Kovalik O 5:16 PMcurl --location "httns:ani.hubani.com/crm/v3/obiects/contacts/search--header 'Content-Type: application/json'\--header "Authorization: BearerC|Kvma?iMx7OINOM8kOFwrAowAcAkUAhIR24?A05D?xiVrIYMILuP6SA01Kwcmhr=n.v2 hytorDniMvDalYck-CMalovolNOM9kOFwrAUAcrkcaws-ThwRARIRAOF-ATFSAOFRAO-ROIEBAQUBEggBAQEBAYICFIґ7Au8O2Nwal9YW2CbCCxYvwngmSgNldTFSAFoAYABoAHAAeAA'\--data "{ "limit", 13'Message Aneliva Angelova+ AaIđ 0Pm~ (Q SearchDate ModifiedYesterday at 13.3Yesterday at 13:36Yesterday at 13:36Yesterday at 13.30Yesterday at 13:35Yesterday at 13:34Yesterday at 13:34Yesterdav at 13:3kYesterday at 13:33Yesterday at 13.32Yesterday at 13:31resterday at 15:30Yesterdav at 13:30Yesterday at 13:29Yesterday at 13:29Yesterday at 13:28Yesterday at 13:28resterday at 13-21Yesterdav at 13:26Yesterday at 13:26Yesterday at 13:25Yesterday at 13:25Yesterday at 13:24Yesterday at 13.23Yesterdav at 13:22resterady al 15.clYesterday at 13:20Yesterday at 13.19Yecterdav at 12:19Yesterday at 13:18Yesterday at 13-1/Yesterdav at 13:17Yesterday at 13:16Yesterday at 13:15Yecterdav at 12:15Yesterday at 13.14Yecterdav at 13:10Yesterday at 13:13Yesterday at 13:12Yesterday at 13:11Yesterday at 13.10Yecterdav at 12:10Yesterday at 13:09Yesterdav at 13:08v SizeMPEG-4 movie23 KBMPEG-4 movie9 KB13 Kb16 KEMPEG-4 movieMPEG-4 movie17 KB29 KBMPE0"4 movie16 K:12 KBMPEG-4 movie9 KBIKBnMP2G-4 movie8 KBMPEG-4 movie37 KB10 KBMPEG"4 movie7 KEMPEG-4 movie8 KBMPEG-4 movie9 KB8 KB1MPEG-4 movie72 KBMPEG-4 movie14 KB13 KBMPEG-4 movie9 KEMPEG-4 movie18 KBMPEG-4 movie12 KB10 KBIMPEG-4 movie16 KBMPEG-4 movie6 KB6KBMPEG-4 movie12 KEMPEG-4 movie23 KBMPEG-4 movie8 KBMPEG-4 movie16 K:6 KBMPEG-4 movie11 KBMPEG-4 movie20 KPMPEG-4 movie34 KBMPEG-4 movie10 KB7 K:MPEG-4 movie5 KBMPEG-4 movie11 KB26 KB111 KCMPEG-4 movieMDEG-A movia102 KB88 KBMPEG-4 movie59 KB1MPEG-A movie98 KB MPEG-4 movie97 KB66 K3AAKPMPEG-4 movieMPEG-4 movie93 KB/8 KBMPEG-4 movie50 KгMDEG-A movid58 KBMPEG-4 movie27 KB7KBMPEG-4 movieAl Notes: OffLeave• 0FavouritesE jiminny© Recents* ApplicationsiCloudiCloud Drive228 Sync folderQ DXP4800PLUS-B5FA@ Network|• CRMI• Orange• Red• Yellow• Green• Purple•) All lags..lohlDownloadsNameLoom.pkgAlfred copv.alfredoreterencesB KeychronAssist-1.0.2 (1).dmgA Keychron Assist-1.0.2.dmgmazanoke-images-ywJo.ziPhotos-3-001.zipD Transcript.pdf→mage U.loge1 Orioninstaller.dmaimage.jpg- image (2).1pc• ПО-22221726037035-004-001_ORGES.pdf• %D0%9F%D0%9E-22221726037035-004-001_archive.zipПO-22221726037035-004-001_archive (1).zip• repon 4).XmAltred copy2.altredoreterences05012026_0000000026574472_ SWIFT_OB70501260015890.pdf27022026_0000000026574472_SWIFT_OB72702260049200.pdf= 03042026 [CREDIT_CARD] SWIFT [CREDIT_CARD].001B reporti) xm=pdt.odipdf-1.pdfD pdf-2.pdf-pdf-5.pd1= ndf-1 ndipdf-3.pdfKoválik Family Tree.gedbitwarden export 20251031122528.isonKoválik Family Tree.zip*macOS Storage_Cleanup.mdal favicon icofirst_aid_notes_complete.docxrenortl2).esvconfig.ymlIteration run Search HS.postman_collection.jsonm licence bettertouchtoalMariusHosting Config.json1ooks-891a6503-bbb7-4b2b-9c3.csv•Alfredmazanoke-images-YWJ6ана Ковалик.jpg•искане даниел Ковалик..pg• Фактура Март Даниел Ковалик.jрс• Фактура Април Даниел Ковалик.jpg• Dhotac 2.001Q SearchKind00,4 MDinstdlle..dckage55.9 MBAlfred...ferences10,1 MBDisk Image10,1 MBDisk ImageIL MBLiP archive6,6 MBZIP archive2,5 MB PDF Document2,5 MBJreo lmage2.2 MBDisk Image2,2 MB PDF Document2 MBJPEG image1,9 MBJPEG imaqe192 KBPDF Document140 KbZIP archive148 KВZIP archivel148 KBZIP archive122 KBXML document111 KBAlfred...ferences94 KBPDF Document92 KBPDr DocumentK:91 KB91 KB30 KB29 KBPDF DocumentXML documentPDF Document28 KBPDF Document28 KR28 KB27 KB14 KB11 KB6 KB6KBPDE DocumentDocumentJSONICSV DocumentZIP archiveMarkdo…..ument5KRWindo...n image4 KB3 KBword ..cumentCSV Document2 KBYAML document1 KBcSV Document928 byteshttlicence183 bytesZero butesJSONAlfred.. ferencesZero bytesFolde1,9 MB1,8 MB17 MB1,7 MBColdorJPEG imageJPEG ImageIPEG imadeJPEG imageColdo1 of 58 selected, 8.43 GB availabld• Inu 14 May 1/.39:00Date AddedIs Mdl ZUzo dl 19:4530 Jan 2026 at 12:3617 Mar 2026 at 20:2717 Mar 2026 at 20:26Z3 Aor 2020 al 13:0229 Jan 2026 at 15:2019 Dec 2025 at 10:1619 Dec 2025 at 12:238 Aor 2026 at 20:3519 Dec 2025 at 10:2919 Dec 2025 at 12:1819 Dec 2025 at 12:4026 Mar 2026 at 11:2410 May 2026 at 13:5326 Mar 2026 at 11:2426 Mar 2026 at 11:2426 Mar 2026 at 11:2310 May 2026 at 14:3730 Jan 2026 at 12:3713 Feb 2026 at 11:54Z3 Apr 2026 at 13.0823 Aor 2026 at 13:0810 May 2026 at 13:5410 May 2026 at 14:3710 May 2026 at 13:4910 May 2026 at 13:5010 May 2026 at 13:5110 Mav 2026 at 12:51110 May 2026 at 13:5019 Dec 2025 at 11:3431 Oct 2025 at 12:2525 Nov 2025 at 17:596 Mar 2026 at 11.2224 Anr 2026 at 16:5220 Oct 2025 at 11:0218 Mar 2026 at 15:29• Mav 2026 at 11:09129 Oct 2025 at 19:329 May 2026 at 10:0418 Mar 2026 at 11:5510 May 2026 at 13:5712 Jun 2025 at 19:0430 Jan 2026 at 12:3630 Jan 2026 at 12:3616 Oct 2025 aт 16:0123 Apr 2026 at 13:0223 Apr 2026 at 13:0223 Apr 2026 at 13:0222 Anr 2026 at 12:0223 Apr 2026 at 13:0229 Jan 2026 at 15:20...
|
45489
|
NULL
|
NULL
|
NULL
|
|
45377
|
1625
|
26
|
2026-05-14T14:33:28.043331+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769208043_m1.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
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,"bounds":{"left":0.054166667,"top":0.027777778,"width":0.08055556,"height":0.035555556},"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":"#12066 on JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.13472222,"top":0.027777778,"width":0.25555557,"height":0.035555556},"on_screen":true,"help_text":"Pull request #12066 exists for current branch JY-20725-handle-HS-search-rate-limit, but local branch is out of sync with remote","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.6326389,"top":0.027777778,"width":0.023611112,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.6645833,"top":0.027777778,"width":0.15902779,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.82361114,"top":0.027777778,"width":0.023611112,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.8472222,"top":0.027777778,"width":0.023611112,"height":0.035555556},"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.87083334,"top":0.027777778,"width":0.023611112,"height":0.035555556},"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.9291667,"top":0.027777778,"width":0.023611112,"height":0.035555556},"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.9527778,"top":0.027777778,"width":0.023611112,"height":0.035555556},"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.9763889,"top":0.027777778,"width":0.023611112,"height":0.035555556},"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}]...
|
6814957943380363182
|
-8708761519200826421
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
PhpStormFileEditViewNavigateCodeLaravelRefactorRunToolsGitWindowHelp•FV faVsco.jsv* #12066 on JY-20725-handle-HS-search-rate-limit K vabl19HandleHubspotRateLimitTest100% C8• Thu 14 May 17:33:27* :QProjectv=custom.logAutomatedReportGenerated.phpTrackAutomatedReportGeneratedEvent.phpPlaybackController.php© FieldDefinitions.phpUserAutomatedReportsController.phpPlanhatService.phpAutomatedReportResult.phpSendReportJob.php© FieldValueConverter.php• DeleteCrmEntityTrait.phpDeleteAccountJob.php© ImportActivityTypes.phpT WriteCrmTrait.php© Service.php© DecorateActivity.php> D CrmObjects© Salesforce/Service.php© LogActivityTrait.php© Pipedrive/Service.php© Close/Service.phpCopper/Service.php X• DecorateActivity© PlainTextDecorateActivity.phpT ActivityPlaybookTrait.php© CrmHelperRepository.php© AccountController.php18© BaseDecorateActivity.php© PlainTextDecorateActivity.plE.env© DetachActivityObject.php> D Dummyv HelpersT ActivityPlaybookTrait.php521612© Arraylterator.phpT IntegrationAppTrait.php=.env.staging© MatchActivityCrmData.php© Client.php© HubspotPaginationService.phpclass Service extends BaseService implementspublic functionsaveActivity(Activity $activity): ActivityRematchActivityOnCrmObjectDetach.php© HandleHubspotRateLimit.php811 472 M1 м4 лT ConnectionStateTrait.php1627© CrmHelperRepository.php1628return Sactivity:© FilterJoinedParticipants.php1629+ OpportunitySyncableFieldsT1630v D Hubspot4 usages• AccountSyncStrategy> OJ Actions |16311652private function convertActivityAssociations(Activity $activity): array{...}• ContactSyncStrategy2 usages> ODTO1653private function convertActivityType(PlaybookCategory $activityType): array› Fields1654› 0 Journal1655• Metadata1656v C OpportunitySyncStrategy1657return ['category' => 'user','id'=> $this->getCrmType($activityType)->value,› D Concerns16581;© HubspotLastModifiedByF 1659}© HubspotLastModifiedCre1660© HubspotLastModifiedCre1661HubspotLastModifiedOpe1662© HubspotLastModifiedSyn1663© HubspotSingleSyncStrate/***/1 usage* @throws CrmException© HubspotSyncStrategyBa: 1664private function buildCallPayload(Activity $activity): Activity© HubspotWebhookBatchS1665-v [ Pagination1666try {© HubspotPaginationServic1667if (Sactivity->crm_provider_id) {A DaninatinnCanfin nhn1668f The activity should be loqged under the existing lask (not Activity)=Workspace associated with branch 'JY-20725-handle-HS-search-rate-limit' has been restored // Rollback // Configure... (today 16:17)W Windsurf Teams=laravel.logSF [jiminny@localhost]A HS_local [jiminny@localho:W4 console [QAI PROD] X4 console [PROD]A console (EU]DGo jiminny084143 ×4 л215•m_layout_id =2162,1661,66799,66217218219=id = 33;220221==222E 223=224id THEN •(own225)=226= 227228- 229I230T231"hubspot';— 232- 233 v= 11512582;=2341653:22UTF-8Ca 4 spaces...
|
45375
|
NULL
|
NULL
|
NULL
|
|
45376
|
1626
|
17
|
2026-05-14T14:33:24.529049+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769204529_m2.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
11
72
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Copper;
use Carbon\Carbon;
use Exception;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Support\Facades\Cache;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\CopperInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Crm\LayoutEntity;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Repositories\UserRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Copper\Api\Client;
use Jiminny\Services\Crm\Copper\Api\ClientFactory;
use Jiminny\Services\Crm\Copper\Exception\RequestFailedException;
use Jiminny\Services\Crm\Helpers\FilterJoinedParticipants;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\Copper\Traits\SearchesCrmEntities;
use Jiminny\Utils\CurrencyFormatter;
use Jiminny\Utils\StringUtil;
class Service extends BaseService implements
CopperInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
RemoteEntityManipulationInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use SearchesCrmEntities;
private const int NOTE_BODY_MAX_LENGTH = 3000000;
private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day
private const array STANDARD_OPPORTUNITY_FIELDS = [
'monetary_value' => [
'label' => 'Value',
'available_on' => Field::OBJECT_OPPORTUNITY,
'type' => Field::TYPE_CURRENCY,
],
'pipeline_stage_id' => [
'label' => 'Stage',
'type' => Field::TYPE_PICKLIST,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
'close_date' => [
'label' => 'Close date',
'type' => Field::TYPE_DATE,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
'win_probability' => [
'label' => 'Win probability',
'type' => Field::TYPE_NUMBER,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
];
private const string UNSUPPORTED_OBJECT_TYPE = 'unsupported';
private const string OPPORTUNITY_STATUS_OPEN = 'Open';
private const string OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE = 'Opportunity import failed';
private const string RESOURCE_UPDATE_FAILED_ERROR_MESSAGE = 'Failed to update resource';
private FieldValueConverter $fieldValueConverter;
private ClientFactory $clientFactory;
private ?Client $copperClient = null;
public function __construct(
ClientFactory $clientFactory,
FieldValueConverter $fieldValueConverter,
private readonly UserRepository $userRepository,
private readonly ProspectPhotoPathService $prospectPhotoPathService,
private readonly CrmEntityRepository $crmEntityRepository
) {
parent::__construct();
$this->clientFactory = $clientFactory;
$this->fieldValueConverter = $fieldValueConverter;
}
public function getDisplayName(): string
{
return 'Copper';
}
/**
* Get the CRM entity repository (used by SearchesCrmEntities trait)
*/
protected function getCrmEntityRepository(): CrmEntityRepository
{
return $this->crmEntityRepository;
}
public function getMinimumApiVersion(): string
{
return Client::MIN_API_VERSION;
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
$owner = $user->team->owner;
return $owner->getSocialAccount(SocialAccount::PROVIDER_COPPER);
}
public function setUser(User $user): void
{
$this->configureSentryScope($user);
$this->team = $user->getTeam();
$this->teamService->setTeam($user->getTeam());
$this->setConfiguration($user->getTeam()->getCrmConfiguration());
// Reset state.
$this->profile = $user->getProfile();
if (! $this->profile instanceof Profile) {
// Try to fetch their profile, maybe it was not yet imported?
$this->profile = $this->getProfile($user);
}
}
public function setConfiguration(Configuration $configuration): void
{
$this->config = $configuration;
$this->copperClient = $this->clientFactory->create($configuration);
if ($this->team === null) {
$this->team = $configuration->getTeam();
}
}
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);
}
private function mapObjectType(string $objectType): string
{
$objectType = strtolower($objectType);
switch ($objectType) {
case Field::OBJECT_TASK:
case Field::OBJECT_OPPORTUNITY:
case Field::OBJECT_LEAD:
$mappedType = $objectType;
break;
case Field::OBJECT_ACCOUNT:
$mappedType = 'company';
break;
case Field::OBJECT_CONTACT:
$mappedType = 'person';
break;
default:
$mappedType = self::UNSUPPORTED_OBJECT_TYPE;
break;
}
return $mappedType;
}
/**
* @param string $crmObject The name of the CRM object. i.e. Opportunity or Contact
*/
protected function getFields(string $crmObject): array
{
$mappedObjectType = $this->mapObjectType($crmObject);
if (! $this->isSupportedObjectType($mappedObjectType)) {
return [];
}
$customFields = $this->copperClient->fields()->all();
$filteredFields = array_filter(
$customFields,
static fn ($field) => in_array($mappedObjectType, $field['available_on'], true)
);
return array_map(
fn (array $property) => [
'name' => $property['id'],
'label' => $property['name'],
'type' => $this->convertFieldType($property['data_type']),
],
$filteredFields
);
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
// Setup the activity field as the default Type.
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'type',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldFilters = FieldDefinitions::taskFollowupFieldsFilter();
foreach ($fieldFilters as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
public function syncFields(): void
{
$this->syncStandardFields();
$this->syncCustomFields();
}
public function syncField(Field $field): void
{
if ($field->getCrmProviderId() === 'type') {
/**
* This field is a special case, it is not a custom field and is not returned by the Copper API.
*
* The field is created manually during layout setup.
*
* @see getDefaultFields()
*
* There is a separate endpoint to get the activity types.
* @see importPicklistValues()
*/
return;
}
if ($field->getCrmProviderId() === 'pipeline_stage_id') {
// Not a custom type
return;
}
$crmField = $this->copperClient->fields()->find($field->getCrmProviderId());
$field->label = $crmField['name'];
$field->type = $this->convertFieldType($crmField['data_type']);
$field->save();
}
/**
* @param string $fieldType How the data should be input
*/
private function convertFieldType(string $fieldType): string
{
$fieldType = strtolower($fieldType);
switch ($fieldType) {
case 'dropdown':
$convertedType = Field::TYPE_PICKLIST;
break;
case 'string':
$convertedType = Field::TYPE_TEXT;
break;
case 'float':
case 'percentage':
$convertedType = Field::TYPE_NUMBER;
break;
case 'text':
$convertedType = Field::TYPE_TEXTAREA;
break;
case 'checkbox':
$convertedType = Field::TYPE_BOOLEAN;
break;
case Field::TYPE_DATE:
case Field::TYPE_CURRENCY:
case Field::TYPE_URL:
$convertedType = $fieldType;
break;
default:
$convertedType = Field::TYPE_UNSUPPORTED;
break;
}
return $convertedType;
}
/**
* @inheritdoc
*/
public function importPicklistValues(Field $field): array
{
$fieldValues = [];
if ($field->object_type === 'opportunity' && $field->crm_provider_id === 'pipeline_stage_id') {
return $this->importFieldValuesForDealInsights($field);
}
$values = [];
if ($field->object_type === Field::OBJECT_TASK && $field->crm_provider_id === 'type') {
$activityTypes = $this->copperClient->activityTypes()->all();
/**
* We ignore "system" activity types, disabled activity types and the "Note" activity type.
*/
$activityTypes = array_filter(
$activityTypes['user'],
fn (array $activityType) => ! $activityType['is_disabled'] && $activityType['id'] !== 0
);
// Import all activity values.
$i = 0;
foreach ($activityTypes as $activityType) {
$values[] = [
'value' => $activityType['id'],
'label' => mb_strimwidth($activityType['name'], 0, Field::LABEL_MAX_LENGTH),
'sequence' => $i++,
];
}
} else {
// We just check for the field in the custom definitions.
$crmField = $this->copperClient->fields()->find($field->crm_provider_id);
// Import all values.
foreach ($crmField['options'] as $option) {
$values[] = [
'value' => $option['id'],
'label' => mb_strimwidth($option['name'], 0, 191),
'sequence' => $option['rank'],
];
}
}
// Take the existing set of field values.
$fieldsToPurge = $field->values()->get()->pluck('value')->toArray();
foreach ($values as $value) {
// For all current values, upsert the field.
$value['value'] = substr($value['value'] ?? '', 0, 255);
$fieldValues[] = $field->values()->updateOrCreate([
'value' => $value['value'],
], $value);
// Remove this value from the ones we are going to purge.
$key = array_search($value['value'], $fieldsToPurge, false);
if ($key !== false) {
unset($fieldsToPurge[$key]);
}
}
// Delete the old values that are no longer used.
$field->values()->whereIn('value', $fieldsToPurge)->delete();
return $fieldValues;
}
/**
*
* @return FieldValue[]
*/
private function importFieldValuesForDealInsights(Field $field): array
{
$fieldValues = [];
$pipelines = $this->copperClient->pipelines()->all();
foreach ($pipelines as $pipeline) {
foreach ($pipeline['stages'] as $i => $dealStage) {
$fieldValues[] = $field->values()->updateOrCreate(
['value' => $dealStage['id']],
[
'label' => $dealStage['name'],
'sequence' => $i,
]
);
}
}
return $fieldValues;
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
if ($types === null) {
$types = [Stage::TYPE_LEAD, Stage::TYPE_OPPORTUNITY];
}
$missingStage = null;
foreach ($types as $type) {
if ($type === Stage::TYPE_LEAD) {
$statuses = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leadStatuses()->all()
);
if (count($statuses) > 0) {
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => BusinessProcess::TYPE_LEAD,
], [
'team_id' => $this->team->id,
'name' => BusinessProcess::TYPE_LEAD,
'type' => BusinessProcess::TYPE_LEAD,
'is_selectable' => true,
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => BusinessProcess::TYPE_LEAD,
], [
'team_id' => $this->team->id,
'name' => BusinessProcess::TYPE_LEAD,
'is_selectable' => true,
'business_process_id' => $businessProcess->id ?? null,
]);
$leadStatuses = [];
foreach ($statuses as $status) {
// Upsert all statuses for the team.
$status = $this->config->stages()->updateOrCreate([
'crm_provider_id' => $status['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($status['name'], 0, 50),
'label' => mb_strimwidth($status['name'], 0, 191),
'type' => Stage::TYPE_LEAD,
'sequence' => $status['order'],
'is_selectable' => true,
]);
if ($missingStageName && $missingStageName === $status['id']) {
$missingStage = $status;
}
$leadStatuses[] = $status['id'];
}
$businessProcess->stages()->sync($leadStatuses);
}
} else {
// We create a business process to contain the pipeline, and later store all stages against it.
foreach ($this->copperClient->pipelines()->all() as $pipeline) {
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $pipeline['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($pipeline['name'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => true,
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $pipeline['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($pipeline['name'], 0, 150),
'is_selectable' => true,
'business_process_id' => $businessProcess->id ?? null,
]);
$stages = [];
foreach ($pipeline['stages'] as $i => $dealStage) {
// Upsert all stages for the team.
$stage = $this->config->stages()->updateOrCreate([
'crm_provider_id' => $dealStage['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($dealStage['name'], 0, 50),
'label' => mb_strimwidth($dealStage['name'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $i,
'is_selectable' => true,
'probability' => $dealStage['win_probability'],
]);
if ($missingStageName && $missingStageName === $dealStage['id']) {
$missingStage = $stage;
}
$stages[] = $stage['id'];
}
$businessProcess->stages()->sync($stages);
}
}
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int
{
$syncCount = 0;
$cpLeads = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->paginate([
'minimum_modified_date' => $since->timestamp,
'sort_by' => 'date_modified',
])
);
foreach ($cpLeads as $cpLead) {
// Only sync if previously imported.
if ($this->hasLead($cpLead['id']) === false) {
$this->importLead($cpLead);
$syncCount++;
}
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncLead(string $crmId): ?Lead
{
$cpLead = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->find($crmId)
);
if (\count($cpLead) === 0) {
return null;
}
return $this->importLead($cpLead);
}
/**
* @inheritdoc
*/
private function importLead($crmData): ?Lead
{
$countryCode = null;
if (! empty($crmData['address']) && isset($crmData['address']['country'])) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$mobilePhone = $parsedNumber = null;
if (! empty($crmData['phone_numbers'])) {
foreach ($crmData['phone_numbers'] as $phoneNumber) {
if ($phoneNumber['category'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);
} else {
$parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);
}
}
}
$name = $crmData['name'];
if (empty($crmData['company_name'])) {
$company = 'Unknown';
} else {
$company = mb_strimwidth($crmData['company_name'], 0, 191);
}
$domain = null;
if (empty($crmData['websites']) === false) {
$domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);
$domain = StringUtil::resolveDomain($domain);
}
$email = null;
if (empty($crmData['email']) === false) {
$email = mb_strimwidth($crmData['email']['email'], 0, 80);
}
$stage = $this->config
->stages()
->where('crm_provider_id', (string) $crmData['status_id'])
->where('type', Stage::TYPE_LEAD)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_LEAD], $crmData['status_id']);
}
if (! $stage instanceof Stage) {
return null;
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($name, 0, 191),
'company' => $company,
'domain' => $domain,
'title' => $crmData['title'] ? mb_strimwidth($crmData['title'], 0, 128) : null,
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'mobile_phone' => $mobilePhone,
'stage_id' => $stage->id,
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Lead::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'country_code' => $countryCode,
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->leads()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
/**
* @inheritdoc
*/
public function syncAccounts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
$cpAccounts = $this->copperClient->accounts()->paginate([
'minimum_modified_date' => $since->timestamp,
'sort_by' => 'date_modified',
]);
foreach ($cpAccounts as $cpAccount) {
// Only sync if previously imported.
if ($this->hasAccount($cpAccount['id'])) {
$this->importAccount($cpAccount);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncAccount(string $crmId): ?Account
{
$cpAccount = $this->copperClient->accounts()->find($crmId);
if (empty($cpAccount)) {
return null;
}
return $this->importAccount($cpAccount);
}
/**
* @inheritdoc
*/
private function importAccount($crmData): Account
{
$countryCode = null;
if (empty($crmData['address']) === false && $crmData['address']['country']) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$name = $crmData['name'];
$parsedNumber = null;
foreach ($crmData['phone_numbers'] as $phoneNumber) {
$parsedNumber = parsePhoneNumber($countryCode, $phoneNumber['number']);
}
$domain = null;
if (empty($crmData['websites']) === false) {
$domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);
$domain = StringUtil::resolveDomain($domain);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($name, 0, 191),
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Account::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'country_code' => $countryCode,
'domain' => $domain,
'phone' => $parsedNumber['phone'] ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->accounts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
public function syncOpportunities(array $parameters, ?string $strategy = null): int
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->copperClient,
]);
$strategies = $strategyResolver->getStrategies($this->config, $strategy);
$syncCount = 0;
try {
foreach ($strategies as $syncStrategy) {
foreach ($syncStrategy->fetchOpportunities($parameters) as $opportunityData) {
$this->importOpportunity($opportunityData);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
$this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => $exception->getMessage(),
]);
}
return $syncCount;
}
public function syncOpportunity(string $crmId): ?Opportunity
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->copperClient,
]);
$strategy = $strategyResolver->resolve(
$this->config,
OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY
);
$parameters['crm_id'] = $crmId;
$cpOpportunity = $strategy->fetchOpportunities($parameters);
return $this->importOpportunity($cpOpportunity);
}
private function importOpportunity($crmData): ?Opportunity
{
$companyId = (string) $crmData['company_id'];
if (empty($companyId)) {
$this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => 'No company id',
]);
return null;
}
$account = $this->config->accounts()->where('crm_provider_id', $companyId)->first();
if ($account === null) {
$account = $this->syncAccount($companyId);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', (string) $crmData['pipeline_id'])
->first();
if ($businessProcess === null) {
// It is possible for some deals to not be in a pipeline.
$this->logger->warning(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => 'Missing pipeline',
]);
return null;
}
$stage = $businessProcess
->stages()
->where('crm_provider_id', (string) $crmData['pipeline_stage_id'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
$this->logger->info('Stage not found, importing', [
'pipeline_id' => $crmData['pipeline_id'],
'stage_id' => $crmData['pipeline_stage_id'],
]);
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData['pipeline_stage_id']);
}
$recordType = $businessProcess->recordTypes()->first();
$closeDate = null;
$isClosed = $crmData['status'] !== self::OPPORTUNITY_STATUS_OPEN;
if ($crmData['close_date']) {
$closeDate = Carbon::parse($crmData['close_date'])->format('Y-m-d');
}
$data = [
'team_id' => $this->team->getId(),
'account_id' => $account->id,
'user_id' => $profile->user_id ?? null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($crmData['name'], 0, 128),
'value' => $crmData['monetary_value'],
'currency_code' => CurrencyFormatter::formatCode($crmData['monetary_unit']),
'close_date' => $closeDate,
'is_closed' => $isClosed,
'is_won' => $crmData['status'] === 'Won',
'stage_id' => $stage->id,
'record_type_id' => $recordType->id ?? null,
'remotely_created_at' => $crmData['date_created'],
];
/** @var Opportunity $opportunity */
$opportunity = $this->config
->opportunities()
->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data)
;
// import external fields into crm_field_data if present
$dealInsightsFields = $this->getOpportunitySyncableFields();
$this->importOpportunityCrmFieldData($crmData, $dealInsightsFields, $opportunity->id);
return $opportunity;
}
/**
* @param array<string, mixed> $opportunityData
* @param string[] $dealInsightsFields
*/
public function importOpportunityCrmFieldData(
array $opportunityData,
array $dealInsightsFields,
int $opportunityId
): void {
foreach ($dealInsightsFields as $fieldName) {
$field = $this->config->fields()->with('entities')
->where('crm_provider_id', $fieldName)
->where('object_type', Field::OBJECT_OPPORTUNITY)
->first();
if (! $field instanceof Field) {
$this->logger->warning('Field not found', [
'field' => $fieldName,
'opportunity_id' => $opportunityId,
]);
continue;
}
$entity = $field->getEntities()->first();
if (! $entity instanceof LayoutEntity) {
continue;
}
$fieldValue = $this->extractFieldValue($opportunityData, $fieldName);
$normalizedValue = $this->normalizeValue($field->getType(), (string) $fieldValue, true);
$field->data()
->updateOrCreate([
'crm_layout_entity_id' => $entity->id,
'crm_field_id' => $field->id,
'object_type' => 'opportunity',
'object_id' => $opportunityId,
], ['value' => $normalizedValue])
;
}
}
/**
* @inheritdoc
*/
public function syncContacts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
$cpContacts = $this->copperClient->contacts()->paginate([
'minimum_interaction_date' => $since->timestamp,
'sort_by' => 'date_modified',
]);
foreach ($cpContacts as $cpContact) {
// Only sync if previously imported.
if ($this->hasContact($cpContact['id'])) {
$this->importContact($cpContact);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
throw $exception;
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncContact(string $crmId): ?Contact
{
$cpContact = $this->copperClient->contacts()->find($crmId);
if (empty($cpContact)) {
return null;
}
return $this->importContact($cpContact);
}
/**
* @inheritdoc
*/
private function importContact($crmData): Contact
{
$account = null;
if ($crmData['company_id']) {
$account = $this->team
->crm
->accounts()
->where('crm_provider_id', (string) $crmData['company_id'])
->first();
if ($account === null) {
$account = $this->syncAccount($crmData['company_id']);
}
}
$countryCode = null;
if (empty($crmData['address']) === false && $crmData['address']['country']) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$mobilePhone = $parsedNumber = null;
foreach ($crmData['phone_numbers'] as $phoneNumber) {
if ($phoneNumber['category'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);
} else {
$parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);
}
}
$email = null;
if (empty($crmData['emails']) === false) {
$email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'account_id' => $account->id ?? null,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => $crmData['name'],
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'mobile_phone' => $mobilePhone ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'title' => $crmData['title'],
'country_code' => $countryCode,
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Contact::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
private function buildContactPhone(?string $countryCode, ?string $number): ?array
{
if ($number) {
// Trim to our width and attempt to parse it.
$number = mb_strimwidth($number, 0, 25);
$parsedNumber = parsePhoneNumber($countryCode, $number);
} else {
$parsedNumber = [];
}
return $parsedNumber;
}
private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string
{
return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
$organization = $this->copperClient->organisation()->all();
if ($this->config->crm_provider_id !== $organization['id']) {
$this->config->update(['crm_provider_id' => $organization['id']]);
}
}
private function syncCustomFields(): void
{
foreach ($this->getFieldTypes() as $fieldType) {
$currentFields = $this->getFields($fieldType);
foreach ($currentFields as $field) {
/** @var Field $field */
$field = $this->config->fields()->updateOrCreate([
'crm_provider_id' => $field['name'],
'object_type' => $fieldType,
], [
'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),
'type' => $field['type'],
]);
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
}
$this->config->save();
}
protected function getFieldTypes(): array
{
return [
parent::OBJECT_TASK,
parent::OBJECT_LEAD,
parent::OBJECT_ACCOUNT,
parent::OBJECT_CONTACT,
parent::OBJECT_OPPORTUNITY,
];
}
/**
* @inheritdoc
*/
public function syncProfiles(?User $userToSearch = null): ?Profile
{
$profiles = $this->copperClient->users()->all();
foreach ($profiles as $profile) {
$user = $this->userRepository->findByTeamAndEmailAddress($this->team, $profile['email'], onlyActive: true);
// Only import profiles for users we have locally.
if ($user) {
$profile = $user->crmProfile()->updateOrCreate([
'crm_configuration_id' => $this->config->id,
'crm_provider_id' => $profile['id'],
]);
if ($userToSearch && $userToSearch->id === $user->id) {
return $profile;
}
}
}
return null;
}
/**
* @inheritdoc
*/
public function syncProfileFields(): void
{
$fieldTypes = [
'task',
'lead',
'account',
'contact',
'opportunity',
];
foreach ($fieldTypes as $fieldType) {
try {
$currentFields = $this->getFields(ucfirst($fieldType));
$newFields = array_column($currentFields, 'name');
$changedFields = array_merge(
array_diff($this->profile->getFieldsAsArray($fieldType), $newFields),
array_diff($newFields, $this->profile->getFieldsAsArray($fieldType))
);
if (\count($changedFields) > 0) {
$fields = implode(',', $newFields);
$this->logger->debug(
ucfirst($fieldType)
. ' fields changed from '
. $this->profile->{$fieldType . '_fields'}
. ' to: '
. $fields
);
$this->profile->{$fieldType . '_fields'} = $fields;
}
} catch (\Exception $exception) {
$this->logger->error('No access to ' . $fieldType . ' object, skipping...');
continue;
}
}
$this->profile->save();
}
/**
* @inheritdoc
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
$scopeValues = array_map(fn ($scope) => is_string($scope) ? $scope : $scope->value, $scopes);
$cacheKey = sprintf('copper-search-%d-%s-%s-%d-%d', $this->team->id, $name, implode('-', $scopeValues), $count, $offset);
return Cache::remember($cacheKey, 300, function () use ($name, $scopes, $count, $offset) {
// Try local search first
$localResults = $this->searchLocally($name, $scopes, $count, $offset);
// If no local results, fall back to remote API search
if (empty($localResults)) {
return $this->searchRemotely($name, $scopes, $count, $offset);
}
return $localResults;
});
}
/**
* @inheritdoc
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
$contact = null;
$account = null;
if ($crmAccountId) {
$account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();
if ($account === null) {
$account = $this->syncAccount($crmAccountId);
}
}
if ($crmContactId) {
$contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();
if ($contact === null) {
$contact = $this->syncContact($crmContactId);
}
}
if ($contact || $account) {
if ($contact && $account === null) {
$account = $contact->account;
}
if ($account === null) {
return [];
}
$params = [
'company_ids' => [$account->crm_provider_id],
'status_ids' => [0], // The integer values are 0, 1, 2, 3, for "Open", "Won", "Lost", and "Abandoned".
'sort_by' => 'date_modified',
'sort_direction' => 'desc',
];
switch ($this->config->opportunity_assignment_rule) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['sort_by'] = 'date_modified';
$params['sort_direction'] = 'desc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['sort_by'] = 'date_created';
$params['sort_direction'] = 'desc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['sort_by'] = 'date_created';
$params['sort_direction'] = 'asc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['sort_by'] = 'date_modified';
$params['sort_direction'] = 'desc';
$params['status_ids'] = [0, 1, 2, 3];
}
$cpOpportunities = $this->copperClient->opportunities()->search($params);
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
foreach ($cpOpportunities as $cpOpportunity) {
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', (string) $cpOpportunity['pipeline_id'])
->first();
if ($businessProcess === null) {
// Import it.
$businessProcess = $this->importStages(
[Stage::TYPE_OPPORTUNITY],
$cpOpportunity['pipeline_stage_id']
);
}
$stage = $businessProcess
->stages()
->where('crm_provider_id', (string) $cpOpportunity['pipeline_stage_id'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $cpOpportunity['pipeline_stage_id']);
}
$recordType = $businessProcess->recordTypes()->first();
$record = [
'crmId' => $cpOpportunity['id'],
'name' => $cpOpportunity['name'],
'value' => currency_format($cpOpportunity['monetary_value'], $cpOpportunity['monetary_unit']),
'won' => $cpOpportunity['status'] === 'Won',
'stage' => [
'id' => $stage->id_string,
'name' => $stage->name,
],
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
if ($ownerId && isset($cpOpportunity['assignee_id']) && $cpOpportunity['assignee_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
}
if (! empty($ownerData)) {
return $ownerData;
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array
{
$data = $cpTasks = [];
switch ($objectType) {
case 'lead':
$cpTasks = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->relatedTasks($objectId)
);
break;
case 'account':
$cpTasks = $this->copperClient->accounts()->relatedTasks($objectId);
break;
case 'contact':
if ($opportunityId) {
$cpTasks = $this->copperClient->opportunities()->relatedTasks($opportunityId);
} elseif ($objectType === 'contact') {
$cpTasks = $this->copperClient->contacts()->relatedTasks($objectId);
}
break;
}
foreach ($cpTasks as $cpTask) {
// We only get the ID itself returned, so pull out the full object.
try {
$cpTask = $this->copperClient->tasks()->find($cpTask['id']);
} catch (Exception $exception) {
$this->logger->error('[Copper] Error fetching task', [
'resource_id' => $cpTask['id'],
'error' => $exception->getMessage(),
]);
continue;
}
// Only allow open tasks.
if ($cpTask['status'] === 'Open') {
$data[] = [
'crmId' => $cpTask['id'],
'subject' => $cpTask['name'],
'due' => $cpTask['due_date']
? Carbon::createFromTimestamp($cpTask['due_date'])->format('Y-m-d\TH:i:sO')
: null,
'type' => null,
];
}
}
return $data;
}
/**
* Try to find email address in CRM service
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$cpObjectType = 'contact';
$cpObjects = $this->copperClient->contacts()->search([
'emails' => $email,
'sort_by' => 'date_modified',
'sort_direction' => 'desc',
]);
if (empty($cpObjects)) {
$cpObjectType = 'lead';
$cpObjects = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->search([
'emails' => ...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.2962101,"top":1.0,"width":0.03856383,"height":-0.019952059},"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":"#12066 on JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.33477393,"top":1.0,"width":0.122340426,"height":-0.019952059},"on_screen":true,"help_text":"Pull request #12066 exists for current branch JY-20725-handle-HS-search-rate-limit, but local branch is out of sync with remote","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.5731383,"top":1.0,"width":0.011303191,"height":-0.019952059},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.5884308,"top":1.0,"width":0.076130316,"height":-0.019952059},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.66456115,"top":1.0,"width":0.011303191,"height":-0.019952059},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.67586434,"top":1.0,"width":0.011303191,"height":-0.019952059},"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.6871675,"top":1.0,"width":0.011303191,"height":-0.019952059},"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.7150931,"top":1.0,"width":0.011303191,"height":-0.019952059},"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.72639626,"top":1.0,"width":0.011303191,"height":-0.019952059},"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.73769945,"top":1.0,"width":0.011303191,"height":-0.019952059},"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":"11","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"72","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"4","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\nnamespace Jiminny\\Services\\Crm\\Copper;\n\nuse Carbon\\Carbon;\nuse Exception;\nuse GuzzleHttp\\Exception\\ClientException;\nuse Illuminate\\Support\\Facades\\Cache;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\CopperInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Crm\\LayoutEntity;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Copper\\Api\\Client;\nuse Jiminny\\Services\\Crm\\Copper\\Api\\ClientFactory;\nuse Jiminny\\Services\\Crm\\Copper\\Exception\\RequestFailedException;\nuse Jiminny\\Services\\Crm\\Helpers\\FilterJoinedParticipants;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Services\\Crm\\Copper\\Traits\\SearchesCrmEntities;\nuse Jiminny\\Utils\\CurrencyFormatter;\nuse Jiminny\\Utils\\StringUtil;\n\nclass Service extends BaseService implements\n CopperInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n RemoteEntityManipulationInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n VerifyTaskExistsInterface\n{\n use SearchesCrmEntities;\n private const int NOTE_BODY_MAX_LENGTH = 3000000;\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n private const array STANDARD_OPPORTUNITY_FIELDS = [\n 'monetary_value' => [\n 'label' => 'Value',\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n 'type' => Field::TYPE_CURRENCY,\n ],\n 'pipeline_stage_id' => [\n 'label' => 'Stage',\n 'type' => Field::TYPE_PICKLIST,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n 'close_date' => [\n 'label' => 'Close date',\n 'type' => Field::TYPE_DATE,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n 'win_probability' => [\n 'label' => 'Win probability',\n 'type' => Field::TYPE_NUMBER,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n ];\n private const string UNSUPPORTED_OBJECT_TYPE = 'unsupported';\n private const string OPPORTUNITY_STATUS_OPEN = 'Open';\n private const string OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE = 'Opportunity import failed';\n private const string RESOURCE_UPDATE_FAILED_ERROR_MESSAGE = 'Failed to update resource';\n\n private FieldValueConverter $fieldValueConverter;\n private ClientFactory $clientFactory;\n private ?Client $copperClient = null;\n\n public function __construct(\n ClientFactory $clientFactory,\n FieldValueConverter $fieldValueConverter,\n private readonly UserRepository $userRepository,\n private readonly ProspectPhotoPathService $prospectPhotoPathService,\n private readonly CrmEntityRepository $crmEntityRepository\n ) {\n parent::__construct();\n\n $this->clientFactory = $clientFactory;\n $this->fieldValueConverter = $fieldValueConverter;\n }\n\n public function getDisplayName(): string\n {\n return 'Copper';\n }\n\n /**\n * Get the CRM entity repository (used by SearchesCrmEntities trait)\n */\n protected function getCrmEntityRepository(): CrmEntityRepository\n {\n return $this->crmEntityRepository;\n }\n\n public function getMinimumApiVersion(): string\n {\n return Client::MIN_API_VERSION;\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n $owner = $user->team->owner;\n\n return $owner->getSocialAccount(SocialAccount::PROVIDER_COPPER);\n }\n\n public function setUser(User $user): void\n {\n $this->configureSentryScope($user);\n\n $this->team = $user->getTeam();\n $this->teamService->setTeam($user->getTeam());\n $this->setConfiguration($user->getTeam()->getCrmConfiguration());\n\n // Reset state.\n $this->profile = $user->getProfile();\n\n if (! $this->profile instanceof Profile) {\n // Try to fetch their profile, maybe it was not yet imported?\n $this->profile = $this->getProfile($user);\n }\n }\n\n public function setConfiguration(Configuration $configuration): void\n {\n $this->config = $configuration;\n $this->copperClient = $this->clientFactory->create($configuration);\n\n if ($this->team === null) {\n $this->team = $configuration->getTeam();\n }\n }\n\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);\n }\n\n private function mapObjectType(string $objectType): string\n {\n $objectType = strtolower($objectType);\n\n switch ($objectType) {\n case Field::OBJECT_TASK:\n case Field::OBJECT_OPPORTUNITY:\n case Field::OBJECT_LEAD:\n $mappedType = $objectType;\n\n break;\n case Field::OBJECT_ACCOUNT:\n $mappedType = 'company';\n\n break;\n case Field::OBJECT_CONTACT:\n $mappedType = 'person';\n\n break;\n default:\n $mappedType = self::UNSUPPORTED_OBJECT_TYPE;\n\n break;\n }\n\n return $mappedType;\n }\n\n /**\n * @param string $crmObject The name of the CRM object. i.e. Opportunity or Contact\n */\n protected function getFields(string $crmObject): array\n {\n $mappedObjectType = $this->mapObjectType($crmObject);\n\n if (! $this->isSupportedObjectType($mappedObjectType)) {\n return [];\n }\n\n $customFields = $this->copperClient->fields()->all();\n\n $filteredFields = array_filter(\n $customFields,\n static fn ($field) => in_array($mappedObjectType, $field['available_on'], true)\n );\n\n return array_map(\n fn (array $property) => [\n 'name' => $property['id'],\n 'label' => $property['name'],\n 'type' => $this->convertFieldType($property['data_type']),\n ],\n $filteredFields\n );\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n // Setup the activity field as the default Type.\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'type',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n $fieldFilters = FieldDefinitions::taskFollowupFieldsFilter();\n\n foreach ($fieldFilters as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n public function syncFields(): void\n {\n $this->syncStandardFields();\n $this->syncCustomFields();\n }\n\n public function syncField(Field $field): void\n {\n if ($field->getCrmProviderId() === 'type') {\n /**\n * This field is a special case, it is not a custom field and is not returned by the Copper API.\n *\n * The field is created manually during layout setup.\n *\n * @see getDefaultFields()\n *\n * There is a separate endpoint to get the activity types.\n * @see importPicklistValues()\n */\n return;\n }\n\n if ($field->getCrmProviderId() === 'pipeline_stage_id') {\n // Not a custom type\n return;\n }\n\n $crmField = $this->copperClient->fields()->find($field->getCrmProviderId());\n $field->label = $crmField['name'];\n $field->type = $this->convertFieldType($crmField['data_type']);\n\n $field->save();\n }\n\n /**\n * @param string $fieldType How the data should be input\n */\n private function convertFieldType(string $fieldType): string\n {\n $fieldType = strtolower($fieldType);\n\n switch ($fieldType) {\n case 'dropdown':\n $convertedType = Field::TYPE_PICKLIST;\n\n break;\n case 'string':\n $convertedType = Field::TYPE_TEXT;\n\n break;\n case 'float':\n case 'percentage':\n $convertedType = Field::TYPE_NUMBER;\n\n break;\n case 'text':\n $convertedType = Field::TYPE_TEXTAREA;\n\n break;\n case 'checkbox':\n $convertedType = Field::TYPE_BOOLEAN;\n\n break;\n case Field::TYPE_DATE:\n case Field::TYPE_CURRENCY:\n case Field::TYPE_URL:\n $convertedType = $fieldType;\n\n break;\n default:\n $convertedType = Field::TYPE_UNSUPPORTED;\n\n break;\n }\n\n return $convertedType;\n }\n\n /**\n * @inheritdoc\n */\n public function importPicklistValues(Field $field): array\n {\n $fieldValues = [];\n\n if ($field->object_type === 'opportunity' && $field->crm_provider_id === 'pipeline_stage_id') {\n return $this->importFieldValuesForDealInsights($field);\n }\n\n $values = [];\n\n if ($field->object_type === Field::OBJECT_TASK && $field->crm_provider_id === 'type') {\n $activityTypes = $this->copperClient->activityTypes()->all();\n\n /**\n * We ignore \"system\" activity types, disabled activity types and the \"Note\" activity type.\n */\n $activityTypes = array_filter(\n $activityTypes['user'],\n fn (array $activityType) => ! $activityType['is_disabled'] && $activityType['id'] !== 0\n );\n\n // Import all activity values.\n $i = 0;\n foreach ($activityTypes as $activityType) {\n $values[] = [\n 'value' => $activityType['id'],\n 'label' => mb_strimwidth($activityType['name'], 0, Field::LABEL_MAX_LENGTH),\n 'sequence' => $i++,\n ];\n }\n } else {\n // We just check for the field in the custom definitions.\n $crmField = $this->copperClient->fields()->find($field->crm_provider_id);\n\n // Import all values.\n foreach ($crmField['options'] as $option) {\n $values[] = [\n 'value' => $option['id'],\n 'label' => mb_strimwidth($option['name'], 0, 191),\n 'sequence' => $option['rank'],\n ];\n }\n }\n\n // Take the existing set of field values.\n $fieldsToPurge = $field->values()->get()->pluck('value')->toArray();\n\n foreach ($values as $value) {\n // For all current values, upsert the field.\n $value['value'] = substr($value['value'] ?? '', 0, 255);\n $fieldValues[] = $field->values()->updateOrCreate([\n 'value' => $value['value'],\n ], $value);\n\n // Remove this value from the ones we are going to purge.\n $key = array_search($value['value'], $fieldsToPurge, false);\n if ($key !== false) {\n unset($fieldsToPurge[$key]);\n }\n }\n\n // Delete the old values that are no longer used.\n $field->values()->whereIn('value', $fieldsToPurge)->delete();\n\n return $fieldValues;\n }\n\n /**\n *\n * @return FieldValue[]\n */\n private function importFieldValuesForDealInsights(Field $field): array\n {\n $fieldValues = [];\n $pipelines = $this->copperClient->pipelines()->all();\n\n foreach ($pipelines as $pipeline) {\n foreach ($pipeline['stages'] as $i => $dealStage) {\n $fieldValues[] = $field->values()->updateOrCreate(\n ['value' => $dealStage['id']],\n [\n 'label' => $dealStage['name'],\n 'sequence' => $i,\n ]\n );\n }\n }\n\n return $fieldValues;\n }\n\n /**\n * @inheritdoc\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n if ($types === null) {\n $types = [Stage::TYPE_LEAD, Stage::TYPE_OPPORTUNITY];\n }\n $missingStage = null;\n\n foreach ($types as $type) {\n if ($type === Stage::TYPE_LEAD) {\n $statuses = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leadStatuses()->all()\n );\n\n if (count($statuses) > 0) {\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => BusinessProcess::TYPE_LEAD,\n ], [\n 'team_id' => $this->team->id,\n 'name' => BusinessProcess::TYPE_LEAD,\n 'type' => BusinessProcess::TYPE_LEAD,\n 'is_selectable' => true,\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => BusinessProcess::TYPE_LEAD,\n ], [\n 'team_id' => $this->team->id,\n 'name' => BusinessProcess::TYPE_LEAD,\n 'is_selectable' => true,\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n $leadStatuses = [];\n foreach ($statuses as $status) {\n // Upsert all statuses for the team.\n $status = $this->config->stages()->updateOrCreate([\n 'crm_provider_id' => $status['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($status['name'], 0, 50),\n 'label' => mb_strimwidth($status['name'], 0, 191),\n 'type' => Stage::TYPE_LEAD,\n 'sequence' => $status['order'],\n 'is_selectable' => true,\n ]);\n\n if ($missingStageName && $missingStageName === $status['id']) {\n $missingStage = $status;\n }\n\n $leadStatuses[] = $status['id'];\n }\n\n $businessProcess->stages()->sync($leadStatuses);\n }\n } else {\n // We create a business process to contain the pipeline, and later store all stages against it.\n foreach ($this->copperClient->pipelines()->all() as $pipeline) {\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => $pipeline['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($pipeline['name'], 0, 150),\n 'type' => BusinessProcess::TYPE_OPPORTUNITY,\n 'is_selectable' => true,\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => $pipeline['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($pipeline['name'], 0, 150),\n 'is_selectable' => true,\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n $stages = [];\n\n foreach ($pipeline['stages'] as $i => $dealStage) {\n // Upsert all stages for the team.\n $stage = $this->config->stages()->updateOrCreate([\n 'crm_provider_id' => $dealStage['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($dealStage['name'], 0, 50),\n 'label' => mb_strimwidth($dealStage['name'], 0, 191),\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'sequence' => $i,\n 'is_selectable' => true,\n 'probability' => $dealStage['win_probability'],\n ]);\n\n if ($missingStageName && $missingStageName === $dealStage['id']) {\n $missingStage = $stage;\n }\n\n $stages[] = $stage['id'];\n }\n\n $businessProcess->stages()->sync($stages);\n }\n }\n }\n\n return $missingStage;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int\n {\n $syncCount = 0;\n\n $cpLeads = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->paginate([\n 'minimum_modified_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ])\n );\n\n foreach ($cpLeads as $cpLead) {\n // Only sync if previously imported.\n if ($this->hasLead($cpLead['id']) === false) {\n $this->importLead($cpLead);\n $syncCount++;\n }\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLead(string $crmId): ?Lead\n {\n $cpLead = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->find($crmId)\n );\n\n if (\\count($cpLead) === 0) {\n return null;\n }\n\n return $this->importLead($cpLead);\n }\n\n /**\n * @inheritdoc\n */\n private function importLead($crmData): ?Lead\n {\n $countryCode = null;\n if (! empty($crmData['address']) && isset($crmData['address']['country'])) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $mobilePhone = $parsedNumber = null;\n if (! empty($crmData['phone_numbers'])) {\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n if ($phoneNumber['category'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);\n } else {\n $parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);\n }\n }\n }\n\n $name = $crmData['name'];\n\n if (empty($crmData['company_name'])) {\n $company = 'Unknown';\n } else {\n $company = mb_strimwidth($crmData['company_name'], 0, 191);\n }\n\n $domain = null;\n if (empty($crmData['websites']) === false) {\n $domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);\n $domain = StringUtil::resolveDomain($domain);\n }\n\n $email = null;\n if (empty($crmData['email']) === false) {\n $email = mb_strimwidth($crmData['email']['email'], 0, 80);\n }\n\n $stage = $this->config\n ->stages()\n ->where('crm_provider_id', (string) $crmData['status_id'])\n ->where('type', Stage::TYPE_LEAD)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_LEAD], $crmData['status_id']);\n }\n\n if (! $stage instanceof Stage) {\n return null;\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($name, 0, 191),\n 'company' => $company,\n 'domain' => $domain,\n 'title' => $crmData['title'] ? mb_strimwidth($crmData['title'], 0, 128) : null,\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'mobile_phone' => $mobilePhone,\n 'stage_id' => $stage->id,\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Lead::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'country_code' => $countryCode,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->leads()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n /**\n * @inheritdoc\n */\n public function syncAccounts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n $cpAccounts = $this->copperClient->accounts()->paginate([\n 'minimum_modified_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ]);\n\n foreach ($cpAccounts as $cpAccount) {\n // Only sync if previously imported.\n if ($this->hasAccount($cpAccount['id'])) {\n $this->importAccount($cpAccount);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncAccount(string $crmId): ?Account\n {\n $cpAccount = $this->copperClient->accounts()->find($crmId);\n\n if (empty($cpAccount)) {\n return null;\n }\n\n return $this->importAccount($cpAccount);\n }\n\n /**\n * @inheritdoc\n */\n private function importAccount($crmData): Account\n {\n $countryCode = null;\n if (empty($crmData['address']) === false && $crmData['address']['country']) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $name = $crmData['name'];\n\n $parsedNumber = null;\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n $parsedNumber = parsePhoneNumber($countryCode, $phoneNumber['number']);\n }\n\n $domain = null;\n if (empty($crmData['websites']) === false) {\n $domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);\n $domain = StringUtil::resolveDomain($domain);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($name, 0, 191),\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Account::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'country_code' => $countryCode,\n 'domain' => $domain,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->accounts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n public function syncOpportunities(array $parameters, ?string $strategy = null): int\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->copperClient,\n ]);\n $strategies = $strategyResolver->getStrategies($this->config, $strategy);\n\n $syncCount = 0;\n\n try {\n foreach ($strategies as $syncStrategy) {\n foreach ($syncStrategy->fetchOpportunities($parameters) as $opportunityData) {\n $this->importOpportunity($opportunityData);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n $this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => $exception->getMessage(),\n ]);\n }\n\n return $syncCount;\n }\n\n public function syncOpportunity(string $crmId): ?Opportunity\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->copperClient,\n ]);\n $strategy = $strategyResolver->resolve(\n $this->config,\n OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY\n );\n\n $parameters['crm_id'] = $crmId;\n\n $cpOpportunity = $strategy->fetchOpportunities($parameters);\n\n return $this->importOpportunity($cpOpportunity);\n }\n\n private function importOpportunity($crmData): ?Opportunity\n {\n $companyId = (string) $crmData['company_id'];\n\n if (empty($companyId)) {\n $this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => 'No company id',\n ]);\n\n return null;\n }\n\n $account = $this->config->accounts()->where('crm_provider_id', $companyId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($companyId);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', (string) $crmData['pipeline_id'])\n ->first();\n\n if ($businessProcess === null) {\n // It is possible for some deals to not be in a pipeline.\n $this->logger->warning(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => 'Missing pipeline',\n ]);\n\n return null;\n }\n\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', (string) $crmData['pipeline_stage_id'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n $this->logger->info('Stage not found, importing', [\n 'pipeline_id' => $crmData['pipeline_id'],\n 'stage_id' => $crmData['pipeline_stage_id'],\n ]);\n\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData['pipeline_stage_id']);\n }\n\n $recordType = $businessProcess->recordTypes()->first();\n $closeDate = null;\n $isClosed = $crmData['status'] !== self::OPPORTUNITY_STATUS_OPEN;\n\n if ($crmData['close_date']) {\n $closeDate = Carbon::parse($crmData['close_date'])->format('Y-m-d');\n }\n\n $data = [\n 'team_id' => $this->team->getId(),\n 'account_id' => $account->id,\n 'user_id' => $profile->user_id ?? null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($crmData['name'], 0, 128),\n 'value' => $crmData['monetary_value'],\n 'currency_code' => CurrencyFormatter::formatCode($crmData['monetary_unit']),\n 'close_date' => $closeDate,\n 'is_closed' => $isClosed,\n 'is_won' => $crmData['status'] === 'Won',\n 'stage_id' => $stage->id,\n 'record_type_id' => $recordType->id ?? null,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n /** @var Opportunity $opportunity */\n $opportunity = $this->config\n ->opportunities()\n ->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data)\n ;\n\n // import external fields into crm_field_data if present\n $dealInsightsFields = $this->getOpportunitySyncableFields();\n $this->importOpportunityCrmFieldData($crmData, $dealInsightsFields, $opportunity->id);\n\n return $opportunity;\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n * @param string[] $dealInsightsFields\n */\n public function importOpportunityCrmFieldData(\n array $opportunityData,\n array $dealInsightsFields,\n int $opportunityId\n ): void {\n foreach ($dealInsightsFields as $fieldName) {\n $field = $this->config->fields()->with('entities')\n ->where('crm_provider_id', $fieldName)\n ->where('object_type', Field::OBJECT_OPPORTUNITY)\n ->first();\n\n if (! $field instanceof Field) {\n $this->logger->warning('Field not found', [\n 'field' => $fieldName,\n 'opportunity_id' => $opportunityId,\n ]);\n\n continue;\n }\n\n $entity = $field->getEntities()->first();\n\n if (! $entity instanceof LayoutEntity) {\n continue;\n }\n\n $fieldValue = $this->extractFieldValue($opportunityData, $fieldName);\n $normalizedValue = $this->normalizeValue($field->getType(), (string) $fieldValue, true);\n\n $field->data()\n ->updateOrCreate([\n 'crm_layout_entity_id' => $entity->id,\n 'crm_field_id' => $field->id,\n 'object_type' => 'opportunity',\n 'object_id' => $opportunityId,\n ], ['value' => $normalizedValue])\n ;\n }\n }\n\n /**\n * @inheritdoc\n */\n public function syncContacts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n $cpContacts = $this->copperClient->contacts()->paginate([\n 'minimum_interaction_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ]);\n\n foreach ($cpContacts as $cpContact) {\n // Only sync if previously imported.\n if ($this->hasContact($cpContact['id'])) {\n $this->importContact($cpContact);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n throw $exception;\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncContact(string $crmId): ?Contact\n {\n $cpContact = $this->copperClient->contacts()->find($crmId);\n\n if (empty($cpContact)) {\n return null;\n }\n\n return $this->importContact($cpContact);\n }\n\n /**\n * @inheritdoc\n */\n private function importContact($crmData): Contact\n {\n $account = null;\n if ($crmData['company_id']) {\n $account = $this->team\n ->crm\n ->accounts()\n ->where('crm_provider_id', (string) $crmData['company_id'])\n ->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmData['company_id']);\n }\n }\n\n $countryCode = null;\n if (empty($crmData['address']) === false && $crmData['address']['country']) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $mobilePhone = $parsedNumber = null;\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n if ($phoneNumber['category'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);\n } else {\n $parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);\n }\n }\n\n $email = null;\n if (empty($crmData['emails']) === false) {\n $email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'account_id' => $account->id ?? null,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => $crmData['name'],\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'mobile_phone' => $mobilePhone ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'title' => $crmData['title'],\n 'country_code' => $countryCode,\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Contact::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n private function buildContactPhone(?string $countryCode, ?string $number): ?array\n {\n if ($number) {\n // Trim to our width and attempt to parse it.\n $number = mb_strimwidth($number, 0, 25);\n $parsedNumber = parsePhoneNumber($countryCode, $number);\n } else {\n $parsedNumber = [];\n }\n\n return $parsedNumber;\n }\n\n private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string\n {\n return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;\n }\n\n /**\n * @inheritdoc\n */\n public function syncOrganization(): void\n {\n $organization = $this->copperClient->organisation()->all();\n\n if ($this->config->crm_provider_id !== $organization['id']) {\n $this->config->update(['crm_provider_id' => $organization['id']]);\n }\n }\n\n private function syncCustomFields(): void\n {\n foreach ($this->getFieldTypes() as $fieldType) {\n $currentFields = $this->getFields($fieldType);\n\n foreach ($currentFields as $field) {\n /** @var Field $field */\n $field = $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => $field['name'],\n 'object_type' => $fieldType,\n ], [\n 'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),\n 'type' => $field['type'],\n ]);\n\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n }\n\n $this->config->save();\n }\n\n protected function getFieldTypes(): array\n {\n return [\n parent::OBJECT_TASK,\n parent::OBJECT_LEAD,\n parent::OBJECT_ACCOUNT,\n parent::OBJECT_CONTACT,\n parent::OBJECT_OPPORTUNITY,\n ];\n }\n\n /**\n * @inheritdoc\n */\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n $profiles = $this->copperClient->users()->all();\n\n foreach ($profiles as $profile) {\n $user = $this->userRepository->findByTeamAndEmailAddress($this->team, $profile['email'], onlyActive: true);\n\n // Only import profiles for users we have locally.\n if ($user) {\n $profile = $user->crmProfile()->updateOrCreate([\n 'crm_configuration_id' => $this->config->id,\n 'crm_provider_id' => $profile['id'],\n ]);\n\n if ($userToSearch && $userToSearch->id === $user->id) {\n return $profile;\n }\n }\n }\n\n return null;\n }\n\n /**\n * @inheritdoc\n */\n public function syncProfileFields(): void\n {\n $fieldTypes = [\n 'task',\n 'lead',\n 'account',\n 'contact',\n 'opportunity',\n ];\n\n foreach ($fieldTypes as $fieldType) {\n try {\n $currentFields = $this->getFields(ucfirst($fieldType));\n\n $newFields = array_column($currentFields, 'name');\n $changedFields = array_merge(\n array_diff($this->profile->getFieldsAsArray($fieldType), $newFields),\n array_diff($newFields, $this->profile->getFieldsAsArray($fieldType))\n );\n\n if (\\count($changedFields) > 0) {\n $fields = implode(',', $newFields);\n $this->logger->debug(\n ucfirst($fieldType)\n . ' fields changed from '\n . $this->profile->{$fieldType . '_fields'}\n . ' to: '\n . $fields\n );\n\n $this->profile->{$fieldType . '_fields'} = $fields;\n }\n } catch (\\Exception $exception) {\n $this->logger->error('No access to ' . $fieldType . ' object, skipping...');\n\n continue;\n }\n }\n\n $this->profile->save();\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n $scopeValues = array_map(fn ($scope) => is_string($scope) ? $scope : $scope->value, $scopes);\n $cacheKey = sprintf('copper-search-%d-%s-%s-%d-%d', $this->team->id, $name, implode('-', $scopeValues), $count, $offset);\n\n return Cache::remember($cacheKey, 300, function () use ($name, $scopes, $count, $offset) {\n // Try local search first\n $localResults = $this->searchLocally($name, $scopes, $count, $offset);\n\n // If no local results, fall back to remote API search\n if (empty($localResults)) {\n return $this->searchRemotely($name, $scopes, $count, $offset);\n }\n\n return $localResults;\n });\n }\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n $contact = null;\n $account = null;\n\n if ($crmAccountId) {\n $account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmAccountId);\n }\n }\n\n if ($crmContactId) {\n $contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();\n\n if ($contact === null) {\n $contact = $this->syncContact($crmContactId);\n }\n }\n\n if ($contact || $account) {\n if ($contact && $account === null) {\n $account = $contact->account;\n }\n\n if ($account === null) {\n return [];\n }\n\n $params = [\n 'company_ids' => [$account->crm_provider_id],\n 'status_ids' => [0], // The integer values are 0, 1, 2, 3, for \"Open\", \"Won\", \"Lost\", and \"Abandoned\".\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ];\n\n switch ($this->config->opportunity_assignment_rule) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['sort_by'] = 'date_modified';\n $params['sort_direction'] = 'desc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['sort_by'] = 'date_created';\n $params['sort_direction'] = 'desc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['sort_by'] = 'date_created';\n $params['sort_direction'] = 'asc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['sort_by'] = 'date_modified';\n $params['sort_direction'] = 'desc';\n $params['status_ids'] = [0, 1, 2, 3];\n }\n\n $cpOpportunities = $this->copperClient->opportunities()->search($params);\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n foreach ($cpOpportunities as $cpOpportunity) {\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', (string) $cpOpportunity['pipeline_id'])\n ->first();\n\n if ($businessProcess === null) {\n // Import it.\n $businessProcess = $this->importStages(\n [Stage::TYPE_OPPORTUNITY],\n $cpOpportunity['pipeline_stage_id']\n );\n }\n\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', (string) $cpOpportunity['pipeline_stage_id'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $cpOpportunity['pipeline_stage_id']);\n }\n\n $recordType = $businessProcess->recordTypes()->first();\n\n $record = [\n 'crmId' => $cpOpportunity['id'],\n 'name' => $cpOpportunity['name'],\n 'value' => currency_format($cpOpportunity['monetary_value'], $cpOpportunity['monetary_unit']),\n 'won' => $cpOpportunity['status'] === 'Won',\n 'stage' => [\n 'id' => $stage->id_string,\n 'name' => $stage->name,\n ],\n 'recordType' => [\n 'id' => $recordType->id_string,\n 'name' => $recordType->name,\n ],\n ];\n\n if ($ownerId && isset($cpOpportunity['assignee_id']) && $cpOpportunity['assignee_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = $cpTasks = [];\n\n switch ($objectType) {\n case 'lead':\n $cpTasks = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->relatedTasks($objectId)\n );\n\n break;\n\n case 'account':\n $cpTasks = $this->copperClient->accounts()->relatedTasks($objectId);\n\n break;\n case 'contact':\n if ($opportunityId) {\n $cpTasks = $this->copperClient->opportunities()->relatedTasks($opportunityId);\n } elseif ($objectType === 'contact') {\n $cpTasks = $this->copperClient->contacts()->relatedTasks($objectId);\n }\n\n break;\n }\n\n foreach ($cpTasks as $cpTask) {\n // We only get the ID itself returned, so pull out the full object.\n try {\n $cpTask = $this->copperClient->tasks()->find($cpTask['id']);\n } catch (Exception $exception) {\n $this->logger->error('[Copper] Error fetching task', [\n 'resource_id' => $cpTask['id'],\n 'error' => $exception->getMessage(),\n ]);\n\n continue;\n }\n\n // Only allow open tasks.\n if ($cpTask['status'] === 'Open') {\n $data[] = [\n 'crmId' => $cpTask['id'],\n 'subject' => $cpTask['name'],\n 'due' => $cpTask['due_date']\n ? Carbon::createFromTimestamp($cpTask['due_date'])->format('Y-m-d\\TH:i:sO')\n : null,\n 'type' => null,\n ];\n }\n }\n\n return $data;\n }\n\n /**\n * Try to find email address in CRM service\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $cpObjectType = 'contact';\n\n $cpObjects = $this->copperClient->contacts()->search([\n 'emails' => $email,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (empty($cpObjects)) {\n $cpObjectType = 'lead';\n $cpObjects = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'emails' => $email,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (empty($cpObjects)) {\n return null;\n }\n\n // Search returns an array of results, but we only want the first\n $cpObject = reset($cpObjects);\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n // Check if the user is internal.\n $teamMember = $this->team->users()->where('phone', $phone)->exists();\n\n // Skip the attendee if internal.\n if ($teamMember === false) {\n $cpObjectType = 'contact';\n $cpObject = $this->copperClient->contacts()->search([\n 'phone_number' => $phone,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (\\count($cpObject) === 0) {\n $cpObjectType = 'lead';\n $cpObject = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'phone_number' => $phone,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (empty($cpObject)) {\n return null;\n }\n\n $cpObject = reset($cpObject);\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n return null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $result = \\Cache::remember($this->team->id . $name, 60, function () use ($name, $userId) {\n $cpObjectType = 'contact';\n $cpObject = $this->copperClient->contacts()->search([\n 'name' => $name,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (\\count($cpObject) === 0) {\n $cpObjectType = 'lead';\n $cpObject = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'name' => $name,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (! empty($cpObject)) {\n $cpObject = reset($cpObject);\n }\n\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : false;\n });\n\n return is_array($result) ? $result : null;\n }\n\n private function convertCrmData(array $object, string $objectType, ?int $userId = null): array\n {\n $lead = null;\n $contact = null;\n $opportunity = null;\n $account = null;\n $stage = null;\n $countryCode = null;\n\n if ($objectType === 'lead') {\n $lead = $this->importLead($object);\n\n // Lead might not be imported if the Stage is null for example.\n if ($lead) {\n $countryCode = $lead->country_code;\n $stage = $lead->stage;\n }\n } else {\n $contact = $this->importContact($object);\n $account = $contact->account;\n\n if ($contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account) {\n $countryCode = $account->country_code;\n }\n\n try {\n $cpOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId,\n );\n\n if (! empty($cpOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($cpOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (\\Exception $e) {\n // Nothing to see here.\n }\n }\n\n return [\n $lead,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n public function saveActivity(Activity $activity): Activity\n {\n switch ($activity->type) {\n case Activity::TYPE_CONFERENCE:\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n $activity = $this->buildCallPayload($activity);\n\n break;\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $activity = $this->buildTextMessagePayload($activity);\n\n break;\n }\n\n return $activity;\n }\n\n private function convertActivityAssociations(Activity $activity): array\n {\n if ($activity->lead) {\n $type = 'lead';\n $id = $activity->lead->crm_provider_id;\n } elseif ($activity->contact) {\n $type = 'person';\n $id = $activity->contact->crm_provider_id;\n } elseif ($activity->opportunity) {\n $type = 'opportunity';\n $id = $activity->opportunity->crm_provider_id;\n } else {\n $type = 'company';\n $id = $activity->account->crm_provider_id;\n }\n\n return [\n 'type' => $type,\n 'id' => $id,\n ];\n }\n\n private function convertActivityType(PlaybookCategory $activityType): array\n {\n return [\n 'category' => 'user',\n 'id' => $this->getCrmType($activityType)->value,\n ];\n }\n\n /**\n * @throws CrmException\n */\n private function buildCallPayload(Activity $activity): Activity\n {\n try {\n if ($activity->crm_provider_id) {\n // The activity should be logged under the existing Task (not Activity).\n $newActivityType = $this->getCrmType($activity->category);\n if ($newActivityType === null) {\n $message = sprintf('[Copper] invalid CRM Custom Activity Type: %s', $activity->category);\n\n throw new CrmException($message, 400);\n }\n $this->copperClient->tasks()->update($activity->crm_provider_id, [\n 'status' => 'Completed',\n 'custom_activity_type_id' => $newActivityType->value,\n 'details' => $this->generateActivityDescription($activity),\n ]);\n } else {\n if ($this->getCrmType($activity->category) === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n if ($this->getCrmType($activity->category)->value === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n // Just create an activity.\n $cpActivity = $this->copperClient->activities()->create([\n 'user_id' => $this->profile->crm_provider_id,\n 'activity_date' => $activity->scheduled_start_time->timestamp,\n 'parent' => $this->convertActivityAssociations($activity),\n 'type' => $this->convertActivityType($activity->category),\n 'details' => $this->generateActivityDescription($activity),\n ]);\n\n $activity->crm_provider_id = $cpActivity['id'];\n $activity->save();\n }\n } catch (ClientException $exception) {\n //Log all errors to Sentry\n \\Sentry::captureException($exception);\n\n $response = $exception->getResponse();\n\n $responseBody = $response->getBody();\n $message = $responseBody;\n $errorCode = $response->getStatusCode();\n\n $jsonResponse = json_decode($responseBody, true);\n if (isset($jsonResponse[0]['message'])) {\n $message = $jsonResponse[0]['message'];\n }\n\n throw new CrmException($message, $errorCode);\n }\n\n return $activity;\n }\n\n private function buildTextMessagePayload(Activity $activity): Activity\n {\n if ($this->getCrmType($activity->category) === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n if ($this->getCrmType($activity->category)->value === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n $cpActivity = $this->copperClient->activities()->create([\n 'user_id' => $this->profile->crm_provider_id,\n 'activity_date' => $activity->created_at->timestamp,\n 'parent' => $this->convertActivityAssociations($activity),\n 'type' => $this->convertActivityType($activity->category),\n 'details' => $this->generateActivityDescription($activity),\n ]);\n\n $activity->crm_provider_id = $cpActivity['id'];\n $activity->save();\n\n return $activity;\n }\n\n private function generateActivityDescription(Activity $activity): string\n {\n $description = '';\n\n switch ($activity->type) {\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n case Activity::TYPE_CONFERENCE:\n\n $description = 'Jiminny Call Summary' . PHP_EOL . PHP_EOL;\n $description .= 'Call Duration: ' . $activity->duration_for_humans . PHP_EOL . PHP_EOL;\n\n // Tell them which number was dialed.\n if ($activity->to) {\n $description .= 'Dialed: ' . $activity->to->phone_number . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->hasReasonCodeBotKicked()) {\n $description .= 'Notetaker removed from this meeting' . PHP_EOL . PHP_EOL;\n // When we fix the state to be Activity::RECORDING_RECORDED as it should be this can change.\n } elseif ($activity->hasReasonCodeNotCompliant()) {\n $description .= 'Notetaker did not join due to recording consent not being provided by attendees' . PHP_EOL . PHP_EOL;\n } elseif ($activity->canReviewActivity()) {\n $playbackUrl = $activity->user->team->partner->getPlaybackUrl($activity);\n $description .= 'Review Activity:' . PHP_EOL . $playbackUrl . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->getCrmType() === Activity::TYPE_CONFERENCE) {\n $description .= 'Attendees:'\n . PHP_EOL\n . (new FilterJoinedParticipants())->toString($activity);\n }\n\n if (\\count($activity->notes) > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Notes: ' . PHP_EOL;\n\n foreach ($activity->notes as $note) {\n $nTime = (int) ceil($note->time);\n $time = ($nTime > 3600) ? gmdate('H:i:s', $nTime) : gmdate('i:s', $nTime);\n $description .= $time . ' ' . $note->note . PHP_EOL;\n }\n }\n\n // Get all private messages.\n $messages = $activity->messages()\n ->where('is_private', 1)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Coaching Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n // Get all public messages.\n $messages = $activity->messages()\n ->where('is_private', 0)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Customer Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n if ($activity->summary) {\n $description .= PHP_EOL . PHP_EOL . 'Summary: ' . PHP_EOL . $activity->summary;\n }\n\n break;\n\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $description = $activity->description;\n\n break;\n }\n\n return $description;\n }\n\n public function saveFollowupActivity(Activity $activity, array $fields): ?string\n {\n // This is the user provided activity subject field.\n if (empty($fields['type'])) {\n return null;\n }\n\n $reminder = null;\n if (empty($fields['reminder_date']) === false) {\n $formatReminder = Carbon::createFromFormat('Y-m-d\\TH:i:s\\Z', $fields['reminder_date']);\n $reminder = $formatReminder->getTimestamp();\n }\n\n $due = null;\n if (empty($fields['due_date']) === false) {\n $formatDue = Carbon::createFromFormat('Y-m-d\\TH:i:s\\Z', $fields['due_date']);\n $due = $formatDue->getTimestamp();\n }\n\n $data = [\n 'custom_activity_type_id' => $fields['type'],\n 'status' => 'Open',\n 'assignee_id' => $this->profile->crm_provider_id,\n 'due_date' => $due,\n 'details' => $fields['details'] ?? '',\n 'reminder_date' => $reminder,\n 'name' => $fields['name'] ?? 'Follow-up',\n 'related_resource' => $this->convertActivityAssociations($activity),\n 'custom_fields' => $this->fetchCustomFieldData($activity, Field::OBJECT_TASK),\n ];\n\n // We don't actually create a corresponding activity object on our side yet.\n return $this->copperClient->tasks()->create($data)['id'];\n }\n\n /**\n * Store transcripts as note.\n *\n * @throws \\Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, static::NOTE_BODY_MAX_LENGTH);\n\n $data = [\n 'user_id' => $this->profile->crm_provider_id,\n 'type' => [\n 'category' => 'user',\n 'id' => 0, // This creates a note.\n ],\n 'activity_date' => time(),\n 'details' => $transcripts,\n 'parent' => $this->convertActivityAssociations($activity),\n ];\n\n $cpActivity = $this->copperClient->activities()->create($data);\n\n // Store CRM Activity ID in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $cpActivity['id'];\n $transcription->save();\n }\n\n /**\n * @inheritdoc\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n if ($crmObject instanceof Lead) {\n $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->update($crmObject->crm_provider_id, [\n 'status_id' => $stage->crm_provider_id,\n ])\n );\n } else {\n $this->copperClient->opportunities()->update($crmObject->crm_provider_id, [\n 'pipeline_stage_id' => $stage->crm_provider_id,\n ]);\n }\n }\n\n public function prepareValueForUpdate(array $params): array\n {\n return [$params['fieldName'] => $params['fieldValue']];\n }\n\n /*\n * @inheritdoc\n */\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $preparedData = $data;\n\n if ($objectType === Field::OBJECT_OPPORTUNITY) {\n $preparedData = $this->prepareOpportunityFieldsForUpdate($data);\n }\n\n try {\n $this->copperClient\n ->createResourceFromObjectType($objectType)\n ->update($objectId, $preparedData)\n ;\n } catch (Exception $e) {\n $this->logger->error(self::RESOURCE_UPDATE_FAILED_ERROR_MESSAGE, [\n 'resource_id' => $objectId,\n 'data' => $preparedData,\n 'error' => $e->getMessage(),\n ]);\n\n throw new CrmException(self::RESOURCE_UPDATE_FAILED_ERROR_MESSAGE, $e->getCode(), $e);\n }\n }\n\n /**\n * @param array<string,string> $fieldData\n *\n * @throws CrmException\n *\n * @return array<string,array<int,array<string,bool|float|int|string|null>>|bool|float|int|string|null>\n */\n private function prepareOpportunityFieldsForUpdate(array $fieldData): array\n {\n $preparedData = [];\n $customFields = [];\n\n foreach ($fieldData as $fieldName => $fieldValue) {\n $field = $this->config\n ->fields()\n ->where('crm_provider_id', $fieldName)\n ->first();\n\n if (! $field instanceof Field) {\n throw new CrmException('Field not found');\n }\n\n $convertedValue = $this->fieldValueConverter->convertToCrm($field->getType(), $fieldValue);\n\n if ($this->isStandardField($fieldName)) {\n $preparedData[$fieldName] = $convertedValue;\n\n continue;\n }\n\n $customFields[] = [\n 'custom_field_definition_id' => $fieldName,\n 'value' => $convertedValue,\n ];\n }\n\n if (! empty($customFields)) {\n $preparedData['custom_fields'] = $customFields;\n }\n\n return $preparedData;\n }\n\n /*\n * @inheritdoc\n */\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n return $this->copperClient->createResourceFromObjectType($objectType)->find($objectId);\n }\n\n private function fetchCustomFieldData(Activity $activity, string $objectType): array\n {\n $payload = [];\n\n $fieldData = FieldData::where([\n 'object_id' => $activity->id,\n ])->whereHas('field', function ($query) use ($objectType) {\n $query->where('object_type', $objectType);\n })->get();\n\n foreach ($fieldData as $data) {\n // Add the field and value to the payload.\n $payload += [\n 'custom_field_definition_id' => $data->field->crm_provider_id,\n 'value' => $data->value,\n ];\n }\n\n return $payload;\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $baseUrl = 'https://app.prosperworks.com/companies/' . $this->config->crm_provider_id . '/app#/';\n switch ($objectType) {\n case 'lead':\n $url = $baseUrl . 'leads/' . $providerId;\n\n break;\n\n case 'account':\n $url = $baseUrl . 'organization/' . $providerId;\n\n break;\n\n case 'contact':\n $url = $baseUrl . 'contact/' . $providerId;\n\n break;\n\n case 'opportunity':\n $url = $baseUrl . 'deal/' . $providerId;\n\n break;\n\n default:\n case 'task':\n case 'activity':\n // Sadly we can't deeplink to these in Copper UI.\n $url = null;\n }\n\n return $url;\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! ($this->config->store_transcript)) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n return $this->transcriptionService\n ->findTranscriptionByActivity($activity)\n ->map(static function (array $transcriptionSegment): string {\n return $transcriptionSegment['formattedStartsAt'] . ' | ' . $transcriptionSegment['transcript'];\n })\n ->implode(PHP_EOL);\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n *\n * @return int|string|bool|float|null\n */\n private function extractFieldValue(array $opportunityData, string $fieldName)\n {\n $fieldValue = $this->isStandardField($fieldName)\n ? $opportunityData[$fieldName]\n : $this->resolveCustomFieldFromOpportunityData($opportunityData, $fieldName);\n\n if (is_array($fieldValue)) {\n $fieldValue = implode(', ', $fieldValue);\n }\n\n return $fieldValue;\n }\n\n private function isStandardField(string $fieldName): bool\n {\n return array_key_exists($fieldName, self::STANDARD_OPPORTUNITY_FIELDS);\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n *\n * @return string|int|float|bool|null|array<string, mixed>\n */\n private function resolveCustomFieldFromOpportunityData(array $opportunityData, string $fieldName)\n {\n $fieldData = array_filter(\n $opportunityData['custom_fields'],\n static fn ($field) => (string) $field['custom_field_definition_id'] === $fieldName\n );\n\n return array_pop($fieldData)['value'] ?? '';\n }\n\n private function isSupportedObjectType(string $objectType): bool\n {\n return $objectType !== self::UNSUPPORTED_OBJECT_TYPE;\n }\n\n private function syncStandardFields(): void\n {\n foreach (self::STANDARD_OPPORTUNITY_FIELDS as $fieldId => $fieldData) {\n $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => mb_strimwidth($fieldId, 0, 128),\n 'object_type' => Field::OBJECT_OPPORTUNITY,\n ], [\n 'label' => mb_strimwidth($fieldData['label'], 0, Field::LABEL_MAX_LENGTH),\n 'type' => $fieldData['type'],\n ]);\n }\n\n $this->importStages([Stage::TYPE_OPPORTUNITY]);\n }\n\n private function requestWithExceptionHandling(\\Closure $apiRequest): iterable\n {\n try {\n return $apiRequest();\n } catch (\\Exception $exception) {\n if ($exception->getCode() === 403) {\n // Object might not be supported\n return [];\n }\n\n \\Sentry::captureException($exception);\n\n return [];\n }\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n if ($this->copperClient === null) {\n return false;\n }\n\n $task = $this->copperClient->tasks()->find($crmProviderId);\n\n return ! empty($task);\n } catch (HttpNotFoundException) {\n // Task not found in CRM - this is expected and permanent\n $this->logger->info('[Copper] Task not found during verification', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n } catch (RequestFailedException $e) {\n // Handle 404 responses from Copper API\n if ($e->getCode() === 404) {\n $this->logger->info('[Copper] Task not found during verification (404)', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n\n // Re-throw other Copper exceptions for retry\n throw $e;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\n });\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Crm\\Copper;\n\nuse Carbon\\Carbon;\nuse Exception;\nuse GuzzleHttp\\Exception\\ClientException;\nuse Illuminate\\Support\\Facades\\Cache;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\CopperInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Crm\\LayoutEntity;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Copper\\Api\\Client;\nuse Jiminny\\Services\\Crm\\Copper\\Api\\ClientFactory;\nuse Jiminny\\Services\\Crm\\Copper\\Exception\\RequestFailedException;\nuse Jiminny\\Services\\Crm\\Helpers\\FilterJoinedParticipants;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Services\\Crm\\Copper\\Traits\\SearchesCrmEntities;\nuse Jiminny\\Utils\\CurrencyFormatter;\nuse Jiminny\\Utils\\StringUtil;\n\nclass Service extends BaseService implements\n CopperInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n RemoteEntityManipulationInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n VerifyTaskExistsInterface\n{\n use SearchesCrmEntities;\n private const int NOTE_BODY_MAX_LENGTH = 3000000;\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n private const array STANDARD_OPPORTUNITY_FIELDS = [\n 'monetary_value' => [\n 'label' => 'Value',\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n 'type' => Field::TYPE_CURRENCY,\n ],\n 'pipeline_stage_id' => [\n 'label' => 'Stage',\n 'type' => Field::TYPE_PICKLIST,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n 'close_date' => [\n 'label' => 'Close date',\n 'type' => Field::TYPE_DATE,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n 'win_probability' => [\n 'label' => 'Win probability',\n 'type' => Field::TYPE_NUMBER,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n ];\n private const string UNSUPPORTED_OBJECT_TYPE = 'unsupported';\n private const string OPPORTUNITY_STATUS_OPEN = 'Open';\n private const string OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE = 'Opportunity import failed';\n private const string RESOURCE_UPDATE_FAILED_ERROR_MESSAGE = 'Failed to update resource';\n\n private FieldValueConverter $fieldValueConverter;\n private ClientFactory $clientFactory;\n private ?Client $copperClient = null;\n\n public function __construct(\n ClientFactory $clientFactory,\n FieldValueConverter $fieldValueConverter,\n private readonly UserRepository $userRepository,\n private readonly ProspectPhotoPathService $prospectPhotoPathService,\n private readonly CrmEntityRepository $crmEntityRepository\n ) {\n parent::__construct();\n\n $this->clientFactory = $clientFactory;\n $this->fieldValueConverter = $fieldValueConverter;\n }\n\n public function getDisplayName(): string\n {\n return 'Copper';\n }\n\n /**\n * Get the CRM entity repository (used by SearchesCrmEntities trait)\n */\n protected function getCrmEntityRepository(): CrmEntityRepository\n {\n return $this->crmEntityRepository;\n }\n\n public function getMinimumApiVersion(): string\n {\n return Client::MIN_API_VERSION;\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n $owner = $user->team->owner;\n\n return $owner->getSocialAccount(SocialAccount::PROVIDER_COPPER);\n }\n\n public function setUser(User $user): void\n {\n $this->configureSentryScope($user);\n\n $this->team = $user->getTeam();\n $this->teamService->setTeam($user->getTeam());\n $this->setConfiguration($user->getTeam()->getCrmConfiguration());\n\n // Reset state.\n $this->profile = $user->getProfile();\n\n if (! $this->profile instanceof Profile) {\n // Try to fetch their profile, maybe it was not yet imported?\n $this->profile = $this->getProfile($user);\n }\n }\n\n public function setConfiguration(Configuration $configuration): void\n {\n $this->config = $configuration;\n $this->copperClient = $this->clientFactory->create($configuration);\n\n if ($this->team === null) {\n $this->team = $configuration->getTeam();\n }\n }\n\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);\n }\n\n private function mapObjectType(string $objectType): string\n {\n $objectType = strtolower($objectType);\n\n switch ($objectType) {\n case Field::OBJECT_TASK:\n case Field::OBJECT_OPPORTUNITY:\n case Field::OBJECT_LEAD:\n $mappedType = $objectType;\n\n break;\n case Field::OBJECT_ACCOUNT:\n $mappedType = 'company';\n\n break;\n case Field::OBJECT_CONTACT:\n $mappedType = 'person';\n\n break;\n default:\n $mappedType = self::UNSUPPORTED_OBJECT_TYPE;\n\n break;\n }\n\n return $mappedType;\n }\n\n /**\n * @param string $crmObject The name of the CRM object. i.e. Opportunity or Contact\n */\n protected function getFields(string $crmObject): array\n {\n $mappedObjectType = $this->mapObjectType($crmObject);\n\n if (! $this->isSupportedObjectType($mappedObjectType)) {\n return [];\n }\n\n $customFields = $this->copperClient->fields()->all();\n\n $filteredFields = array_filter(\n $customFields,\n static fn ($field) => in_array($mappedObjectType, $field['available_on'], true)\n );\n\n return array_map(\n fn (array $property) => [\n 'name' => $property['id'],\n 'label' => $property['name'],\n 'type' => $this->convertFieldType($property['data_type']),\n ],\n $filteredFields\n );\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n // Setup the activity field as the default Type.\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'type',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n $fieldFilters = FieldDefinitions::taskFollowupFieldsFilter();\n\n foreach ($fieldFilters as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n public function syncFields(): void\n {\n $this->syncStandardFields();\n $this->syncCustomFields();\n }\n\n public function syncField(Field $field): void\n {\n if ($field->getCrmProviderId() === 'type') {\n /**\n * This field is a special case, it is not a custom field and is not returned by the Copper API.\n *\n * The field is created manually during layout setup.\n *\n * @see getDefaultFields()\n *\n * There is a separate endpoint to get the activity types.\n * @see importPicklistValues()\n */\n return;\n }\n\n if ($field->getCrmProviderId() === 'pipeline_stage_id') {\n // Not a custom type\n return;\n }\n\n $crmField = $this->copperClient->fields()->find($field->getCrmProviderId());\n $field->label = $crmField['name'];\n $field->type = $this->convertFieldType($crmField['data_type']);\n\n $field->save();\n }\n\n /**\n * @param string $fieldType How the data should be input\n */\n private function convertFieldType(string $fieldType): string\n {\n $fieldType = strtolower($fieldType);\n\n switch ($fieldType) {\n case 'dropdown':\n $convertedType = Field::TYPE_PICKLIST;\n\n break;\n case 'string':\n $convertedType = Field::TYPE_TEXT;\n\n break;\n case 'float':\n case 'percentage':\n $convertedType = Field::TYPE_NUMBER;\n\n break;\n case 'text':\n $convertedType = Field::TYPE_TEXTAREA;\n\n break;\n case 'checkbox':\n $convertedType = Field::TYPE_BOOLEAN;\n\n break;\n case Field::TYPE_DATE:\n case Field::TYPE_CURRENCY:\n case Field::TYPE_URL:\n $convertedType = $fieldType;\n\n break;\n default:\n $convertedType = Field::TYPE_UNSUPPORTED;\n\n break;\n }\n\n return $convertedType;\n }\n\n /**\n * @inheritdoc\n */\n public function importPicklistValues(Field $field): array\n {\n $fieldValues = [];\n\n if ($field->object_type === 'opportunity' && $field->crm_provider_id === 'pipeline_stage_id') {\n return $this->importFieldValuesForDealInsights($field);\n }\n\n $values = [];\n\n if ($field->object_type === Field::OBJECT_TASK && $field->crm_provider_id === 'type') {\n $activityTypes = $this->copperClient->activityTypes()->all();\n\n /**\n * We ignore \"system\" activity types, disabled activity types and the \"Note\" activity type.\n */\n $activityTypes = array_filter(\n $activityTypes['user'],\n fn (array $activityType) => ! $activityType['is_disabled'] && $activityType['id'] !== 0\n );\n\n // Import all activity values.\n $i = 0;\n foreach ($activityTypes as $activityType) {\n $values[] = [\n 'value' => $activityType['id'],\n 'label' => mb_strimwidth($activityType['name'], 0, Field::LABEL_MAX_LENGTH),\n 'sequence' => $i++,\n ];\n }\n } else {\n // We just check for the field in the custom definitions.\n $crmField = $this->copperClient->fields()->find($field->crm_provider_id);\n\n // Import all values.\n foreach ($crmField['options'] as $option) {\n $values[] = [\n 'value' => $option['id'],\n 'label' => mb_strimwidth($option['name'], 0, 191),\n 'sequence' => $option['rank'],\n ];\n }\n }\n\n // Take the existing set of field values.\n $fieldsToPurge = $field->values()->get()->pluck('value')->toArray();\n\n foreach ($values as $value) {\n // For all current values, upsert the field.\n $value['value'] = substr($value['value'] ?? '', 0, 255);\n $fieldValues[] = $field->values()->updateOrCreate([\n 'value' => $value['value'],\n ], $value);\n\n // Remove this value from the ones we are going to purge.\n $key = array_search($value['value'], $fieldsToPurge, false);\n if ($key !== false) {\n unset($fieldsToPurge[$key]);\n }\n }\n\n // Delete the old values that are no longer used.\n $field->values()->whereIn('value', $fieldsToPurge)->delete();\n\n return $fieldValues;\n }\n\n /**\n *\n * @return FieldValue[]\n */\n private function importFieldValuesForDealInsights(Field $field): array\n {\n $fieldValues = [];\n $pipelines = $this->copperClient->pipelines()->all();\n\n foreach ($pipelines as $pipeline) {\n foreach ($pipeline['stages'] as $i => $dealStage) {\n $fieldValues[] = $field->values()->updateOrCreate(\n ['value' => $dealStage['id']],\n [\n 'label' => $dealStage['name'],\n 'sequence' => $i,\n ]\n );\n }\n }\n\n return $fieldValues;\n }\n\n /**\n * @inheritdoc\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n if ($types === null) {\n $types = [Stage::TYPE_LEAD, Stage::TYPE_OPPORTUNITY];\n }\n $missingStage = null;\n\n foreach ($types as $type) {\n if ($type === Stage::TYPE_LEAD) {\n $statuses = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leadStatuses()->all()\n );\n\n if (count($statuses) > 0) {\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => BusinessProcess::TYPE_LEAD,\n ], [\n 'team_id' => $this->team->id,\n 'name' => BusinessProcess::TYPE_LEAD,\n 'type' => BusinessProcess::TYPE_LEAD,\n 'is_selectable' => true,\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => BusinessProcess::TYPE_LEAD,\n ], [\n 'team_id' => $this->team->id,\n 'name' => BusinessProcess::TYPE_LEAD,\n 'is_selectable' => true,\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n $leadStatuses = [];\n foreach ($statuses as $status) {\n // Upsert all statuses for the team.\n $status = $this->config->stages()->updateOrCreate([\n 'crm_provider_id' => $status['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($status['name'], 0, 50),\n 'label' => mb_strimwidth($status['name'], 0, 191),\n 'type' => Stage::TYPE_LEAD,\n 'sequence' => $status['order'],\n 'is_selectable' => true,\n ]);\n\n if ($missingStageName && $missingStageName === $status['id']) {\n $missingStage = $status;\n }\n\n $leadStatuses[] = $status['id'];\n }\n\n $businessProcess->stages()->sync($leadStatuses);\n }\n } else {\n // We create a business process to contain the pipeline, and later store all stages against it.\n foreach ($this->copperClient->pipelines()->all() as $pipeline) {\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => $pipeline['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($pipeline['name'], 0, 150),\n 'type' => BusinessProcess::TYPE_OPPORTUNITY,\n 'is_selectable' => true,\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => $pipeline['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($pipeline['name'], 0, 150),\n 'is_selectable' => true,\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n $stages = [];\n\n foreach ($pipeline['stages'] as $i => $dealStage) {\n // Upsert all stages for the team.\n $stage = $this->config->stages()->updateOrCreate([\n 'crm_provider_id' => $dealStage['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($dealStage['name'], 0, 50),\n 'label' => mb_strimwidth($dealStage['name'], 0, 191),\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'sequence' => $i,\n 'is_selectable' => true,\n 'probability' => $dealStage['win_probability'],\n ]);\n\n if ($missingStageName && $missingStageName === $dealStage['id']) {\n $missingStage = $stage;\n }\n\n $stages[] = $stage['id'];\n }\n\n $businessProcess->stages()->sync($stages);\n }\n }\n }\n\n return $missingStage;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int\n {\n $syncCount = 0;\n\n $cpLeads = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->paginate([\n 'minimum_modified_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ])\n );\n\n foreach ($cpLeads as $cpLead) {\n // Only sync if previously imported.\n if ($this->hasLead($cpLead['id']) === false) {\n $this->importLead($cpLead);\n $syncCount++;\n }\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLead(string $crmId): ?Lead\n {\n $cpLead = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->find($crmId)\n );\n\n if (\\count($cpLead) === 0) {\n return null;\n }\n\n return $this->importLead($cpLead);\n }\n\n /**\n * @inheritdoc\n */\n private function importLead($crmData): ?Lead\n {\n $countryCode = null;\n if (! empty($crmData['address']) && isset($crmData['address']['country'])) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $mobilePhone = $parsedNumber = null;\n if (! empty($crmData['phone_numbers'])) {\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n if ($phoneNumber['category'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);\n } else {\n $parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);\n }\n }\n }\n\n $name = $crmData['name'];\n\n if (empty($crmData['company_name'])) {\n $company = 'Unknown';\n } else {\n $company = mb_strimwidth($crmData['company_name'], 0, 191);\n }\n\n $domain = null;\n if (empty($crmData['websites']) === false) {\n $domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);\n $domain = StringUtil::resolveDomain($domain);\n }\n\n $email = null;\n if (empty($crmData['email']) === false) {\n $email = mb_strimwidth($crmData['email']['email'], 0, 80);\n }\n\n $stage = $this->config\n ->stages()\n ->where('crm_provider_id', (string) $crmData['status_id'])\n ->where('type', Stage::TYPE_LEAD)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_LEAD], $crmData['status_id']);\n }\n\n if (! $stage instanceof Stage) {\n return null;\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($name, 0, 191),\n 'company' => $company,\n 'domain' => $domain,\n 'title' => $crmData['title'] ? mb_strimwidth($crmData['title'], 0, 128) : null,\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'mobile_phone' => $mobilePhone,\n 'stage_id' => $stage->id,\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Lead::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'country_code' => $countryCode,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->leads()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n /**\n * @inheritdoc\n */\n public function syncAccounts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n $cpAccounts = $this->copperClient->accounts()->paginate([\n 'minimum_modified_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ]);\n\n foreach ($cpAccounts as $cpAccount) {\n // Only sync if previously imported.\n if ($this->hasAccount($cpAccount['id'])) {\n $this->importAccount($cpAccount);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncAccount(string $crmId): ?Account\n {\n $cpAccount = $this->copperClient->accounts()->find($crmId);\n\n if (empty($cpAccount)) {\n return null;\n }\n\n return $this->importAccount($cpAccount);\n }\n\n /**\n * @inheritdoc\n */\n private function importAccount($crmData): Account\n {\n $countryCode = null;\n if (empty($crmData['address']) === false && $crmData['address']['country']) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $name = $crmData['name'];\n\n $parsedNumber = null;\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n $parsedNumber = parsePhoneNumber($countryCode, $phoneNumber['number']);\n }\n\n $domain = null;\n if (empty($crmData['websites']) === false) {\n $domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);\n $domain = StringUtil::resolveDomain($domain);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($name, 0, 191),\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Account::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'country_code' => $countryCode,\n 'domain' => $domain,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->accounts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n public function syncOpportunities(array $parameters, ?string $strategy = null): int\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->copperClient,\n ]);\n $strategies = $strategyResolver->getStrategies($this->config, $strategy);\n\n $syncCount = 0;\n\n try {\n foreach ($strategies as $syncStrategy) {\n foreach ($syncStrategy->fetchOpportunities($parameters) as $opportunityData) {\n $this->importOpportunity($opportunityData);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n $this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => $exception->getMessage(),\n ]);\n }\n\n return $syncCount;\n }\n\n public function syncOpportunity(string $crmId): ?Opportunity\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->copperClient,\n ]);\n $strategy = $strategyResolver->resolve(\n $this->config,\n OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY\n );\n\n $parameters['crm_id'] = $crmId;\n\n $cpOpportunity = $strategy->fetchOpportunities($parameters);\n\n return $this->importOpportunity($cpOpportunity);\n }\n\n private function importOpportunity($crmData): ?Opportunity\n {\n $companyId = (string) $crmData['company_id'];\n\n if (empty($companyId)) {\n $this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => 'No company id',\n ]);\n\n return null;\n }\n\n $account = $this->config->accounts()->where('crm_provider_id', $companyId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($companyId);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', (string) $crmData['pipeline_id'])\n ->first();\n\n if ($businessProcess === null) {\n // It is possible for some deals to not be in a pipeline.\n $this->logger->warning(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => 'Missing pipeline',\n ]);\n\n return null;\n }\n\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', (string) $crmData['pipeline_stage_id'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n $this->logger->info('Stage not found, importing', [\n 'pipeline_id' => $crmData['pipeline_id'],\n 'stage_id' => $crmData['pipeline_stage_id'],\n ]);\n\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData['pipeline_stage_id']);\n }\n\n $recordType = $businessProcess->recordTypes()->first();\n $closeDate = null;\n $isClosed = $crmData['status'] !== self::OPPORTUNITY_STATUS_OPEN;\n\n if ($crmData['close_date']) {\n $closeDate = Carbon::parse($crmData['close_date'])->format('Y-m-d');\n }\n\n $data = [\n 'team_id' => $this->team->getId(),\n 'account_id' => $account->id,\n 'user_id' => $profile->user_id ?? null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($crmData['name'], 0, 128),\n 'value' => $crmData['monetary_value'],\n 'currency_code' => CurrencyFormatter::formatCode($crmData['monetary_unit']),\n 'close_date' => $closeDate,\n 'is_closed' => $isClosed,\n 'is_won' => $crmData['status'] === 'Won',\n 'stage_id' => $stage->id,\n 'record_type_id' => $recordType->id ?? null,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n /** @var Opportunity $opportunity */\n $opportunity = $this->config\n ->opportunities()\n ->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data)\n ;\n\n // import external fields into crm_field_data if present\n $dealInsightsFields = $this->getOpportunitySyncableFields();\n $this->importOpportunityCrmFieldData($crmData, $dealInsightsFields, $opportunity->id);\n\n return $opportunity;\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n * @param string[] $dealInsightsFields\n */\n public function importOpportunityCrmFieldData(\n array $opportunityData,\n array $dealInsightsFields,\n int $opportunityId\n ): void {\n foreach ($dealInsightsFields as $fieldName) {\n $field = $this->config->fields()->with('entities')\n ->where('crm_provider_id', $fieldName)\n ->where('object_type', Field::OBJECT_OPPORTUNITY)\n ->first();\n\n if (! $field instanceof Field) {\n $this->logger->warning('Field not found', [\n 'field' => $fieldName,\n 'opportunity_id' => $opportunityId,\n ]);\n\n continue;\n }\n\n $entity = $field->getEntities()->first();\n\n if (! $entity instanceof LayoutEntity) {\n continue;\n }\n\n $fieldValue = $this->extractFieldValue($opportunityData, $fieldName);\n $normalizedValue = $this->normalizeValue($field->getType(), (string) $fieldValue, true);\n\n $field->data()\n ->updateOrCreate([\n 'crm_layout_entity_id' => $entity->id,\n 'crm_field_id' => $field->id,\n 'object_type' => 'opportunity',\n 'object_id' => $opportunityId,\n ], ['value' => $normalizedValue])\n ;\n }\n }\n\n /**\n * @inheritdoc\n */\n public function syncContacts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n $cpContacts = $this->copperClient->contacts()->paginate([\n 'minimum_interaction_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ]);\n\n foreach ($cpContacts as $cpContact) {\n // Only sync if previously imported.\n if ($this->hasContact($cpContact['id'])) {\n $this->importContact($cpContact);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n throw $exception;\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncContact(string $crmId): ?Contact\n {\n $cpContact = $this->copperClient->contacts()->find($crmId);\n\n if (empty($cpContact)) {\n return null;\n }\n\n return $this->importContact($cpContact);\n }\n\n /**\n * @inheritdoc\n */\n private function importContact($crmData): Contact\n {\n $account = null;\n if ($crmData['company_id']) {\n $account = $this->team\n ->crm\n ->accounts()\n ->where('crm_provider_id', (string) $crmData['company_id'])\n ->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmData['company_id']);\n }\n }\n\n $countryCode = null;\n if (empty($crmData['address']) === false && $crmData['address']['country']) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $mobilePhone = $parsedNumber = null;\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n if ($phoneNumber['category'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);\n } else {\n $parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);\n }\n }\n\n $email = null;\n if (empty($crmData['emails']) === false) {\n $email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'account_id' => $account->id ?? null,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => $crmData['name'],\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'mobile_phone' => $mobilePhone ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'title' => $crmData['title'],\n 'country_code' => $countryCode,\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Contact::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n private function buildContactPhone(?string $countryCode, ?string $number): ?array\n {\n if ($number) {\n // Trim to our width and attempt to parse it.\n $number = mb_strimwidth($number, 0, 25);\n $parsedNumber = parsePhoneNumber($countryCode, $number);\n } else {\n $parsedNumber = [];\n }\n\n return $parsedNumber;\n }\n\n private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string\n {\n return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;\n }\n\n /**\n * @inheritdoc\n */\n public function syncOrganization(): void\n {\n $organization = $this->copperClient->organisation()->all();\n\n if ($this->config->crm_provider_id !== $organization['id']) {\n $this->config->update(['crm_provider_id' => $organization['id']]);\n }\n }\n\n private function syncCustomFields(): void\n {\n foreach ($this->getFieldTypes() as $fieldType) {\n $currentFields = $this->getFields($fieldType);\n\n foreach ($currentFields as $field) {\n /** @var Field $field */\n $field = $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => $field['name'],\n 'object_type' => $fieldType,\n ], [\n 'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),\n 'type' => $field['type'],\n ]);\n\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n }\n\n $this->config->save();\n }\n\n protected function getFieldTypes(): array\n {\n return [\n parent::OBJECT_TASK,\n parent::OBJECT_LEAD,\n parent::OBJECT_ACCOUNT,\n parent::OBJECT_CONTACT,\n parent::OBJECT_OPPORTUNITY,\n ];\n }\n\n /**\n * @inheritdoc\n */\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n $profiles = $this->copperClient->users()->all();\n\n foreach ($profiles as $profile) {\n $user = $this->userRepository->findByTeamAndEmailAddress($this->team, $profile['email'], onlyActive: true);\n\n // Only import profiles for users we have locally.\n if ($user) {\n $profile = $user->crmProfile()->updateOrCreate([\n 'crm_configuration_id' => $this->config->id,\n 'crm_provider_id' => $profile['id'],\n ]);\n\n if ($userToSearch && $userToSearch->id === $user->id) {\n return $profile;\n }\n }\n }\n\n return null;\n }\n\n /**\n * @inheritdoc\n */\n public function syncProfileFields(): void\n {\n $fieldTypes = [\n 'task',\n 'lead',\n 'account',\n 'contact',\n 'opportunity',\n ];\n\n foreach ($fieldTypes as $fieldType) {\n try {\n $currentFields = $this->getFields(ucfirst($fieldType));\n\n $newFields = array_column($currentFields, 'name');\n $changedFields = array_merge(\n array_diff($this->profile->getFieldsAsArray($fieldType), $newFields),\n array_diff($newFields, $this->profile->getFieldsAsArray($fieldType))\n );\n\n if (\\count($changedFields) > 0) {\n $fields = implode(',', $newFields);\n $this->logger->debug(\n ucfirst($fieldType)\n . ' fields changed from '\n . $this->profile->{$fieldType . '_fields'}\n . ' to: '\n . $fields\n );\n\n $this->profile->{$fieldType . '_fields'} = $fields;\n }\n } catch (\\Exception $exception) {\n $this->logger->error('No access to ' . $fieldType . ' object, skipping...');\n\n continue;\n }\n }\n\n $this->profile->save();\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n $scopeValues = array_map(fn ($scope) => is_string($scope) ? $scope : $scope->value, $scopes);\n $cacheKey = sprintf('copper-search-%d-%s-%s-%d-%d', $this->team->id, $name, implode('-', $scopeValues), $count, $offset);\n\n return Cache::remember($cacheKey, 300, function () use ($name, $scopes, $count, $offset) {\n // Try local search first\n $localResults = $this->searchLocally($name, $scopes, $count, $offset);\n\n // If no local results, fall back to remote API search\n if (empty($localResults)) {\n return $this->searchRemotely($name, $scopes, $count, $offset);\n }\n\n return $localResults;\n });\n }\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n $contact = null;\n $account = null;\n\n if ($crmAccountId) {\n $account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmAccountId);\n }\n }\n\n if ($crmContactId) {\n $contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();\n\n if ($contact === null) {\n $contact = $this->syncContact($crmContactId);\n }\n }\n\n if ($contact || $account) {\n if ($contact && $account === null) {\n $account = $contact->account;\n }\n\n if ($account === null) {\n return [];\n }\n\n $params = [\n 'company_ids' => [$account->crm_provider_id],\n 'status_ids' => [0], // The integer values are 0, 1, 2, 3, for \"Open\", \"Won\", \"Lost\", and \"Abandoned\".\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ];\n\n switch ($this->config->opportunity_assignment_rule) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['sort_by'] = 'date_modified';\n $params['sort_direction'] = 'desc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['sort_by'] = 'date_created';\n $params['sort_direction'] = 'desc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['sort_by'] = 'date_created';\n $params['sort_direction'] = 'asc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['sort_by'] = 'date_modified';\n $params['sort_direction'] = 'desc';\n $params['status_ids'] = [0, 1, 2, 3];\n }\n\n $cpOpportunities = $this->copperClient->opportunities()->search($params);\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n foreach ($cpOpportunities as $cpOpportunity) {\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', (string) $cpOpportunity['pipeline_id'])\n ->first();\n\n if ($businessProcess === null) {\n // Import it.\n $businessProcess = $this->importStages(\n [Stage::TYPE_OPPORTUNITY],\n $cpOpportunity['pipeline_stage_id']\n );\n }\n\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', (string) $cpOpportunity['pipeline_stage_id'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $cpOpportunity['pipeline_stage_id']);\n }\n\n $recordType = $businessProcess->recordTypes()->first();\n\n $record = [\n 'crmId' => $cpOpportunity['id'],\n 'name' => $cpOpportunity['name'],\n 'value' => currency_format($cpOpportunity['monetary_value'], $cpOpportunity['monetary_unit']),\n 'won' => $cpOpportunity['status'] === 'Won',\n 'stage' => [\n 'id' => $stage->id_string,\n 'name' => $stage->name,\n ],\n 'recordType' => [\n 'id' => $recordType->id_string,\n 'name' => $recordType->name,\n ],\n ];\n\n if ($ownerId && isset($cpOpportunity['assignee_id']) && $cpOpportunity['assignee_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = $cpTasks = [];\n\n switch ($objectType) {\n case 'lead':\n $cpTasks = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->relatedTasks($objectId)\n );\n\n break;\n\n case 'account':\n $cpTasks = $this->copperClient->accounts()->relatedTasks($objectId);\n\n break;\n case 'contact':\n if ($opportunityId) {\n $cpTasks = $this->copperClient->opportunities()->relatedTasks($opportunityId);\n } elseif ($objectType === 'contact') {\n $cpTasks = $this->copperClient->contacts()->relatedTasks($objectId);\n }\n\n break;\n }\n\n foreach ($cpTasks as $cpTask) {\n // We only get the ID itself returned, so pull out the full object.\n try {\n $cpTask = $this->copperClient->tasks()->find($cpTask['id']);\n } catch (Exception $exception) {\n $this->logger->error('[Copper] Error fetching task', [\n 'resource_id' => $cpTask['id'],\n 'error' => $exception->getMessage(),\n ]);\n\n continue;\n }\n\n // Only allow open tasks.\n if ($cpTask['status'] === 'Open') {\n $data[] = [\n 'crmId' => $cpTask['id'],\n 'subject' => $cpTask['name'],\n 'due' => $cpTask['due_date']\n ? Carbon::createFromTimestamp($cpTask['due_date'])->format('Y-m-d\\TH:i:sO')\n : null,\n 'type' => null,\n ];\n }\n }\n\n return $data;\n }\n\n /**\n * Try to find email address in CRM service\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $cpObjectType = 'contact';\n\n $cpObjects = $this->copperClient->contacts()->search([\n 'emails' => $email,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (empty($cpObjects)) {\n $cpObjectType = 'lead';\n $cpObjects = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'emails' => $email,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (empty($cpObjects)) {\n return null;\n }\n\n // Search returns an array of results, but we only want the first\n $cpObject = reset($cpObjects);\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n // Check if the user is internal.\n $teamMember = $this->team->users()->where('phone', $phone)->exists();\n\n // Skip the attendee if internal.\n if ($teamMember === false) {\n $cpObjectType = 'contact';\n $cpObject = $this->copperClient->contacts()->search([\n 'phone_number' => $phone,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (\\count($cpObject) === 0) {\n $cpObjectType = 'lead';\n $cpObject = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'phone_number' => $phone,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (empty($cpObject)) {\n return null;\n }\n\n $cpObject = reset($cpObject);\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n return null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $result = \\Cache::remember($this->team->id . $name, 60, function () use ($name, $userId) {\n $cpObjectType = 'contact';\n $cpObject = $this->copperClient->contacts()->search([\n 'name' => $name,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (\\count($cpObject) === 0) {\n $cpObjectType = 'lead';\n $cpObject = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'name' => $name,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (! empty($cpObject)) {\n $cpObject = reset($cpObject);\n }\n\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : false;\n });\n\n return is_array($result) ? $result : null;\n }\n\n private function convertCrmData(array $object, string $objectType, ?int $userId = null): array\n {\n $lead = null;\n $contact = null;\n $opportunity = null;\n $account = null;\n $stage = null;\n $countryCode = null;\n\n if ($objectType === 'lead') {\n $lead = $this->importLead($object);\n\n // Lead might not be imported if the Stage is null for example.\n if ($lead) {\n $countryCode = $lead->country_code;\n $stage = $lead->stage;\n }\n } else {\n $contact = $this->importContact($object);\n $account = $contact->account;\n\n if ($contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account) {\n $countryCode = $account->country_code;\n }\n\n try {\n $cpOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId,\n );\n\n if (! empty($cpOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($cpOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (\\Exception $e) {\n // Nothing to see here.\n }\n }\n\n return [\n $lead,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n public function saveActivity(Activity $activity): Activity\n {\n switch ($activity->type) {\n case Activity::TYPE_CONFERENCE:\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n $activity = $this->buildCallPayload($activity);\n\n break;\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $activity = $this->buildTextMessagePayload($activity);\n\n break;\n }\n\n return $activity;\n }\n\n private function convertActivityAssociations(Activity $activity): array\n {\n if ($activity->lead) {\n $type = 'lead';\n $id = $activity->lead->crm_provider_id;\n } elseif ($activity->contact) {\n $type = 'person';\n $id = $activity->contact->crm_provider_id;\n } elseif ($activity->opportunity) {\n $type = 'opportunity';\n $id = $activity->opportunity->crm_provider_id;\n } else {\n $type = 'company';\n $id = $activity->account->crm_provider_id;\n }\n\n return [\n 'type' => $type,\n 'id' => $id,\n ];\n }\n\n private function convertActivityType(PlaybookCategory $activityType): array\n {\n return [\n 'category' => 'user',\n 'id' => $this->getCrmType($activityType)->value,\n ];\n }\n\n /**\n * @throws CrmException\n */\n private function buildCallPayload(Activity $activity): Activity\n {\n try {\n if ($activity->crm_provider_id) {\n // The activity should be logged under the existing Task (not Activity).\n $newActivityType = $this->getCrmType($activity->category);\n if ($newActivityType === null) {\n $message = sprintf('[Copper] invalid CRM Custom Activity Type: %s', $activity->category);\n\n throw new CrmException($message, 400);\n }\n $this->copperClient->tasks()->update($activity->crm_provider_id, [\n 'status' => 'Completed',\n 'custom_activity_type_id' => $newActivityType->value,\n 'details' => $this->generateActivityDescription($activity),\n ]);\n } else {\n if ($this->getCrmType($activity->category) === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n if ($this->getCrmType($activity->category)->value === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n // Just create an activity.\n $cpActivity = $this->copperClient->activities()->create([\n 'user_id' => $this->profile->crm_provider_id,\n 'activity_date' => $activity->scheduled_start_time->timestamp,\n 'parent' => $this->convertActivityAssociations($activity),\n 'type' => $this->convertActivityType($activity->category),\n 'details' => $this->generateActivityDescription($activity),\n ]);\n\n $activity->crm_provider_id = $cpActivity['id'];\n $activity->save();\n }\n } catch (ClientException $exception) {\n //Log all errors to Sentry\n \\Sentry::captureException($exception);\n\n $response = $exception->getResponse();\n\n $responseBody = $response->getBody();\n $message = $responseBody;\n $errorCode = $response->getStatusCode();\n\n $jsonResponse = json_decode($responseBody, true);\n if (isset($jsonResponse[0]['message'])) {\n $message = $jsonResponse[0]['message'];\n }\n\n throw new CrmException($message, $errorCode);\n }\n\n return $activity;\n }\n\n private function buildTextMessagePayload(Activity $activity): Activity\n {\n if ($this->getCrmType($activity->category) === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n if ($this->getCrmType($activity->category)->value === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n $cpActivity = $this->copperClient->activities()->create([\n 'user_id' => $this->profile->crm_provider_id,\n 'activity_date' => $activity->created_at->timestamp,\n 'parent' => $this->convertActivityAssociations($activity),\n 'type' => $this->convertActivityType($activity->category),\n 'details' => $this->generateActivityDescription($activity),\n ]);\n\n $activity->crm_provider_id = $cpActivity['id'];\n $activity->save();\n\n return $activity;\n }\n\n private function generateActivityDescription(Activity $activity): string\n {\n $description = '';\n\n switch ($activity->type) {\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n case Activity::TYPE_CONFERENCE:\n\n $description = 'Jiminny Call Summary' . PHP_EOL . PHP_EOL;\n $description .= 'Call Duration: ' . $activity->duration_for_humans . PHP_EOL . PHP_EOL;\n\n // Tell them which number was dialed.\n if ($activity->to) {\n $description .= 'Dialed: ' . $activity->to->phone_number . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->hasReasonCodeBotKicked()) {\n $description .= 'Notetaker removed from this meeting' . PHP_EOL . PHP_EOL;\n // When we fix the state to be Activity::RECORDING_RECORDED as it should be this can change.\n } elseif ($activity->hasReasonCodeNotCompliant()) {\n $description .= 'Notetaker did not join due to recording consent not being provided by attendees' . PHP_EOL . PHP_EOL;\n } elseif ($activity->canReviewActivity()) {\n $playbackUrl = $activity->user->team->partner->getPlaybackUrl($activity);\n $description .= 'Review Activity:' . PHP_EOL . $playbackUrl . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->getCrmType() === Activity::TYPE_CONFERENCE) {\n $description .= 'Attendees:'\n . PHP_EOL\n . (new FilterJoinedParticipants())->toString($activity);\n }\n\n if (\\count($activity->notes) > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Notes: ' . PHP_EOL;\n\n foreach ($activity->notes as $note) {\n $nTime = (int) ceil($note->time);\n $time = ($nTime > 3600) ? gmdate('H:i:s', $nTime) : gmdate('i:s', $nTime);\n $description .= $time . ' ' . $note->note . PHP_EOL;\n }\n }\n\n // Get all private messages.\n $messages = $activity->messages()\n ->where('is_private', 1)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Coaching Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n // Get all public messages.\n $messages = $activity->messages()\n ->where('is_private', 0)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Customer Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n if ($activity->summary) {\n $description .= PHP_EOL . PHP_EOL . 'Summary: ' . PHP_EOL . $activity->summary;\n }\n\n break;\n\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $description = $activity->description;\n\n break;\n }\n\n return $description;\n }\n\n public function saveFollowupActivity(Activity $activity, array $fields): ?string\n {\n // This is the user provided activity subject field.\n if (empty($fields['type'])) {\n return null;\n }\n\n $reminder = null;\n if (empty($fields['reminder_date']) === false) {\n $formatReminder = Carbon::createFromFormat('Y-m-d\\TH:i:s\\Z', $fields['reminder_date']);\n $reminder = $formatReminder->getTimestamp();\n }\n\n $due = null;\n if (empty($fields['due_date']) === false) {\n $formatDue = Carbon::createFromFormat('Y-m-d\\TH:i:s\\Z', $fields['due_date']);\n $due = $formatDue->getTimestamp();\n }\n\n $data = [\n 'custom_activity_type_id' => $fields['type'],\n 'status' => 'Open',\n 'assignee_id' => $this->profile->crm_provider_id,\n 'due_date' => $due,\n 'details' => $fields['details'] ?? '',\n 'reminder_date' => $reminder,\n 'name' => $fields['name'] ?? 'Follow-up',\n 'related_resource' => $this->convertActivityAssociations($activity),\n 'custom_fields' => $this->fetchCustomFieldData($activity, Field::OBJECT_TASK),\n ];\n\n // We don't actually create a corresponding activity object on our side yet.\n return $this->copperClient->tasks()->create($data)['id'];\n }\n\n /**\n * Store transcripts as note.\n *\n * @throws \\Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, static::NOTE_BODY_MAX_LENGTH);\n\n $data = [\n 'user_id' => $this->profile->crm_provider_id,\n 'type' => [\n 'category' => 'user',\n 'id' => 0, // This creates a note.\n ],\n 'activity_date' => time(),\n 'details' => $transcripts,\n 'parent' => $this->convertActivityAssociations($activity),\n ];\n\n $cpActivity = $this->copperClient->activities()->create($data);\n\n // Store CRM Activity ID in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $cpActivity['id'];\n $transcription->save();\n }\n\n /**\n * @inheritdoc\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n if ($crmObject instanceof Lead) {\n $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->update($crmObject->crm_provider_id, [\n 'status_id' => $stage->crm_provider_id,\n ])\n );\n } else {\n $this->copperClient->opportunities()->update($crmObject->crm_provider_id, [\n 'pipeline_stage_id' => $stage->crm_provider_id,\n ]);\n }\n }\n\n public function prepareValueForUpdate(array $params): array\n {\n return [$params['fieldName'] => $params['fieldValue']];\n }\n\n /*\n * @inheritdoc\n */\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $preparedData = $data;\n\n if ($objectType === Field::OBJECT_OPPORTUNITY) {\n $preparedData = $this->prepareOpportunityFieldsForUpdate($data);\n }\n\n try {\n $this->copperClient\n ->createResourceFromObjectType($objectType)\n ->update($objectId, $preparedData)\n ;\n } catch (Exception $e) {\n $this->logger->error(self::RESOURCE_UPDATE_FAILED_ERROR_MESSAGE, [\n 'resource_id' => $objectId,\n 'data' => $preparedData,\n 'error' => $e->getMessage(),\n ]);\n\n throw new CrmException(self::RESOURCE_UPDATE_FAILED_ERROR_MESSAGE, $e->getCode(), $e);\n }\n }\n\n /**\n * @param array<string,string> $fieldData\n *\n * @throws CrmException\n *\n * @return array<string,array<int,array<string,bool|float|int|string|null>>|bool|float|int|string|null>\n */\n private function prepareOpportunityFieldsForUpdate(array $fieldData): array\n {\n $preparedData = [];\n $customFields = [];\n\n foreach ($fieldData as $fieldName => $fieldValue) {\n $field = $this->config\n ->fields()\n ->where('crm_provider_id', $fieldName)\n ->first();\n\n if (! $field instanceof Field) {\n throw new CrmException('Field not found');\n }\n\n $convertedValue = $this->fieldValueConverter->convertToCrm($field->getType(), $fieldValue);\n\n if ($this->isStandardField($fieldName)) {\n $preparedData[$fieldName] = $convertedValue;\n\n continue;\n }\n\n $customFields[] = [\n 'custom_field_definition_id' => $fieldName,\n 'value' => $convertedValue,\n ];\n }\n\n if (! empty($customFields)) {\n $preparedData['custom_fields'] = $customFields;\n }\n\n return $preparedData;\n }\n\n /*\n * @inheritdoc\n */\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n return $this->copperClient->createResourceFromObjectType($objectType)->find($objectId);\n }\n\n private function fetchCustomFieldData(Activity $activity, string $objectType): array\n {\n $payload = [];\n\n $fieldData = FieldData::where([\n 'object_id' => $activity->id,\n ])->whereHas('field', function ($query) use ($objectType) {\n $query->where('object_type', $objectType);\n })->get();\n\n foreach ($fieldData as $data) {\n // Add the field and value to the payload.\n $payload += [\n 'custom_field_definition_id' => $data->field->crm_provider_id,\n 'value' => $data->value,\n ];\n }\n\n return $payload;\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $baseUrl = 'https://app.prosperworks.com/companies/' . $this->config->crm_provider_id . '/app#/';\n switch ($objectType) {\n case 'lead':\n $url = $baseUrl . 'leads/' . $providerId;\n\n break;\n\n case 'account':\n $url = $baseUrl . 'organization/' . $providerId;\n\n break;\n\n case 'contact':\n $url = $baseUrl . 'contact/' . $providerId;\n\n break;\n\n case 'opportunity':\n $url = $baseUrl . 'deal/' . $providerId;\n\n break;\n\n default:\n case 'task':\n case 'activity':\n // Sadly we can't deeplink to these in Copper UI.\n $url = null;\n }\n\n return $url;\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! ($this->config->store_transcript)) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n return $this->transcriptionService\n ->findTranscriptionByActivity($activity)\n ->map(static function (array $transcriptionSegment): string {\n return $transcriptionSegment['formattedStartsAt'] . ' | ' . $transcriptionSegment['transcript'];\n })\n ->implode(PHP_EOL);\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n *\n * @return int|string|bool|float|null\n */\n private function extractFieldValue(array $opportunityData, string $fieldName)\n {\n $fieldValue = $this->isStandardField($fieldName)\n ? $opportunityData[$fieldName]\n : $this->resolveCustomFieldFromOpportunityData($opportunityData, $fieldName);\n\n if (is_array($fieldValue)) {\n $fieldValue = implode(', ', $fieldValue);\n }\n\n return $fieldValue;\n }\n\n private function isStandardField(string $fieldName): bool\n {\n return array_key_exists($fieldName, self::STANDARD_OPPORTUNITY_FIELDS);\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n *\n * @return string|int|float|bool|null|array<string, mixed>\n */\n private function resolveCustomFieldFromOpportunityData(array $opportunityData, string $fieldName)\n {\n $fieldData = array_filter(\n $opportunityData['custom_fields'],\n static fn ($field) => (string) $field['custom_field_definition_id'] === $fieldName\n );\n\n return array_pop($fieldData)['value'] ?? '';\n }\n\n private function isSupportedObjectType(string $objectType): bool\n {\n return $objectType !== self::UNSUPPORTED_OBJECT_TYPE;\n }\n\n private function syncStandardFields(): void\n {\n foreach (self::STANDARD_OPPORTUNITY_FIELDS as $fieldId => $fieldData) {\n $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => mb_strimwidth($fieldId, 0, 128),\n 'object_type' => Field::OBJECT_OPPORTUNITY,\n ], [\n 'label' => mb_strimwidth($fieldData['label'], 0, Field::LABEL_MAX_LENGTH),\n 'type' => $fieldData['type'],\n ]);\n }\n\n $this->importStages([Stage::TYPE_OPPORTUNITY]);\n }\n\n private function requestWithExceptionHandling(\\Closure $apiRequest): iterable\n {\n try {\n return $apiRequest();\n } catch (\\Exception $exception) {\n if ($exception->getCode() === 403) {\n // Object might not be supported\n return [];\n }\n\n \\Sentry::captureException($exception);\n\n return [];\n }\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n if ($this->copperClient === null) {\n return false;\n }\n\n $task = $this->copperClient->tasks()->find($crmProviderId);\n\n return ! empty($task);\n } catch (HttpNotFoundException) {\n // Task not found in CRM - this is expected and permanent\n $this->logger->info('[Copper] Task not found during verification', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n } catch (RequestFailedException $e) {\n // Handle 404 responses from Copper API\n if ($e->getCode() === 404) {\n $this->logger->info('[Copper] Task not found during verification (404)', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n\n // Re-throw other Copper exceptions for retry\n throw $e;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\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":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"on_screen":false,"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":false,"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":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"on_screen":false,"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":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"on_screen":false,"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":"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":"8","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"4","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":"SELECT\n# DISTINCT\nopp.id as opp_id, opp.uuid, opp.name,\n# COUNT(dr.id) AS deal_risk_count,\n\n# dr.id,\n# cfd.value,\nusr.name AS owner_name,\nopp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,\nusr.uuid as owner_uuid,\nusr.photo_path as owner_photo,\nusr.id AS owner_id,\njt.name as owner_job,\nopp.stage_id, opp.stage_updated_at,\nacc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,\nrt.business_process_id AS pipeline_id\nFROM opportunities opp\nLEFT JOIN record_types rt ON opp.record_type_id = rt.id\nLEFT JOIN users usr ON opp.user_id = usr.id\nLEFT JOIN accounts acc ON opp.account_id = acc.id\nLEFT JOIN job_titles jt ON usr.job_title_id = jt.id\n\n# LEFT JOIN group_deal_risk_types gdrt ON gdrt.group_id = usr.group_id\n# LEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id AND dr.group_deal_risk_type_id = gdrt.id\n\nLEFT JOIN crm_field_data cfd ON (cfd.object_id = opp.id and cfd.crm_field_id = 66814)\n\nWHERE opp.user_id IS NOT NULL\nAND opp.deleted_at IS NULL\nAND opp.is_closed = 1\nAND opp.is_won = 0\nAND opp.close_date >= '2024-01-01 00:00:00'\nAND opp.close_date <= '2024-12-31 23:59:59'\nAND usr.team_id = 1\n\n# and opp.id = 4823179\n\nGROUP BY opp.id, cfd.value\nORDER BY\n# cfd.value\n CAST(cfd.value AS UNSIGNED)\n# owner_name\n# (SELECT COUNT(dr.id)\n# FROM deal_risks dr\n# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n# WHERE dr.opportunity_id = opp.id\n# AND dr.is_active = 1\n# AND gdrt.is_enabled = 1)\nDESC\nLIMIT 25\n# OFFSET 0\n;\n\nselect * from crm_fields where crm_configuration_id = 1 and object_type = 'opportunity';\nselect * from crm_layout_entities where crm_layout_id = 1493;\n\nSELECT * FROM opportunities WHERE id = 4584045;\nSELECT * FROM crm_field_data WHERE object_id = 4584045;\n\nSELECT * FROM opportunities where team_id = 1 and crm_provider_id = '0061K00000lfb9IQAQ'\n\nSELECT\n opp.id as opportunity_id,\n opp.name,\n COUNT(dr.id) as risk_count\nFROM opportunities opp\nLEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id\nWHERE opp.id IN (\n 6069574,8900938,9507638,9524799,9660490,9662824,9705675,9749758,4158460,4391812,6450439,4448422,5118945,5590675,4584045,7228149,9002408,9165534,9446720,9641778,9665149,9703344,9709280,5747948,4158491,6182565,6263970,5798120,5111315,4536978,6062352,6548383,6072095,6548225,4480986,5011422,6548381,8760540,8917554,9509986,9514392,9569009,9569011,9578490,9713604,5784397,7276612,7288405,8994421,9118219,9608148,9818911,4510535,6479693,5958049,6271674,6550448,4158331,4158483,6126571,6171615,6540943,4897466,5190896,5796182,5932762,8572433,8723698,8892697,9711001,9789264,4549188,6100831,6170064,6260799,6263653,6449936,6530871,6538978,7777651,8059269,8319918,8787049,8901150,9263153,9453207,9514738,9696700,9791062,5752018,6421452,7439134,7878923,9354763,9369285,9514396,9582506,9889949,9890216,4094311,4158495,4158496,6098128,5585661,3872564,6442149,5891604,6164746,6199593,6583474,6519684,9018490,9809006,4496897,5041324,5829430,6198319,6253504,6555763,7242914,7931055,8024125,8797814,8058559,8673347,8892695,8994420,9616219,9714970,9722004,9809439,9818918,6523177,8134147,9002915,9711422,9892713,9901719,9954210,9978435,5800810,6243518,6416114,6222251,6411974,6512456,5791953,6545606,9914780,5805540,6238986,6463838,6547680,9767049,9809437,9810885,9890855,6673493,9902036,4335521,6379871,6503799,6546077,8018765,9907556,9958433,9905855,9916179,9946741,9957877,5563344,6271838,6450815,7641128,7762567,7780592,8684810,8685786,8685787,8685788\n)\nGROUP BY opp.id;\n\nSELECT COUNT(dr.id)\n FROM deal_risks dr\n JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n WHERE dr.opportunity_id = 5563344\n# AND gdrt.group_id = usr.group_id\n\n\n\nEXPLAIN SELECT\n opp.id as opp_id, opp.uuid, opp.name,\n\ncfd.value,\ncfv.sequence,\ncfv.value,\n# MAX(cfd.value) AS max_cfd_value,\nusr.name AS owner_name,\nopp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,\nusr.uuid as owner_uuid,\nusr.photo_path as owner_photo,\nusr.id AS owner_id,\njt.name as owner_job,\nopp.stage_id, opp.stage_updated_at,\nacc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,\nrt.business_process_id AS pipeline_id\nFROM opportunities opp\n\nLEFT JOIN record_types rt ON opp.record_type_id = rt.id\nLEFT JOIN users usr ON opp.user_id = usr.id\nLEFT JOIN accounts acc ON opp.account_id = acc.id\nLEFT JOIN job_titles jt ON usr.job_title_id = jt.id\n\nLEFT JOIN crm_field_data cfd ON cfd.id = (SELECT sub_cfd.id\n FROM crm_field_data sub_cfd\n WHERE sub_cfd.object_id = opp.id\n AND sub_cfd.crm_field_id = 66810\n ORDER BY sub_cfd.updated_at DESC\n LIMIT 1)\n\nLEFT JOIN crm_field_values cfv ON cfv.crm_field_id = 66810 AND cfv.value = cfd.value\n\nWHERE opp.user_id IS NOT NULL\nAND opp.deleted_at IS NULL\nAND opp.is_closed = 0\n# AND opp.is_closed = 1\n# AND opp.is_won = 0\nAND opp.close_date >= '2024-01-01 00:00:00'\nAND opp.close_date <= '2024-12-31 23:59:59'\nAND usr.team_id = 1\n\n# and opp.id = 4823179\n\n# GROUP BY opp.id\nORDER BY\n cfv.sequence DESC,\n# opp.name\n# owner_name\n cfd.value\n# CAST(cfd.value AS UNSIGNED)\n# CAST(MAX(cfd.value) AS UNSIGNED)\n# (SELECT COUNT(dr.id)\n# FROM deal_risks dr\n# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n# WHERE dr.opportunity_id = opp.id\n# AND dr.is_active = 1 AND gdrt.is_enabled = 1)\nDESC\n# LIMIT 75, 25\n;\n\n\n\nSELECT * FROM crm_field_values WHERE crm_field_id = 66810;\n\nSELECT f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value, fd.updated_at, fd.id, fd.created_at\nFROM crm_fields f\nINNER JOIN crm_field_data fd ON fd.crm_field_id = f.id\n WHERE (f.crm_configuration_id = 1)\n AND (f.object_type = 'opportunity')\n# AND (fd.object_id IN (4158331,4158483,4158495,4158496,6069574,6263970,6171615,6540943,6545606,5829430,6198319,6263653,6548381,7242914,8797814,7228149,7439134,7878923,8134147,9002915,9118219,9165534,9354763,9369285,9446720))\n AND (fd.object_id IN (4158460))\n AND (f.crm_provider_id IN ('ForecastCategoryName'))\n ORDER BY fd.object_id ASC, fd.updated_at DESC;\n\nselect * from crm_layouts where crm_configuration_id = 1;\nselect cf.* from crm_fields cf\njoin crm_layout_entities cle on cf.id = cle.crm_field_id\nwhere crm_layout_id = 1493;\n\nSELECT * FROM opportunities WHERE id = 4158460;\nSELECT * FROM crm_field_data WHERE object_id = 4158460;\n\nselect * from users where team_id = 1;\nSELECT * FROM users WHERE id = 7160;\nselect * from role_user where user_id = 3248;\n\nselect * from crm_field_values where crm_field_id = 66824;\n\nSELECT * FROM users WHERE id = 23470;\nselect * from crm_configurations;\n\n# ******************************************\nselect * from teams where id = 1038; # 23521, 966\nselect * from users where team_id = 1038;\nselect * from crm_configurations where id = 966;\nSELECT * FROM activities WHERE uuid_to_bin('e8dc7c34-31f6-4430-bd81-2d9d8f00dd07') = uuid; # 54965762\nSELECT * FROM activities WHERE uuid_to_bin('4b5727c0-69d1-428f-b8d9-b649055166e2') = uuid; # 54965764\nSELECT * FROM participants WHERE activity_id = 54965764;\n\nSELECT id, uuid, title, recording_state FROM activities WHERE uuid_to_bin('355f105d-5606-4379-b0c5-d91daf59f4ce') = uuid; # 54964075\nSELECT * FROM participants WHERE activity_id = 54964075;\nselect f.id, slug, title, tf.team_id from team_features tf JOIN features f on tf.feature_id = f.id\n where tf.team_id = 1038;\n\n\n# ****************************************** PD *************************\nselect * from teams where id = 1029;\nSELECT * FROM crm_configurations WHERE id = 957;\nSELECT * FROM activities WHERE uuid_to_bin('581a33cb-4343-44bd-ac0c-4a5cee71c5ec') = uuid; # 54963423\nSELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433\n\nSELECT * FROM activities WHERE uuid_to_bin('8b6bb2f7-e7a7-4aec-8806-fbfea7093ccd') = uuid; # 54963421\n\n# ****************************************** Close *************************\nselect * from teams where id = 1031;\nSELECT * FROM crm_configurations WHERE id = 959;\nSELECT * FROM activities WHERE uuid_to_bin('59c517e0-96c9-4dad-bfeb-b7bef72f8725') = uuid; # 54963517\n\n\nSELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433\n\nSELECT * FROM activities WHERE uuid_to_bin('d68311e3-ac34-49bd-bf04-88323a7e5352') = uuid; # 54966009\n\n# ****************************************** SF *************************\nSELECT * FROM activities WHERE uuid_to_bin('2bd4cfa3-4eb5-4c77-84a7-9ed46a21c988') = uuid;\n\nselect * from roles;\nselect * from permissions;\nselect * from permission_role where permission_id = 136;\n\nselect * from migrations order by id desc;\n\nselect * from teams where id IN (1, 1037);\nselect * from crm_layouts where crm_configuration_id = 1;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1493;\nSELECT * FROM crm_fields WHERE id IN (1652,1661,66799,66814,66821,66836,66843,66846,66864,84752,182306,323580,380378);\n\nselect * from features;\nselect * from team_features where feature_id = 33;\nselect * from opportunities;\n\nselect * from teams;\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 = 1052 and sa.provider = 'hubspot';\n\nSELECT * FROM accounts where id = 11512582;\nselect * from activities where account_id = 11512582;","depth":4,"on_screen":true,"value":"SELECT\n# DISTINCT\nopp.id as opp_id, opp.uuid, opp.name,\n# COUNT(dr.id) AS deal_risk_count,\n\n# dr.id,\n# cfd.value,\nusr.name AS owner_name,\nopp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,\nusr.uuid as owner_uuid,\nusr.photo_path as owner_photo,\nusr.id AS owner_id,\njt.name as owner_job,\nopp.stage_id, opp.stage_updated_at,\nacc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,\nrt.business_process_id AS pipeline_id\nFROM opportunities opp\nLEFT JOIN record_types rt ON opp.record_type_id = rt.id\nLEFT JOIN users usr ON opp.user_id = usr.id\nLEFT JOIN accounts acc ON opp.account_id = acc.id\nLEFT JOIN job_titles jt ON usr.job_title_id = jt.id\n\n# LEFT JOIN group_deal_risk_types gdrt ON gdrt.group_id = usr.group_id\n# LEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id AND dr.group_deal_risk_type_id = gdrt.id\n\nLEFT JOIN crm_field_data cfd ON (cfd.object_id = opp.id and cfd.crm_field_id = 66814)\n\nWHERE opp.user_id IS NOT NULL\nAND opp.deleted_at IS NULL\nAND opp.is_closed = 1\nAND opp.is_won = 0\nAND opp.close_date >= '2024-01-01 00:00:00'\nAND opp.close_date <= '2024-12-31 23:59:59'\nAND usr.team_id = 1\n\n# and opp.id = 4823179\n\nGROUP BY opp.id, cfd.value\nORDER BY\n# cfd.value\n CAST(cfd.value AS UNSIGNED)\n# owner_name\n# (SELECT COUNT(dr.id)\n# FROM deal_risks dr\n# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n# WHERE dr.opportunity_id = opp.id\n# AND dr.is_active = 1\n# AND gdrt.is_enabled = 1)\nDESC\nLIMIT 25\n# OFFSET 0\n;\n\nselect * from crm_fields where crm_configuration_id = 1 and object_type = 'opportunity';\nselect * from crm_layout_entities where crm_layout_id = 1493;\n\nSELECT * FROM opportunities WHERE id = 4584045;\nSELECT * FROM crm_field_data WHERE object_id = 4584045;\n\nSELECT * FROM opportunities where team_id = 1 and crm_provider_id = '0061K00000lfb9IQAQ'\n\nSELECT\n opp.id as opportunity_id,\n opp.name,\n COUNT(dr.id) as risk_count\nFROM opportunities opp\nLEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id\nWHERE opp.id IN (\n 6069574,8900938,9507638,9524799,9660490,9662824,9705675,9749758,4158460,4391812,6450439,4448422,5118945,5590675,4584045,7228149,9002408,9165534,9446720,9641778,9665149,9703344,9709280,5747948,4158491,6182565,6263970,5798120,5111315,4536978,6062352,6548383,6072095,6548225,4480986,5011422,6548381,8760540,8917554,9509986,9514392,9569009,9569011,9578490,9713604,5784397,7276612,7288405,8994421,9118219,9608148,9818911,4510535,6479693,5958049,6271674,6550448,4158331,4158483,6126571,6171615,6540943,4897466,5190896,5796182,5932762,8572433,8723698,8892697,9711001,9789264,4549188,6100831,6170064,6260799,6263653,6449936,6530871,6538978,7777651,8059269,8319918,8787049,8901150,9263153,9453207,9514738,9696700,9791062,5752018,6421452,7439134,7878923,9354763,9369285,9514396,9582506,9889949,9890216,4094311,4158495,4158496,6098128,5585661,3872564,6442149,5891604,6164746,6199593,6583474,6519684,9018490,9809006,4496897,5041324,5829430,6198319,6253504,6555763,7242914,7931055,8024125,8797814,8058559,8673347,8892695,8994420,9616219,9714970,9722004,9809439,9818918,6523177,8134147,9002915,9711422,9892713,9901719,9954210,9978435,5800810,6243518,6416114,6222251,6411974,6512456,5791953,6545606,9914780,5805540,6238986,6463838,6547680,9767049,9809437,9810885,9890855,6673493,9902036,4335521,6379871,6503799,6546077,8018765,9907556,9958433,9905855,9916179,9946741,9957877,5563344,6271838,6450815,7641128,7762567,7780592,8684810,8685786,8685787,8685788\n)\nGROUP BY opp.id;\n\nSELECT COUNT(dr.id)\n FROM deal_risks dr\n JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n WHERE dr.opportunity_id = 5563344\n# AND gdrt.group_id = usr.group_id\n\n\n\nEXPLAIN SELECT\n opp.id as opp_id, opp.uuid, opp.name,\n\ncfd.value,\ncfv.sequence,\ncfv.value,\n# MAX(cfd.value) AS max_cfd_value,\nusr.name AS owner_name,\nopp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,\nusr.uuid as owner_uuid,\nusr.photo_path as owner_photo,\nusr.id AS owner_id,\njt.name as owner_job,\nopp.stage_id, opp.stage_updated_at,\nacc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,\nrt.business_process_id AS pipeline_id\nFROM opportunities opp\n\nLEFT JOIN record_types rt ON opp.record_type_id = rt.id\nLEFT JOIN users usr ON opp.user_id = usr.id\nLEFT JOIN accounts acc ON opp.account_id = acc.id\nLEFT JOIN job_titles jt ON usr.job_title_id = jt.id\n\nLEFT JOIN crm_field_data cfd ON cfd.id = (SELECT sub_cfd.id\n FROM crm_field_data sub_cfd\n WHERE sub_cfd.object_id = opp.id\n AND sub_cfd.crm_field_id = 66810\n ORDER BY sub_cfd.updated_at DESC\n LIMIT 1)\n\nLEFT JOIN crm_field_values cfv ON cfv.crm_field_id = 66810 AND cfv.value = cfd.value\n\nWHERE opp.user_id IS NOT NULL\nAND opp.deleted_at IS NULL\nAND opp.is_closed = 0\n# AND opp.is_closed = 1\n# AND opp.is_won = 0\nAND opp.close_date >= '2024-01-01 00:00:00'\nAND opp.close_date <= '2024-12-31 23:59:59'\nAND usr.team_id = 1\n\n# and opp.id = 4823179\n\n# GROUP BY opp.id\nORDER BY\n cfv.sequence DESC,\n# opp.name\n# owner_name\n cfd.value\n# CAST(cfd.value AS UNSIGNED)\n# CAST(MAX(cfd.value) AS UNSIGNED)\n# (SELECT COUNT(dr.id)\n# FROM deal_risks dr\n# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n# WHERE dr.opportunity_id = opp.id\n# AND dr.is_active = 1 AND gdrt.is_enabled = 1)\nDESC\n# LIMIT 75, 25\n;\n\n\n\nSELECT * FROM crm_field_values WHERE crm_field_id = 66810;\n\nSELECT f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value, fd.updated_at, fd.id, fd.created_at\nFROM crm_fields f\nINNER JOIN crm_field_data fd ON fd.crm_field_id = f.id\n WHERE (f.crm_configuration_id = 1)\n AND (f.object_type = 'opportunity')\n# AND (fd.object_id IN (4158331,4158483,4158495,4158496,6069574,6263970,6171615,6540943,6545606,5829430,6198319,6263653,6548381,7242914,8797814,7228149,7439134,7878923,8134147,9002915,9118219,9165534,9354763,9369285,9446720))\n AND (fd.object_id IN (4158460))\n AND (f.crm_provider_id IN ('ForecastCategoryName'))\n ORDER BY fd.object_id ASC, fd.updated_at DESC;\n\nselect * from crm_layouts where crm_configuration_id = 1;\nselect cf.* from crm_fields cf\njoin crm_layout_entities cle on cf.id = cle.crm_field_id\nwhere crm_layout_id = 1493;\n\nSELECT * FROM opportunities WHERE id = 4158460;\nSELECT * FROM crm_field_data WHERE object_id = 4158460;\n\nselect * from users where team_id = 1;\nSELECT * FROM users WHERE id = 7160;\nselect * from role_user where user_id = 3248;\n\nselect * from crm_field_values where crm_field_id = 66824;\n\nSELECT * FROM users WHERE id = 23470;\nselect * from crm_configurations;\n\n# ******************************************\nselect * from teams where id = 1038; # 23521, 966\nselect * from users where team_id = 1038;\nselect * from crm_configurations where id = 966;\nSELECT * FROM activities WHERE uuid_to_bin('e8dc7c34-31f6-4430-bd81-2d9d8f00dd07') = uuid; # 54965762\nSELECT * FROM activities WHERE uuid_to_bin('4b5727c0-69d1-428f-b8d9-b649055166e2') = uuid; # 54965764\nSELECT * FROM participants WHERE activity_id = 54965764;\n\nSELECT id, uuid, title, recording_state FROM activities WHERE uuid_to_bin('355f105d-5606-4379-b0c5-d91daf59f4ce') = uuid; # 54964075\nSELECT * FROM participants WHERE activity_id = 54964075;\nselect f.id, slug, title, tf.team_id from team_features tf JOIN features f on tf.feature_id = f.id\n where tf.team_id = 1038;\n\n\n# ****************************************** PD *************************\nselect * from teams where id = 1029;\nSELECT * FROM crm_configurations WHERE id = 957;\nSELECT * FROM activities WHERE uuid_to_bin('581a33cb-4343-44bd-ac0c-4a5cee71c5ec') = uuid; # 54963423\nSELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433\n\nSELECT * FROM activities WHERE uuid_to_bin('8b6bb2f7-e7a7-4aec-8806-fbfea7093ccd') = uuid; # 54963421\n\n# ****************************************** Close *************************\nselect * from teams where id = 1031;\nSELECT * FROM crm_configurations WHERE id = 959;\nSELECT * FROM activities WHERE uuid_to_bin('59c517e0-96c9-4dad-bfeb-b7bef72f8725') = uuid; # 54963517\n\n\nSELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433\n\nSELECT * FROM activities WHERE uuid_to_bin('d68311e3-ac34-49bd-bf04-88323a7e5352') = uuid; # 54966009\n\n# ****************************************** SF *************************\nSELECT * FROM activities WHERE uuid_to_bin('2bd4cfa3-4eb5-4c77-84a7-9ed46a21c988') = uuid;\n\nselect * from roles;\nselect * from permissions;\nselect * from permission_role where permission_id = 136;\n\nselect * from migrations order by id desc;\n\nselect * from teams where id IN (1, 1037);\nselect * from crm_layouts where crm_configuration_id = 1;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1493;\nSELECT * FROM crm_fields WHERE id IN (1652,1661,66799,66814,66821,66836,66843,66846,66864,84752,182306,323580,380378);\n\nselect * from features;\nselect * from team_features where feature_id = 33;\nselect * from opportunities;\n\nselect * from teams;\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 = 1052 and sa.provider = 'hubspot';\n\nSELECT * FROM accounts where id = 11512582;\nselect * from activities where account_id = 11512582;","role_description":"text entry area","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.28224733,"top":1.0,"width":0.024268618,"height":-0.04788506},"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}]...
|
8957564869086018857
|
-7959665055215941403
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
11
72
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Copper;
use Carbon\Carbon;
use Exception;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Support\Facades\Cache;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\CopperInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Crm\LayoutEntity;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Repositories\UserRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Copper\Api\Client;
use Jiminny\Services\Crm\Copper\Api\ClientFactory;
use Jiminny\Services\Crm\Copper\Exception\RequestFailedException;
use Jiminny\Services\Crm\Helpers\FilterJoinedParticipants;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\Copper\Traits\SearchesCrmEntities;
use Jiminny\Utils\CurrencyFormatter;
use Jiminny\Utils\StringUtil;
class Service extends BaseService implements
CopperInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
RemoteEntityManipulationInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use SearchesCrmEntities;
private const int NOTE_BODY_MAX_LENGTH = 3000000;
private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day
private const array STANDARD_OPPORTUNITY_FIELDS = [
'monetary_value' => [
'label' => 'Value',
'available_on' => Field::OBJECT_OPPORTUNITY,
'type' => Field::TYPE_CURRENCY,
],
'pipeline_stage_id' => [
'label' => 'Stage',
'type' => Field::TYPE_PICKLIST,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
'close_date' => [
'label' => 'Close date',
'type' => Field::TYPE_DATE,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
'win_probability' => [
'label' => 'Win probability',
'type' => Field::TYPE_NUMBER,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
];
private const string UNSUPPORTED_OBJECT_TYPE = 'unsupported';
private const string OPPORTUNITY_STATUS_OPEN = 'Open';
private const string OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE = 'Opportunity import failed';
private const string RESOURCE_UPDATE_FAILED_ERROR_MESSAGE = 'Failed to update resource';
private FieldValueConverter $fieldValueConverter;
private ClientFactory $clientFactory;
private ?Client $copperClient = null;
public function __construct(
ClientFactory $clientFactory,
FieldValueConverter $fieldValueConverter,
private readonly UserRepository $userRepository,
private readonly ProspectPhotoPathService $prospectPhotoPathService,
private readonly CrmEntityRepository $crmEntityRepository
) {
parent::__construct();
$this->clientFactory = $clientFactory;
$this->fieldValueConverter = $fieldValueConverter;
}
public function getDisplayName(): string
{
return 'Copper';
}
/**
* Get the CRM entity repository (used by SearchesCrmEntities trait)
*/
protected function getCrmEntityRepository(): CrmEntityRepository
{
return $this->crmEntityRepository;
}
public function getMinimumApiVersion(): string
{
return Client::MIN_API_VERSION;
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
$owner = $user->team->owner;
return $owner->getSocialAccount(SocialAccount::PROVIDER_COPPER);
}
public function setUser(User $user): void
{
$this->configureSentryScope($user);
$this->team = $user->getTeam();
$this->teamService->setTeam($user->getTeam());
$this->setConfiguration($user->getTeam()->getCrmConfiguration());
// Reset state.
$this->profile = $user->getProfile();
if (! $this->profile instanceof Profile) {
// Try to fetch their profile, maybe it was not yet imported?
$this->profile = $this->getProfile($user);
}
}
public function setConfiguration(Configuration $configuration): void
{
$this->config = $configuration;
$this->copperClient = $this->clientFactory->create($configuration);
if ($this->team === null) {
$this->team = $configuration->getTeam();
}
}
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);
}
private function mapObjectType(string $objectType): string
{
$objectType = strtolower($objectType);
switch ($objectType) {
case Field::OBJECT_TASK:
case Field::OBJECT_OPPORTUNITY:
case Field::OBJECT_LEAD:
$mappedType = $objectType;
break;
case Field::OBJECT_ACCOUNT:
$mappedType = 'company';
break;
case Field::OBJECT_CONTACT:
$mappedType = 'person';
break;
default:
$mappedType = self::UNSUPPORTED_OBJECT_TYPE;
break;
}
return $mappedType;
}
/**
* @param string $crmObject The name of the CRM object. i.e. Opportunity or Contact
*/
protected function getFields(string $crmObject): array
{
$mappedObjectType = $this->mapObjectType($crmObject);
if (! $this->isSupportedObjectType($mappedObjectType)) {
return [];
}
$customFields = $this->copperClient->fields()->all();
$filteredFields = array_filter(
$customFields,
static fn ($field) => in_array($mappedObjectType, $field['available_on'], true)
);
return array_map(
fn (array $property) => [
'name' => $property['id'],
'label' => $property['name'],
'type' => $this->convertFieldType($property['data_type']),
],
$filteredFields
);
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
// Setup the activity field as the default Type.
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'type',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldFilters = FieldDefinitions::taskFollowupFieldsFilter();
foreach ($fieldFilters as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
public function syncFields(): void
{
$this->syncStandardFields();
$this->syncCustomFields();
}
public function syncField(Field $field): void
{
if ($field->getCrmProviderId() === 'type') {
/**
* This field is a special case, it is not a custom field and is not returned by the Copper API.
*
* The field is created manually during layout setup.
*
* @see getDefaultFields()
*
* There is a separate endpoint to get the activity types.
* @see importPicklistValues()
*/
return;
}
if ($field->getCrmProviderId() === 'pipeline_stage_id') {
// Not a custom type
return;
}
$crmField = $this->copperClient->fields()->find($field->getCrmProviderId());
$field->label = $crmField['name'];
$field->type = $this->convertFieldType($crmField['data_type']);
$field->save();
}
/**
* @param string $fieldType How the data should be input
*/
private function convertFieldType(string $fieldType): string
{
$fieldType = strtolower($fieldType);
switch ($fieldType) {
case 'dropdown':
$convertedType = Field::TYPE_PICKLIST;
break;
case 'string':
$convertedType = Field::TYPE_TEXT;
break;
case 'float':
case 'percentage':
$convertedType = Field::TYPE_NUMBER;
break;
case 'text':
$convertedType = Field::TYPE_TEXTAREA;
break;
case 'checkbox':
$convertedType = Field::TYPE_BOOLEAN;
break;
case Field::TYPE_DATE:
case Field::TYPE_CURRENCY:
case Field::TYPE_URL:
$convertedType = $fieldType;
break;
default:
$convertedType = Field::TYPE_UNSUPPORTED;
break;
}
return $convertedType;
}
/**
* @inheritdoc
*/
public function importPicklistValues(Field $field): array
{
$fieldValues = [];
if ($field->object_type === 'opportunity' && $field->crm_provider_id === 'pipeline_stage_id') {
return $this->importFieldValuesForDealInsights($field);
}
$values = [];
if ($field->object_type === Field::OBJECT_TASK && $field->crm_provider_id === 'type') {
$activityTypes = $this->copperClient->activityTypes()->all();
/**
* We ignore "system" activity types, disabled activity types and the "Note" activity type.
*/
$activityTypes = array_filter(
$activityTypes['user'],
fn (array $activityType) => ! $activityType['is_disabled'] && $activityType['id'] !== 0
);
// Import all activity values.
$i = 0;
foreach ($activityTypes as $activityType) {
$values[] = [
'value' => $activityType['id'],
'label' => mb_strimwidth($activityType['name'], 0, Field::LABEL_MAX_LENGTH),
'sequence' => $i++,
];
}
} else {
// We just check for the field in the custom definitions.
$crmField = $this->copperClient->fields()->find($field->crm_provider_id);
// Import all values.
foreach ($crmField['options'] as $option) {
$values[] = [
'value' => $option['id'],
'label' => mb_strimwidth($option['name'], 0, 191),
'sequence' => $option['rank'],
];
}
}
// Take the existing set of field values.
$fieldsToPurge = $field->values()->get()->pluck('value')->toArray();
foreach ($values as $value) {
// For all current values, upsert the field.
$value['value'] = substr($value['value'] ?? '', 0, 255);
$fieldValues[] = $field->values()->updateOrCreate([
'value' => $value['value'],
], $value);
// Remove this value from the ones we are going to purge.
$key = array_search($value['value'], $fieldsToPurge, false);
if ($key !== false) {
unset($fieldsToPurge[$key]);
}
}
// Delete the old values that are no longer used.
$field->values()->whereIn('value', $fieldsToPurge)->delete();
return $fieldValues;
}
/**
*
* @return FieldValue[]
*/
private function importFieldValuesForDealInsights(Field $field): array
{
$fieldValues = [];
$pipelines = $this->copperClient->pipelines()->all();
foreach ($pipelines as $pipeline) {
foreach ($pipeline['stages'] as $i => $dealStage) {
$fieldValues[] = $field->values()->updateOrCreate(
['value' => $dealStage['id']],
[
'label' => $dealStage['name'],
'sequence' => $i,
]
);
}
}
return $fieldValues;
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
if ($types === null) {
$types = [Stage::TYPE_LEAD, Stage::TYPE_OPPORTUNITY];
}
$missingStage = null;
foreach ($types as $type) {
if ($type === Stage::TYPE_LEAD) {
$statuses = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leadStatuses()->all()
);
if (count($statuses) > 0) {
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => BusinessProcess::TYPE_LEAD,
], [
'team_id' => $this->team->id,
'name' => BusinessProcess::TYPE_LEAD,
'type' => BusinessProcess::TYPE_LEAD,
'is_selectable' => true,
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => BusinessProcess::TYPE_LEAD,
], [
'team_id' => $this->team->id,
'name' => BusinessProcess::TYPE_LEAD,
'is_selectable' => true,
'business_process_id' => $businessProcess->id ?? null,
]);
$leadStatuses = [];
foreach ($statuses as $status) {
// Upsert all statuses for the team.
$status = $this->config->stages()->updateOrCreate([
'crm_provider_id' => $status['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($status['name'], 0, 50),
'label' => mb_strimwidth($status['name'], 0, 191),
'type' => Stage::TYPE_LEAD,
'sequence' => $status['order'],
'is_selectable' => true,
]);
if ($missingStageName && $missingStageName === $status['id']) {
$missingStage = $status;
}
$leadStatuses[] = $status['id'];
}
$businessProcess->stages()->sync($leadStatuses);
}
} else {
// We create a business process to contain the pipeline, and later store all stages against it.
foreach ($this->copperClient->pipelines()->all() as $pipeline) {
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $pipeline['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($pipeline['name'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => true,
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $pipeline['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($pipeline['name'], 0, 150),
'is_selectable' => true,
'business_process_id' => $businessProcess->id ?? null,
]);
$stages = [];
foreach ($pipeline['stages'] as $i => $dealStage) {
// Upsert all stages for the team.
$stage = $this->config->stages()->updateOrCreate([
'crm_provider_id' => $dealStage['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($dealStage['name'], 0, 50),
'label' => mb_strimwidth($dealStage['name'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $i,
'is_selectable' => true,
'probability' => $dealStage['win_probability'],
]);
if ($missingStageName && $missingStageName === $dealStage['id']) {
$missingStage = $stage;
}
$stages[] = $stage['id'];
}
$businessProcess->stages()->sync($stages);
}
}
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int
{
$syncCount = 0;
$cpLeads = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->paginate([
'minimum_modified_date' => $since->timestamp,
'sort_by' => 'date_modified',
])
);
foreach ($cpLeads as $cpLead) {
// Only sync if previously imported.
if ($this->hasLead($cpLead['id']) === false) {
$this->importLead($cpLead);
$syncCount++;
}
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncLead(string $crmId): ?Lead
{
$cpLead = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->find($crmId)
);
if (\count($cpLead) === 0) {
return null;
}
return $this->importLead($cpLead);
}
/**
* @inheritdoc
*/
private function importLead($crmData): ?Lead
{
$countryCode = null;
if (! empty($crmData['address']) && isset($crmData['address']['country'])) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$mobilePhone = $parsedNumber = null;
if (! empty($crmData['phone_numbers'])) {
foreach ($crmData['phone_numbers'] as $phoneNumber) {
if ($phoneNumber['category'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);
} else {
$parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);
}
}
}
$name = $crmData['name'];
if (empty($crmData['company_name'])) {
$company = 'Unknown';
} else {
$company = mb_strimwidth($crmData['company_name'], 0, 191);
}
$domain = null;
if (empty($crmData['websites']) === false) {
$domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);
$domain = StringUtil::resolveDomain($domain);
}
$email = null;
if (empty($crmData['email']) === false) {
$email = mb_strimwidth($crmData['email']['email'], 0, 80);
}
$stage = $this->config
->stages()
->where('crm_provider_id', (string) $crmData['status_id'])
->where('type', Stage::TYPE_LEAD)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_LEAD], $crmData['status_id']);
}
if (! $stage instanceof Stage) {
return null;
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($name, 0, 191),
'company' => $company,
'domain' => $domain,
'title' => $crmData['title'] ? mb_strimwidth($crmData['title'], 0, 128) : null,
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'mobile_phone' => $mobilePhone,
'stage_id' => $stage->id,
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Lead::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'country_code' => $countryCode,
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->leads()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
/**
* @inheritdoc
*/
public function syncAccounts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
$cpAccounts = $this->copperClient->accounts()->paginate([
'minimum_modified_date' => $since->timestamp,
'sort_by' => 'date_modified',
]);
foreach ($cpAccounts as $cpAccount) {
// Only sync if previously imported.
if ($this->hasAccount($cpAccount['id'])) {
$this->importAccount($cpAccount);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncAccount(string $crmId): ?Account
{
$cpAccount = $this->copperClient->accounts()->find($crmId);
if (empty($cpAccount)) {
return null;
}
return $this->importAccount($cpAccount);
}
/**
* @inheritdoc
*/
private function importAccount($crmData): Account
{
$countryCode = null;
if (empty($crmData['address']) === false && $crmData['address']['country']) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$name = $crmData['name'];
$parsedNumber = null;
foreach ($crmData['phone_numbers'] as $phoneNumber) {
$parsedNumber = parsePhoneNumber($countryCode, $phoneNumber['number']);
}
$domain = null;
if (empty($crmData['websites']) === false) {
$domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);
$domain = StringUtil::resolveDomain($domain);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($name, 0, 191),
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Account::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'country_code' => $countryCode,
'domain' => $domain,
'phone' => $parsedNumber['phone'] ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->accounts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
public function syncOpportunities(array $parameters, ?string $strategy = null): int
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->copperClient,
]);
$strategies = $strategyResolver->getStrategies($this->config, $strategy);
$syncCount = 0;
try {
foreach ($strategies as $syncStrategy) {
foreach ($syncStrategy->fetchOpportunities($parameters) as $opportunityData) {
$this->importOpportunity($opportunityData);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
$this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => $exception->getMessage(),
]);
}
return $syncCount;
}
public function syncOpportunity(string $crmId): ?Opportunity
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->copperClient,
]);
$strategy = $strategyResolver->resolve(
$this->config,
OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY
);
$parameters['crm_id'] = $crmId;
$cpOpportunity = $strategy->fetchOpportunities($parameters);
return $this->importOpportunity($cpOpportunity);
}
private function importOpportunity($crmData): ?Opportunity
{
$companyId = (string) $crmData['company_id'];
if (empty($companyId)) {
$this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => 'No company id',
]);
return null;
}
$account = $this->config->accounts()->where('crm_provider_id', $companyId)->first();
if ($account === null) {
$account = $this->syncAccount($companyId);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', (string) $crmData['pipeline_id'])
->first();
if ($businessProcess === null) {
// It is possible for some deals to not be in a pipeline.
$this->logger->warning(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => 'Missing pipeline',
]);
return null;
}
$stage = $businessProcess
->stages()
->where('crm_provider_id', (string) $crmData['pipeline_stage_id'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
$this->logger->info('Stage not found, importing', [
'pipeline_id' => $crmData['pipeline_id'],
'stage_id' => $crmData['pipeline_stage_id'],
]);
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData['pipeline_stage_id']);
}
$recordType = $businessProcess->recordTypes()->first();
$closeDate = null;
$isClosed = $crmData['status'] !== self::OPPORTUNITY_STATUS_OPEN;
if ($crmData['close_date']) {
$closeDate = Carbon::parse($crmData['close_date'])->format('Y-m-d');
}
$data = [
'team_id' => $this->team->getId(),
'account_id' => $account->id,
'user_id' => $profile->user_id ?? null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($crmData['name'], 0, 128),
'value' => $crmData['monetary_value'],
'currency_code' => CurrencyFormatter::formatCode($crmData['monetary_unit']),
'close_date' => $closeDate,
'is_closed' => $isClosed,
'is_won' => $crmData['status'] === 'Won',
'stage_id' => $stage->id,
'record_type_id' => $recordType->id ?? null,
'remotely_created_at' => $crmData['date_created'],
];
/** @var Opportunity $opportunity */
$opportunity = $this->config
->opportunities()
->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data)
;
// import external fields into crm_field_data if present
$dealInsightsFields = $this->getOpportunitySyncableFields();
$this->importOpportunityCrmFieldData($crmData, $dealInsightsFields, $opportunity->id);
return $opportunity;
}
/**
* @param array<string, mixed> $opportunityData
* @param string[] $dealInsightsFields
*/
public function importOpportunityCrmFieldData(
array $opportunityData,
array $dealInsightsFields,
int $opportunityId
): void {
foreach ($dealInsightsFields as $fieldName) {
$field = $this->config->fields()->with('entities')
->where('crm_provider_id', $fieldName)
->where('object_type', Field::OBJECT_OPPORTUNITY)
->first();
if (! $field instanceof Field) {
$this->logger->warning('Field not found', [
'field' => $fieldName,
'opportunity_id' => $opportunityId,
]);
continue;
}
$entity = $field->getEntities()->first();
if (! $entity instanceof LayoutEntity) {
continue;
}
$fieldValue = $this->extractFieldValue($opportunityData, $fieldName);
$normalizedValue = $this->normalizeValue($field->getType(), (string) $fieldValue, true);
$field->data()
->updateOrCreate([
'crm_layout_entity_id' => $entity->id,
'crm_field_id' => $field->id,
'object_type' => 'opportunity',
'object_id' => $opportunityId,
], ['value' => $normalizedValue])
;
}
}
/**
* @inheritdoc
*/
public function syncContacts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
$cpContacts = $this->copperClient->contacts()->paginate([
'minimum_interaction_date' => $since->timestamp,
'sort_by' => 'date_modified',
]);
foreach ($cpContacts as $cpContact) {
// Only sync if previously imported.
if ($this->hasContact($cpContact['id'])) {
$this->importContact($cpContact);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
throw $exception;
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncContact(string $crmId): ?Contact
{
$cpContact = $this->copperClient->contacts()->find($crmId);
if (empty($cpContact)) {
return null;
}
return $this->importContact($cpContact);
}
/**
* @inheritdoc
*/
private function importContact($crmData): Contact
{
$account = null;
if ($crmData['company_id']) {
$account = $this->team
->crm
->accounts()
->where('crm_provider_id', (string) $crmData['company_id'])
->first();
if ($account === null) {
$account = $this->syncAccount($crmData['company_id']);
}
}
$countryCode = null;
if (empty($crmData['address']) === false && $crmData['address']['country']) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$mobilePhone = $parsedNumber = null;
foreach ($crmData['phone_numbers'] as $phoneNumber) {
if ($phoneNumber['category'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);
} else {
$parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);
}
}
$email = null;
if (empty($crmData['emails']) === false) {
$email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'account_id' => $account->id ?? null,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => $crmData['name'],
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'mobile_phone' => $mobilePhone ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'title' => $crmData['title'],
'country_code' => $countryCode,
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Contact::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
private function buildContactPhone(?string $countryCode, ?string $number): ?array
{
if ($number) {
// Trim to our width and attempt to parse it.
$number = mb_strimwidth($number, 0, 25);
$parsedNumber = parsePhoneNumber($countryCode, $number);
} else {
$parsedNumber = [];
}
return $parsedNumber;
}
private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string
{
return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
$organization = $this->copperClient->organisation()->all();
if ($this->config->crm_provider_id !== $organization['id']) {
$this->config->update(['crm_provider_id' => $organization['id']]);
}
}
private function syncCustomFields(): void
{
foreach ($this->getFieldTypes() as $fieldType) {
$currentFields = $this->getFields($fieldType);
foreach ($currentFields as $field) {
/** @var Field $field */
$field = $this->config->fields()->updateOrCreate([
'crm_provider_id' => $field['name'],
'object_type' => $fieldType,
], [
'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),
'type' => $field['type'],
]);
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
}
$this->config->save();
}
protected function getFieldTypes(): array
{
return [
parent::OBJECT_TASK,
parent::OBJECT_LEAD,
parent::OBJECT_ACCOUNT,
parent::OBJECT_CONTACT,
parent::OBJECT_OPPORTUNITY,
];
}
/**
* @inheritdoc
*/
public function syncProfiles(?User $userToSearch = null): ?Profile
{
$profiles = $this->copperClient->users()->all();
foreach ($profiles as $profile) {
$user = $this->userRepository->findByTeamAndEmailAddress($this->team, $profile['email'], onlyActive: true);
// Only import profiles for users we have locally.
if ($user) {
$profile = $user->crmProfile()->updateOrCreate([
'crm_configuration_id' => $this->config->id,
'crm_provider_id' => $profile['id'],
]);
if ($userToSearch && $userToSearch->id === $user->id) {
return $profile;
}
}
}
return null;
}
/**
* @inheritdoc
*/
public function syncProfileFields(): void
{
$fieldTypes = [
'task',
'lead',
'account',
'contact',
'opportunity',
];
foreach ($fieldTypes as $fieldType) {
try {
$currentFields = $this->getFields(ucfirst($fieldType));
$newFields = array_column($currentFields, 'name');
$changedFields = array_merge(
array_diff($this->profile->getFieldsAsArray($fieldType), $newFields),
array_diff($newFields, $this->profile->getFieldsAsArray($fieldType))
);
if (\count($changedFields) > 0) {
$fields = implode(',', $newFields);
$this->logger->debug(
ucfirst($fieldType)
. ' fields changed from '
. $this->profile->{$fieldType . '_fields'}
. ' to: '
. $fields
);
$this->profile->{$fieldType . '_fields'} = $fields;
}
} catch (\Exception $exception) {
$this->logger->error('No access to ' . $fieldType . ' object, skipping...');
continue;
}
}
$this->profile->save();
}
/**
* @inheritdoc
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
$scopeValues = array_map(fn ($scope) => is_string($scope) ? $scope : $scope->value, $scopes);
$cacheKey = sprintf('copper-search-%d-%s-%s-%d-%d', $this->team->id, $name, implode('-', $scopeValues), $count, $offset);
return Cache::remember($cacheKey, 300, function () use ($name, $scopes, $count, $offset) {
// Try local search first
$localResults = $this->searchLocally($name, $scopes, $count, $offset);
// If no local results, fall back to remote API search
if (empty($localResults)) {
return $this->searchRemotely($name, $scopes, $count, $offset);
}
return $localResults;
});
}
/**
* @inheritdoc
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
$contact = null;
$account = null;
if ($crmAccountId) {
$account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();
if ($account === null) {
$account = $this->syncAccount($crmAccountId);
}
}
if ($crmContactId) {
$contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();
if ($contact === null) {
$contact = $this->syncContact($crmContactId);
}
}
if ($contact || $account) {
if ($contact && $account === null) {
$account = $contact->account;
}
if ($account === null) {
return [];
}
$params = [
'company_ids' => [$account->crm_provider_id],
'status_ids' => [0], // The integer values are 0, 1, 2, 3, for "Open", "Won", "Lost", and "Abandoned".
'sort_by' => 'date_modified',
'sort_direction' => 'desc',
];
switch ($this->config->opportunity_assignment_rule) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['sort_by'] = 'date_modified';
$params['sort_direction'] = 'desc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['sort_by'] = 'date_created';
$params['sort_direction'] = 'desc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['sort_by'] = 'date_created';
$params['sort_direction'] = 'asc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['sort_by'] = 'date_modified';
$params['sort_direction'] = 'desc';
$params['status_ids'] = [0, 1, 2, 3];
}
$cpOpportunities = $this->copperClient->opportunities()->search($params);
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
foreach ($cpOpportunities as $cpOpportunity) {
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', (string) $cpOpportunity['pipeline_id'])
->first();
if ($businessProcess === null) {
// Import it.
$businessProcess = $this->importStages(
[Stage::TYPE_OPPORTUNITY],
$cpOpportunity['pipeline_stage_id']
);
}
$stage = $businessProcess
->stages()
->where('crm_provider_id', (string) $cpOpportunity['pipeline_stage_id'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $cpOpportunity['pipeline_stage_id']);
}
$recordType = $businessProcess->recordTypes()->first();
$record = [
'crmId' => $cpOpportunity['id'],
'name' => $cpOpportunity['name'],
'value' => currency_format($cpOpportunity['monetary_value'], $cpOpportunity['monetary_unit']),
'won' => $cpOpportunity['status'] === 'Won',
'stage' => [
'id' => $stage->id_string,
'name' => $stage->name,
],
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
if ($ownerId && isset($cpOpportunity['assignee_id']) && $cpOpportunity['assignee_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
}
if (! empty($ownerData)) {
return $ownerData;
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array
{
$data = $cpTasks = [];
switch ($objectType) {
case 'lead':
$cpTasks = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->relatedTasks($objectId)
);
break;
case 'account':
$cpTasks = $this->copperClient->accounts()->relatedTasks($objectId);
break;
case 'contact':
if ($opportunityId) {
$cpTasks = $this->copperClient->opportunities()->relatedTasks($opportunityId);
} elseif ($objectType === 'contact') {
$cpTasks = $this->copperClient->contacts()->relatedTasks($objectId);
}
break;
}
foreach ($cpTasks as $cpTask) {
// We only get the ID itself returned, so pull out the full object.
try {
$cpTask = $this->copperClient->tasks()->find($cpTask['id']);
} catch (Exception $exception) {
$this->logger->error('[Copper] Error fetching task', [
'resource_id' => $cpTask['id'],
'error' => $exception->getMessage(),
]);
continue;
}
// Only allow open tasks.
if ($cpTask['status'] === 'Open') {
$data[] = [
'crmId' => $cpTask['id'],
'subject' => $cpTask['name'],
'due' => $cpTask['due_date']
? Carbon::createFromTimestamp($cpTask['due_date'])->format('Y-m-d\TH:i:sO')
: null,
'type' => null,
];
}
}
return $data;
}
/**
* Try to find email address in CRM service
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$cpObjectType = 'contact';
$cpObjects = $this->copperClient->contacts()->search([
'emails' => $email,
'sort_by' => 'date_modified',
'sort_direction' => 'desc',
]);
if (empty($cpObjects)) {
$cpObjectType = 'lead';
$cpObjects = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->search([
'emails' => ...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
45375
|
1625
|
25
|
2026-05-14T14:33:24.529049+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769204529_m1.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
11
72
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Copper;
use Carbon\Carbon;
use Exception;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Support\Facades\Cache;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\CopperInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Crm\LayoutEntity;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Repositories\UserRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Copper\Api\Client;
use Jiminny\Services\Crm\Copper\Api\ClientFactory;
use Jiminny\Services\Crm\Copper\Exception\RequestFailedException;
use Jiminny\Services\Crm\Helpers\FilterJoinedParticipants;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\Copper\Traits\SearchesCrmEntities;
use Jiminny\Utils\CurrencyFormatter;
use Jiminny\Utils\StringUtil;
class Service extends BaseService implements
CopperInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
RemoteEntityManipulationInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use SearchesCrmEntities;
private const int NOTE_BODY_MAX_LENGTH = 3000000;
private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day
private const array STANDARD_OPPORTUNITY_FIELDS = [
'monetary_value' => [
'label' => 'Value',
'available_on' => Field::OBJECT_OPPORTUNITY,
'type' => Field::TYPE_CURRENCY,
],
'pipeline_stage_id' => [
'label' => 'Stage',
'type' => Field::TYPE_PICKLIST,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
'close_date' => [
'label' => 'Close date',
'type' => Field::TYPE_DATE,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
'win_probability' => [
'label' => 'Win probability',
'type' => Field::TYPE_NUMBER,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
];
private const string UNSUPPORTED_OBJECT_TYPE = 'unsupported';
private const string OPPORTUNITY_STATUS_OPEN = 'Open';
private const string OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE = 'Opportunity import failed';
private const string RESOURCE_UPDATE_FAILED_ERROR_MESSAGE = 'Failed to update resource';
private FieldValueConverter $fieldValueConverter;
private ClientFactory $clientFactory;
private ?Client $copperClient = null;
public function __construct(
ClientFactory $clientFactory,
FieldValueConverter $fieldValueConverter,
private readonly UserRepository $userRepository,
private readonly ProspectPhotoPathService $prospectPhotoPathService,
private readonly CrmEntityRepository $crmEntityRepository
) {
parent::__construct();
$this->clientFactory = $clientFactory;
$this->fieldValueConverter = $fieldValueConverter;
}
public function getDisplayName(): string
{
return 'Copper';
}
/**
* Get the CRM entity repository (used by SearchesCrmEntities trait)
*/
protected function getCrmEntityRepository(): CrmEntityRepository
{
return $this->crmEntityRepository;
}
public function getMinimumApiVersion(): string
{
return Client::MIN_API_VERSION;
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
$owner = $user->team->owner;
return $owner->getSocialAccount(SocialAccount::PROVIDER_COPPER);
}
public function setUser(User $user): void
{
$this->configureSentryScope($user);
$this->team = $user->getTeam();
$this->teamService->setTeam($user->getTeam());
$this->setConfiguration($user->getTeam()->getCrmConfiguration());
// Reset state.
$this->profile = $user->getProfile();
if (! $this->profile instanceof Profile) {
// Try to fetch their profile, maybe it was not yet imported?
$this->profile = $this->getProfile($user);
}
}
public function setConfiguration(Configuration $configuration): void
{
$this->config = $configuration;
$this->copperClient = $this->clientFactory->create($configuration);
if ($this->team === null) {
$this->team = $configuration->getTeam();
}
}
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);
}
private function mapObjectType(string $objectType): string
{
$objectType = strtolower($objectType);
switch ($objectType) {
case Field::OBJECT_TASK:
case Field::OBJECT_OPPORTUNITY:
case Field::OBJECT_LEAD:
$mappedType = $objectType;
break;
case Field::OBJECT_ACCOUNT:
$mappedType = 'company';
break;
case Field::OBJECT_CONTACT:
$mappedType = 'person';
break;
default:
$mappedType = self::UNSUPPORTED_OBJECT_TYPE;
break;
}
return $mappedType;
}
/**
* @param string $crmObject The name of the CRM object. i.e. Opportunity or Contact
*/
protected function getFields(string $crmObject): array
{
$mappedObjectType = $this->mapObjectType($crmObject);
if (! $this->isSupportedObjectType($mappedObjectType)) {
return [];
}
$customFields = $this->copperClient->fields()->all();
$filteredFields = array_filter(
$customFields,
static fn ($field) => in_array($mappedObjectType, $field['available_on'], true)
);
return array_map(
fn (array $property) => [
'name' => $property['id'],
'label' => $property['name'],
'type' => $this->convertFieldType($property['data_type']),
],
$filteredFields
);
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
// Setup the activity field as the default Type.
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'type',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldFilters = FieldDefinitions::taskFollowupFieldsFilter();
foreach ($fieldFilters as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
public function syncFields(): void
{
$this->syncStandardFields();
$this->syncCustomFields();
}
public function syncField(Field $field): void
{
if ($field->getCrmProviderId() === 'type') {
/**
* This field is a special case, it is not a custom field and is not returned by the Copper API.
*
* The field is created manually during layout setup.
*
* @see getDefaultFields()
*
* There is a separate endpoint to get the activity types.
* @see importPicklistValues()
*/
return;
}
if ($field->getCrmProviderId() === 'pipeline_stage_id') {
// Not a custom type
return;
}
$crmField = $this->copperClient->fields()->find($field->getCrmProviderId());
$field->label = $crmField['name'];
$field->type = $this->convertFieldType($crmField['data_type']);
$field->save();
}
/**
* @param string $fieldType How the data should be input
*/
private function convertFieldType(string $fieldType): string
{
$fieldType = strtolower($fieldType);
switch ($fieldType) {
case 'dropdown':
$convertedType = Field::TYPE_PICKLIST;
break;
case 'string':
$convertedType = Field::TYPE_TEXT;
break;
case 'float':
case 'percentage':
$convertedType = Field::TYPE_NUMBER;
break;
case 'text':
$convertedType = Field::TYPE_TEXTAREA;
break;
case 'checkbox':
$convertedType = Field::TYPE_BOOLEAN;
break;
case Field::TYPE_DATE:
case Field::TYPE_CURRENCY:
case Field::TYPE_URL:
$convertedType = $fieldType;
break;
default:
$convertedType = Field::TYPE_UNSUPPORTED;
break;
}
return $convertedType;
}
/**
* @inheritdoc
*/
public function importPicklistValues(Field $field): array
{
$fieldValues = [];
if ($field->object_type === 'opportunity' && $field->crm_provider_id === 'pipeline_stage_id') {
return $this->importFieldValuesForDealInsights($field);
}
$values = [];
if ($field->object_type === Field::OBJECT_TASK && $field->crm_provider_id === 'type') {
$activityTypes = $this->copperClient->activityTypes()->all();
/**
* We ignore "system" activity types, disabled activity types and the "Note" activity type.
*/
$activityTypes = array_filter(
$activityTypes['user'],
fn (array $activityType) => ! $activityType['is_disabled'] && $activityType['id'] !== 0
);
// Import all activity values.
$i = 0;
foreach ($activityTypes as $activityType) {
$values[] = [
'value' => $activityType['id'],
'label' => mb_strimwidth($activityType['name'], 0, Field::LABEL_MAX_LENGTH),
'sequence' => $i++,
];
}
} else {
// We just check for the field in the custom definitions.
$crmField = $this->copperClient->fields()->find($field->crm_provider_id);
// Import all values.
foreach ($crmField['options'] as $option) {
$values[] = [
'value' => $option['id'],
'label' => mb_strimwidth($option['name'], 0, 191),
'sequence' => $option['rank'],
];
}
}
// Take the existing set of field values.
$fieldsToPurge = $field->values()->get()->pluck('value')->toArray();
foreach ($values as $value) {
// For all current values, upsert the field.
$value['value'] = substr($value['value'] ?? '', 0, 255);
$fieldValues[] = $field->values()->updateOrCreate([
'value' => $value['value'],
], $value);
// Remove this value from the ones we are going to purge.
$key = array_search($value['value'], $fieldsToPurge, false);
if ($key !== false) {
unset($fieldsToPurge[$key]);
}
}
// Delete the old values that are no longer used.
$field->values()->whereIn('value', $fieldsToPurge)->delete();
return $fieldValues;
}
/**
*
* @return FieldValue[]
*/
private function importFieldValuesForDealInsights(Field $field): array
{
$fieldValues = [];
$pipelines = $this->copperClient->pipelines()->all();
foreach ($pipelines as $pipeline) {
foreach ($pipeline['stages'] as $i => $dealStage) {
$fieldValues[] = $field->values()->updateOrCreate(
['value' => $dealStage['id']],
[
'label' => $dealStage['name'],
'sequence' => $i,
]
);
}
}
return $fieldValues;
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
if ($types === null) {
$types = [Stage::TYPE_LEAD, Stage::TYPE_OPPORTUNITY];
}
$missingStage = null;
foreach ($types as $type) {
if ($type === Stage::TYPE_LEAD) {
$statuses = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leadStatuses()->all()
);
if (count($statuses) > 0) {
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => BusinessProcess::TYPE_LEAD,
], [
'team_id' => $this->team->id,
'name' => BusinessProcess::TYPE_LEAD,
'type' => BusinessProcess::TYPE_LEAD,
'is_selectable' => true,
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => BusinessProcess::TYPE_LEAD,
], [
'team_id' => $this->team->id,
'name' => BusinessProcess::TYPE_LEAD,
'is_selectable' => true,
'business_process_id' => $businessProcess->id ?? null,
]);
$leadStatuses = [];
foreach ($statuses as $status) {
// Upsert all statuses for the team.
$status = $this->config->stages()->updateOrCreate([
'crm_provider_id' => $status['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($status['name'], 0, 50),
'label' => mb_strimwidth($status['name'], 0, 191),
'type' => Stage::TYPE_LEAD,
'sequence' => $status['order'],
'is_selectable' => true,
]);
if ($missingStageName && $missingStageName === $status['id']) {
$missingStage = $status;
}
$leadStatuses[] = $status['id'];
}
$businessProcess->stages()->sync($leadStatuses);
}
} else {
// We create a business process to contain the pipeline, and later store all stages against it.
foreach ($this->copperClient->pipelines()->all() as $pipeline) {
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $pipeline['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($pipeline['name'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => true,
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $pipeline['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($pipeline['name'], 0, 150),
'is_selectable' => true,
'business_process_id' => $businessProcess->id ?? null,
]);
$stages = [];
foreach ($pipeline['stages'] as $i => $dealStage) {
// Upsert all stages for the team.
$stage = $this->config->stages()->updateOrCreate([
'crm_provider_id' => $dealStage['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($dealStage['name'], 0, 50),
'label' => mb_strimwidth($dealStage['name'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $i,
'is_selectable' => true,
'probability' => $dealStage['win_probability'],
]);
if ($missingStageName && $missingStageName === $dealStage['id']) {
$missingStage = $stage;
}
$stages[] = $stage['id'];
}
$businessProcess->stages()->sync($stages);
}
}
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int
{
$syncCount = 0;
$cpLeads = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->paginate([
'minimum_modified_date' => $since->timestamp,
'sort_by' => 'date_modified',
])
);
foreach ($cpLeads as $cpLead) {
// Only sync if previously imported.
if ($this->hasLead($cpLead['id']) === false) {
$this->importLead($cpLead);
$syncCount++;
}
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncLead(string $crmId): ?Lead
{
$cpLead = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->find($crmId)
);
if (\count($cpLead) === 0) {
return null;
}
return $this->importLead($cpLead);
}
/**
* @inheritdoc
*/
private function importLead($crmData): ?Lead
{
$countryCode = null;
if (! empty($crmData['address']) && isset($crmData['address']['country'])) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$mobilePhone = $parsedNumber = null;
if (! empty($crmData['phone_numbers'])) {
foreach ($crmData['phone_numbers'] as $phoneNumber) {
if ($phoneNumber['category'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);
} else {
$parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);
}
}
}
$name = $crmData['name'];
if (empty($crmData['company_name'])) {
$company = 'Unknown';
} else {
$company = mb_strimwidth($crmData['company_name'], 0, 191);
}
$domain = null;
if (empty($crmData['websites']) === false) {
$domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);
$domain = StringUtil::resolveDomain($domain);
}
$email = null;
if (empty($crmData['email']) === false) {
$email = mb_strimwidth($crmData['email']['email'], 0, 80);
}
$stage = $this->config
->stages()
->where('crm_provider_id', (string) $crmData['status_id'])
->where('type', Stage::TYPE_LEAD)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_LEAD], $crmData['status_id']);
}
if (! $stage instanceof Stage) {
return null;
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($name, 0, 191),
'company' => $company,
'domain' => $domain,
'title' => $crmData['title'] ? mb_strimwidth($crmData['title'], 0, 128) : null,
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'mobile_phone' => $mobilePhone,
'stage_id' => $stage->id,
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Lead::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'country_code' => $countryCode,
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->leads()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
/**
* @inheritdoc
*/
public function syncAccounts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
$cpAccounts = $this->copperClient->accounts()->paginate([
'minimum_modified_date' => $since->timestamp,
'sort_by' => 'date_modified',
]);
foreach ($cpAccounts as $cpAccount) {
// Only sync if previously imported.
if ($this->hasAccount($cpAccount['id'])) {
$this->importAccount($cpAccount);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncAccount(string $crmId): ?Account
{
$cpAccount = $this->copperClient->accounts()->find($crmId);
if (empty($cpAccount)) {
return null;
}
return $this->importAccount($cpAccount);
}
/**
* @inheritdoc
*/
private function importAccount($crmData): Account
{
$countryCode = null;
if (empty($crmData['address']) === false && $crmData['address']['country']) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$name = $crmData['name'];
$parsedNumber = null;
foreach ($crmData['phone_numbers'] as $phoneNumber) {
$parsedNumber = parsePhoneNumber($countryCode, $phoneNumber['number']);
}
$domain = null;
if (empty($crmData['websites']) === false) {
$domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);
$domain = StringUtil::resolveDomain($domain);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($name, 0, 191),
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Account::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'country_code' => $countryCode,
'domain' => $domain,
'phone' => $parsedNumber['phone'] ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->accounts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
public function syncOpportunities(array $parameters, ?string $strategy = null): int
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->copperClient,
]);
$strategies = $strategyResolver->getStrategies($this->config, $strategy);
$syncCount = 0;
try {
foreach ($strategies as $syncStrategy) {
foreach ($syncStrategy->fetchOpportunities($parameters) as $opportunityData) {
$this->importOpportunity($opportunityData);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
$this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => $exception->getMessage(),
]);
}
return $syncCount;
}
public function syncOpportunity(string $crmId): ?Opportunity
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->copperClient,
]);
$strategy = $strategyResolver->resolve(
$this->config,
OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY
);
$parameters['crm_id'] = $crmId;
$cpOpportunity = $strategy->fetchOpportunities($parameters);
return $this->importOpportunity($cpOpportunity);
}
private function importOpportunity($crmData): ?Opportunity
{
$companyId = (string) $crmData['company_id'];
if (empty($companyId)) {
$this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => 'No company id',
]);
return null;
}
$account = $this->config->accounts()->where('crm_provider_id', $companyId)->first();
if ($account === null) {
$account = $this->syncAccount($companyId);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', (string) $crmData['pipeline_id'])
->first();
if ($businessProcess === null) {
// It is possible for some deals to not be in a pipeline.
$this->logger->warning(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => 'Missing pipeline',
]);
return null;
}
$stage = $businessProcess
->stages()
->where('crm_provider_id', (string) $crmData['pipeline_stage_id'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
$this->logger->info('Stage not found, importing', [
'pipeline_id' => $crmData['pipeline_id'],
'stage_id' => $crmData['pipeline_stage_id'],
]);
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData['pipeline_stage_id']);
}
$recordType = $businessProcess->recordTypes()->first();
$closeDate = null;
$isClosed = $crmData['status'] !== self::OPPORTUNITY_STATUS_OPEN;
if ($crmData['close_date']) {
$closeDate = Carbon::parse($crmData['close_date'])->format('Y-m-d');
}
$data = [
'team_id' => $this->team->getId(),
'account_id' => $account->id,
'user_id' => $profile->user_id ?? null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($crmData['name'], 0, 128),
'value' => $crmData['monetary_value'],
'currency_code' => CurrencyFormatter::formatCode($crmData['monetary_unit']),
'close_date' => $closeDate,
'is_closed' => $isClosed,
'is_won' => $crmData['status'] === 'Won',
'stage_id' => $stage->id,
'record_type_id' => $recordType->id ?? null,
'remotely_created_at' => $crmData['date_created'],
];
/** @var Opportunity $opportunity */
$opportunity = $this->config
->opportunities()
->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data)
;
// import external fields into crm_field_data if present
$dealInsightsFields = $this->getOpportunitySyncableFields();
$this->importOpportunityCrmFieldData($crmData, $dealInsightsFields, $opportunity->id);
return $opportunity;
}
/**
* @param array<string, mixed> $opportunityData
* @param string[] $dealInsightsFields
*/
public function importOpportunityCrmFieldData(
array $opportunityData,
array $dealInsightsFields,
int $opportunityId
): void {
foreach ($dealInsightsFields as $fieldName) {
$field = $this->config->fields()->with('entities')
->where('crm_provider_id', $fieldName)
->where('object_type', Field::OBJECT_OPPORTUNITY)
->first();
if (! $field instanceof Field) {
$this->logger->warning('Field not found', [
'field' => $fieldName,
'opportunity_id' => $opportunityId,
]);
continue;
}
$entity = $field->getEntities()->first();
if (! $entity instanceof LayoutEntity) {
continue;
}
$fieldValue = $this->extractFieldValue($opportunityData, $fieldName);
$normalizedValue = $this->normalizeValue($field->getType(), (string) $fieldValue, true);
$field->data()
->updateOrCreate([
'crm_layout_entity_id' => $entity->id,
'crm_field_id' => $field->id,
'object_type' => 'opportunity',
'object_id' => $opportunityId,
], ['value' => $normalizedValue])
;
}
}
/**
* @inheritdoc
*/
public function syncContacts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
$cpContacts = $this->copperClient->contacts()->paginate([
'minimum_interaction_date' => $since->timestamp,
'sort_by' => 'date_modified',
]);
foreach ($cpContacts as $cpContact) {
// Only sync if previously imported.
if ($this->hasContact($cpContact['id'])) {
$this->importContact($cpContact);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
throw $exception;
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncContact(string $crmId): ?Contact
{
$cpContact = $this->copperClient->contacts()->find($crmId);
if (empty($cpContact)) {
return null;
}
return $this->importContact($cpContact);
}
/**
* @inheritdoc
*/
private function importContact($crmData): Contact
{
$account = null;
if ($crmData['company_id']) {
$account = $this->team
->crm
->accounts()
->where('crm_provider_id', (string) $crmData['company_id'])
->first();
if ($account === null) {
$account = $this->syncAccount($crmData['company_id']);
}
}
$countryCode = null;
if (empty($crmData['address']) === false && $crmData['address']['country']) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$mobilePhone = $parsedNumber = null;
foreach ($crmData['phone_numbers'] as $phoneNumber) {
if ($phoneNumber['category'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);
} else {
$parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);
}
}
$email = null;
if (empty($crmData['emails']) === false) {
$email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'account_id' => $account->id ?? null,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => $crmData['name'],
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'mobile_phone' => $mobilePhone ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'title' => $crmData['title'],
'country_code' => $countryCode,
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Contact::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
private function buildContactPhone(?string $countryCode, ?string $number): ?array
{
if ($number) {
// Trim to our width and attempt to parse it.
$number = mb_strimwidth($number, 0, 25);
$parsedNumber = parsePhoneNumber($countryCode, $number);
} else {
$parsedNumber = [];
}
return $parsedNumber;
}
private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string
{
return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
$organization = $this->copperClient->organisation()->all();
if ($this->config->crm_provider_id !== $organization['id']) {
$this->config->update(['crm_provider_id' => $organization['id']]);
}
}
private function syncCustomFields(): void
{
foreach ($this->getFieldTypes() as $fieldType) {
$currentFields = $this->getFields($fieldType);
foreach ($currentFields as $field) {
/** @var Field $field */
$field = $this->config->fields()->updateOrCreate([
'crm_provider_id' => $field['name'],
'object_type' => $fieldType,
], [
'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),
'type' => $field['type'],
]);
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
}
$this->config->save();
}
protected function getFieldTypes(): array
{
return [
parent::OBJECT_TASK,
parent::OBJECT_LEAD,
parent::OBJECT_ACCOUNT,
parent::OBJECT_CONTACT,
parent::OBJECT_OPPORTUNITY,
];
}
/**
* @inheritdoc
*/
public function syncProfiles(?User $userToSearch = null): ?Profile
{
$profiles = $this->copperClient->users()->all();
foreach ($profiles as $profile) {
$user = $this->userRepository->findByTeamAndEmailAddress($this->team, $profile['email'], onlyActive: true);
// Only import profiles for users we have locally.
if ($user) {
$profile = $user->crmProfile()->updateOrCreate([
'crm_configuration_id' => $this->config->id,
'crm_provider_id' => $profile['id'],
]);
if ($userToSearch && $userToSearch->id === $user->id) {
return $profile;
}
}
}
return null;
}
/**
* @inheritdoc
*/
public function syncProfileFields(): void
{
$fieldTypes = [
'task',
'lead',
'account',
'contact',
'opportunity',
];
foreach ($fieldTypes as $fieldType) {
try {
$currentFields = $this->getFields(ucfirst($fieldType));
$newFields = array_column($currentFields, 'name');
$changedFields = array_merge(
array_diff($this->profile->getFieldsAsArray($fieldType), $newFields),
array_diff($newFields, $this->profile->getFieldsAsArray($fieldType))
);
if (\count($changedFields) > 0) {
$fields = implode(',', $newFields);
$this->logger->debug(
ucfirst($fieldType)
. ' fields changed from '
. $this->profile->{$fieldType . '_fields'}
. ' to: '
. $fields
);
$this->profile->{$fieldType . '_fields'} = $fields;
}
} catch (\Exception $exception) {
$this->logger->error('No access to ' . $fieldType . ' object, skipping...');
continue;
}
}
$this->profile->save();
}
/**
* @inheritdoc
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
$scopeValues = array_map(fn ($scope) => is_string($scope) ? $scope : $scope->value, $scopes);
$cacheKey = sprintf('copper-search-%d-%s-%s-%d-%d', $this->team->id, $name, implode('-', $scopeValues), $count, $offset);
return Cache::remember($cacheKey, 300, function () use ($name, $scopes, $count, $offset) {
// Try local search first
$localResults = $this->searchLocally($name, $scopes, $count, $offset);
// If no local results, fall back to remote API search
if (empty($localResults)) {
return $this->searchRemotely($name, $scopes, $count, $offset);
}
return $localResults;
});
}
/**
* @inheritdoc
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
$contact = null;
$account = null;
if ($crmAccountId) {
$account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();
if ($account === null) {
$account = $this->syncAccount($crmAccountId);
}
}
if ($crmContactId) {
$contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();
if ($contact === null) {
$contact = $this->syncContact($crmContactId);
}
}
if ($contact || $account) {
if ($contact && $account === null) {
$account = $contact->account;
}
if ($account === null) {
return [];
}
$params = [
'company_ids' => [$account->crm_provider_id],
'status_ids' => [0], // The integer values are 0, 1, 2, 3, for "Open", "Won", "Lost", and "Abandoned".
'sort_by' => 'date_modified',
'sort_direction' => 'desc',
];
switch ($this->config->opportunity_assignment_rule) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['sort_by'] = 'date_modified';
$params['sort_direction'] = 'desc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['sort_by'] = 'date_created';
$params['sort_direction'] = 'desc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['sort_by'] = 'date_created';
$params['sort_direction'] = 'asc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['sort_by'] = 'date_modified';
$params['sort_direction'] = 'desc';
$params['status_ids'] = [0, 1, 2, 3];
}
$cpOpportunities = $this->copperClient->opportunities()->search($params);
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
foreach ($cpOpportunities as $cpOpportunity) {
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', (string) $cpOpportunity['pipeline_id'])
->first();
if ($businessProcess === null) {
// Import it.
$businessProcess = $this->importStages(
[Stage::TYPE_OPPORTUNITY],
$cpOpportunity['pipeline_stage_id']
);
}
$stage = $businessProcess
->stages()
->where('crm_provider_id', (string) $cpOpportunity['pipeline_stage_id'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $cpOpportunity['pipeline_stage_id']);
}
$recordType = $businessProcess->recordTypes()->first();
$record = [
'crmId' => $cpOpportunity['id'],
'name' => $cpOpportunity['name'],
'value' => currency_format($cpOpportunity['monetary_value'], $cpOpportunity['monetary_unit']),
'won' => $cpOpportunity['status'] === 'Won',
'stage' => [
'id' => $stage->id_string,
'name' => $stage->name,
],
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
if ($ownerId && isset($cpOpportunity['assignee_id']) && $cpOpportunity['assignee_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
}
if (! empty($ownerData)) {
return $ownerData;
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array
{
$data = $cpTasks = [];
switch ($objectType) {
case 'lead':
$cpTasks = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->relatedTasks($objectId)
);
break;
case 'account':
$cpTasks = $this->copperClient->accounts()->relatedTasks($objectId);
break;
case 'contact':
if ($opportunityId) {
$cpTasks = $this->copperClient->opportunities()->relatedTasks($opportunityId);
} elseif ($objectType === 'contact') {
$cpTasks = $this->copperClient->contacts()->relatedTasks($objectId);
}
break;
}
foreach ($cpTasks as $cpTask) {
// We only get the ID itself returned, so pull out the full object.
try {
$cpTask = $this->copperClient->tasks()->find($cpTask['id']);
} catch (Exception $exception) {
$this->logger->error('[Copper] Error fetching task', [
'resource_id' => $cpTask['id'],
'error' => $exception->getMessage(),
]);
continue;
}
// Only allow open tasks.
if ($cpTask['status'] === 'Open') {
$data[] = [
'crmId' => $cpTask['id'],
'subject' => $cpTask['name'],
'due' => $cpTask['due_date']
? Carbon::createFromTimestamp($cpTask['due_date'])->format('Y-m-d\TH:i:sO')
: null,
'type' => null,
];
}
}
return $data;
}
/**
* Try to find email address in CRM service
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$cpObjectType = 'contact';
$cpObjects = $this->copperClient->contacts()->search([
'emails' => $email,
'sort_by' => 'date_modified',
'sort_direction' => 'desc',
]);
if (empty($cpObjects)) {
$cpObjectType = 'lead';
$cpObjects = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->search([
'emails' => ...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.054166667,"top":0.027777778,"width":0.08055556,"height":0.035555556},"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":"#12066 on JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.13472222,"top":0.027777778,"width":0.25555557,"height":0.035555556},"on_screen":true,"help_text":"Pull request #12066 exists for current branch JY-20725-handle-HS-search-rate-limit, but local branch is out of sync with remote","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.6326389,"top":0.027777778,"width":0.023611112,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.6645833,"top":0.027777778,"width":0.15902779,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.82361114,"top":0.027777778,"width":0.023611112,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.8472222,"top":0.027777778,"width":0.023611112,"height":0.035555556},"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.87083334,"top":0.027777778,"width":0.023611112,"height":0.035555556},"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.9291667,"top":0.027777778,"width":0.023611112,"height":0.035555556},"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.9527778,"top":0.027777778,"width":0.023611112,"height":0.035555556},"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.9763889,"top":0.027777778,"width":0.023611112,"height":0.035555556},"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":"11","depth":4,"bounds":{"left":0.7340278,"top":0.3122222,"width":0.01875,"height":0.02111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"72","depth":4,"bounds":{"left":0.7569444,"top":0.3122222,"width":0.020833334,"height":0.02111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.78194445,"top":0.3122222,"width":0.015277778,"height":0.02111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"bounds":{"left":0.80138886,"top":0.3122222,"width":0.016666668,"height":0.02111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.8215278,"top":0.31,"width":0.015277778,"height":0.025555555},"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.8368056,"top":0.31,"width":0.014583333,"height":0.025555555},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Crm\\Copper;\n\nuse Carbon\\Carbon;\nuse Exception;\nuse GuzzleHttp\\Exception\\ClientException;\nuse Illuminate\\Support\\Facades\\Cache;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\CopperInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Crm\\LayoutEntity;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Copper\\Api\\Client;\nuse Jiminny\\Services\\Crm\\Copper\\Api\\ClientFactory;\nuse Jiminny\\Services\\Crm\\Copper\\Exception\\RequestFailedException;\nuse Jiminny\\Services\\Crm\\Helpers\\FilterJoinedParticipants;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Services\\Crm\\Copper\\Traits\\SearchesCrmEntities;\nuse Jiminny\\Utils\\CurrencyFormatter;\nuse Jiminny\\Utils\\StringUtil;\n\nclass Service extends BaseService implements\n CopperInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n RemoteEntityManipulationInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n VerifyTaskExistsInterface\n{\n use SearchesCrmEntities;\n private const int NOTE_BODY_MAX_LENGTH = 3000000;\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n private const array STANDARD_OPPORTUNITY_FIELDS = [\n 'monetary_value' => [\n 'label' => 'Value',\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n 'type' => Field::TYPE_CURRENCY,\n ],\n 'pipeline_stage_id' => [\n 'label' => 'Stage',\n 'type' => Field::TYPE_PICKLIST,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n 'close_date' => [\n 'label' => 'Close date',\n 'type' => Field::TYPE_DATE,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n 'win_probability' => [\n 'label' => 'Win probability',\n 'type' => Field::TYPE_NUMBER,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n ];\n private const string UNSUPPORTED_OBJECT_TYPE = 'unsupported';\n private const string OPPORTUNITY_STATUS_OPEN = 'Open';\n private const string OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE = 'Opportunity import failed';\n private const string RESOURCE_UPDATE_FAILED_ERROR_MESSAGE = 'Failed to update resource';\n\n private FieldValueConverter $fieldValueConverter;\n private ClientFactory $clientFactory;\n private ?Client $copperClient = null;\n\n public function __construct(\n ClientFactory $clientFactory,\n FieldValueConverter $fieldValueConverter,\n private readonly UserRepository $userRepository,\n private readonly ProspectPhotoPathService $prospectPhotoPathService,\n private readonly CrmEntityRepository $crmEntityRepository\n ) {\n parent::__construct();\n\n $this->clientFactory = $clientFactory;\n $this->fieldValueConverter = $fieldValueConverter;\n }\n\n public function getDisplayName(): string\n {\n return 'Copper';\n }\n\n /**\n * Get the CRM entity repository (used by SearchesCrmEntities trait)\n */\n protected function getCrmEntityRepository(): CrmEntityRepository\n {\n return $this->crmEntityRepository;\n }\n\n public function getMinimumApiVersion(): string\n {\n return Client::MIN_API_VERSION;\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n $owner = $user->team->owner;\n\n return $owner->getSocialAccount(SocialAccount::PROVIDER_COPPER);\n }\n\n public function setUser(User $user): void\n {\n $this->configureSentryScope($user);\n\n $this->team = $user->getTeam();\n $this->teamService->setTeam($user->getTeam());\n $this->setConfiguration($user->getTeam()->getCrmConfiguration());\n\n // Reset state.\n $this->profile = $user->getProfile();\n\n if (! $this->profile instanceof Profile) {\n // Try to fetch their profile, maybe it was not yet imported?\n $this->profile = $this->getProfile($user);\n }\n }\n\n public function setConfiguration(Configuration $configuration): void\n {\n $this->config = $configuration;\n $this->copperClient = $this->clientFactory->create($configuration);\n\n if ($this->team === null) {\n $this->team = $configuration->getTeam();\n }\n }\n\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);\n }\n\n private function mapObjectType(string $objectType): string\n {\n $objectType = strtolower($objectType);\n\n switch ($objectType) {\n case Field::OBJECT_TASK:\n case Field::OBJECT_OPPORTUNITY:\n case Field::OBJECT_LEAD:\n $mappedType = $objectType;\n\n break;\n case Field::OBJECT_ACCOUNT:\n $mappedType = 'company';\n\n break;\n case Field::OBJECT_CONTACT:\n $mappedType = 'person';\n\n break;\n default:\n $mappedType = self::UNSUPPORTED_OBJECT_TYPE;\n\n break;\n }\n\n return $mappedType;\n }\n\n /**\n * @param string $crmObject The name of the CRM object. i.e. Opportunity or Contact\n */\n protected function getFields(string $crmObject): array\n {\n $mappedObjectType = $this->mapObjectType($crmObject);\n\n if (! $this->isSupportedObjectType($mappedObjectType)) {\n return [];\n }\n\n $customFields = $this->copperClient->fields()->all();\n\n $filteredFields = array_filter(\n $customFields,\n static fn ($field) => in_array($mappedObjectType, $field['available_on'], true)\n );\n\n return array_map(\n fn (array $property) => [\n 'name' => $property['id'],\n 'label' => $property['name'],\n 'type' => $this->convertFieldType($property['data_type']),\n ],\n $filteredFields\n );\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n // Setup the activity field as the default Type.\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'type',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n $fieldFilters = FieldDefinitions::taskFollowupFieldsFilter();\n\n foreach ($fieldFilters as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n public function syncFields(): void\n {\n $this->syncStandardFields();\n $this->syncCustomFields();\n }\n\n public function syncField(Field $field): void\n {\n if ($field->getCrmProviderId() === 'type') {\n /**\n * This field is a special case, it is not a custom field and is not returned by the Copper API.\n *\n * The field is created manually during layout setup.\n *\n * @see getDefaultFields()\n *\n * There is a separate endpoint to get the activity types.\n * @see importPicklistValues()\n */\n return;\n }\n\n if ($field->getCrmProviderId() === 'pipeline_stage_id') {\n // Not a custom type\n return;\n }\n\n $crmField = $this->copperClient->fields()->find($field->getCrmProviderId());\n $field->label = $crmField['name'];\n $field->type = $this->convertFieldType($crmField['data_type']);\n\n $field->save();\n }\n\n /**\n * @param string $fieldType How the data should be input\n */\n private function convertFieldType(string $fieldType): string\n {\n $fieldType = strtolower($fieldType);\n\n switch ($fieldType) {\n case 'dropdown':\n $convertedType = Field::TYPE_PICKLIST;\n\n break;\n case 'string':\n $convertedType = Field::TYPE_TEXT;\n\n break;\n case 'float':\n case 'percentage':\n $convertedType = Field::TYPE_NUMBER;\n\n break;\n case 'text':\n $convertedType = Field::TYPE_TEXTAREA;\n\n break;\n case 'checkbox':\n $convertedType = Field::TYPE_BOOLEAN;\n\n break;\n case Field::TYPE_DATE:\n case Field::TYPE_CURRENCY:\n case Field::TYPE_URL:\n $convertedType = $fieldType;\n\n break;\n default:\n $convertedType = Field::TYPE_UNSUPPORTED;\n\n break;\n }\n\n return $convertedType;\n }\n\n /**\n * @inheritdoc\n */\n public function importPicklistValues(Field $field): array\n {\n $fieldValues = [];\n\n if ($field->object_type === 'opportunity' && $field->crm_provider_id === 'pipeline_stage_id') {\n return $this->importFieldValuesForDealInsights($field);\n }\n\n $values = [];\n\n if ($field->object_type === Field::OBJECT_TASK && $field->crm_provider_id === 'type') {\n $activityTypes = $this->copperClient->activityTypes()->all();\n\n /**\n * We ignore \"system\" activity types, disabled activity types and the \"Note\" activity type.\n */\n $activityTypes = array_filter(\n $activityTypes['user'],\n fn (array $activityType) => ! $activityType['is_disabled'] && $activityType['id'] !== 0\n );\n\n // Import all activity values.\n $i = 0;\n foreach ($activityTypes as $activityType) {\n $values[] = [\n 'value' => $activityType['id'],\n 'label' => mb_strimwidth($activityType['name'], 0, Field::LABEL_MAX_LENGTH),\n 'sequence' => $i++,\n ];\n }\n } else {\n // We just check for the field in the custom definitions.\n $crmField = $this->copperClient->fields()->find($field->crm_provider_id);\n\n // Import all values.\n foreach ($crmField['options'] as $option) {\n $values[] = [\n 'value' => $option['id'],\n 'label' => mb_strimwidth($option['name'], 0, 191),\n 'sequence' => $option['rank'],\n ];\n }\n }\n\n // Take the existing set of field values.\n $fieldsToPurge = $field->values()->get()->pluck('value')->toArray();\n\n foreach ($values as $value) {\n // For all current values, upsert the field.\n $value['value'] = substr($value['value'] ?? '', 0, 255);\n $fieldValues[] = $field->values()->updateOrCreate([\n 'value' => $value['value'],\n ], $value);\n\n // Remove this value from the ones we are going to purge.\n $key = array_search($value['value'], $fieldsToPurge, false);\n if ($key !== false) {\n unset($fieldsToPurge[$key]);\n }\n }\n\n // Delete the old values that are no longer used.\n $field->values()->whereIn('value', $fieldsToPurge)->delete();\n\n return $fieldValues;\n }\n\n /**\n *\n * @return FieldValue[]\n */\n private function importFieldValuesForDealInsights(Field $field): array\n {\n $fieldValues = [];\n $pipelines = $this->copperClient->pipelines()->all();\n\n foreach ($pipelines as $pipeline) {\n foreach ($pipeline['stages'] as $i => $dealStage) {\n $fieldValues[] = $field->values()->updateOrCreate(\n ['value' => $dealStage['id']],\n [\n 'label' => $dealStage['name'],\n 'sequence' => $i,\n ]\n );\n }\n }\n\n return $fieldValues;\n }\n\n /**\n * @inheritdoc\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n if ($types === null) {\n $types = [Stage::TYPE_LEAD, Stage::TYPE_OPPORTUNITY];\n }\n $missingStage = null;\n\n foreach ($types as $type) {\n if ($type === Stage::TYPE_LEAD) {\n $statuses = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leadStatuses()->all()\n );\n\n if (count($statuses) > 0) {\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => BusinessProcess::TYPE_LEAD,\n ], [\n 'team_id' => $this->team->id,\n 'name' => BusinessProcess::TYPE_LEAD,\n 'type' => BusinessProcess::TYPE_LEAD,\n 'is_selectable' => true,\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => BusinessProcess::TYPE_LEAD,\n ], [\n 'team_id' => $this->team->id,\n 'name' => BusinessProcess::TYPE_LEAD,\n 'is_selectable' => true,\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n $leadStatuses = [];\n foreach ($statuses as $status) {\n // Upsert all statuses for the team.\n $status = $this->config->stages()->updateOrCreate([\n 'crm_provider_id' => $status['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($status['name'], 0, 50),\n 'label' => mb_strimwidth($status['name'], 0, 191),\n 'type' => Stage::TYPE_LEAD,\n 'sequence' => $status['order'],\n 'is_selectable' => true,\n ]);\n\n if ($missingStageName && $missingStageName === $status['id']) {\n $missingStage = $status;\n }\n\n $leadStatuses[] = $status['id'];\n }\n\n $businessProcess->stages()->sync($leadStatuses);\n }\n } else {\n // We create a business process to contain the pipeline, and later store all stages against it.\n foreach ($this->copperClient->pipelines()->all() as $pipeline) {\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => $pipeline['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($pipeline['name'], 0, 150),\n 'type' => BusinessProcess::TYPE_OPPORTUNITY,\n 'is_selectable' => true,\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => $pipeline['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($pipeline['name'], 0, 150),\n 'is_selectable' => true,\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n $stages = [];\n\n foreach ($pipeline['stages'] as $i => $dealStage) {\n // Upsert all stages for the team.\n $stage = $this->config->stages()->updateOrCreate([\n 'crm_provider_id' => $dealStage['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($dealStage['name'], 0, 50),\n 'label' => mb_strimwidth($dealStage['name'], 0, 191),\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'sequence' => $i,\n 'is_selectable' => true,\n 'probability' => $dealStage['win_probability'],\n ]);\n\n if ($missingStageName && $missingStageName === $dealStage['id']) {\n $missingStage = $stage;\n }\n\n $stages[] = $stage['id'];\n }\n\n $businessProcess->stages()->sync($stages);\n }\n }\n }\n\n return $missingStage;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int\n {\n $syncCount = 0;\n\n $cpLeads = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->paginate([\n 'minimum_modified_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ])\n );\n\n foreach ($cpLeads as $cpLead) {\n // Only sync if previously imported.\n if ($this->hasLead($cpLead['id']) === false) {\n $this->importLead($cpLead);\n $syncCount++;\n }\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLead(string $crmId): ?Lead\n {\n $cpLead = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->find($crmId)\n );\n\n if (\\count($cpLead) === 0) {\n return null;\n }\n\n return $this->importLead($cpLead);\n }\n\n /**\n * @inheritdoc\n */\n private function importLead($crmData): ?Lead\n {\n $countryCode = null;\n if (! empty($crmData['address']) && isset($crmData['address']['country'])) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $mobilePhone = $parsedNumber = null;\n if (! empty($crmData['phone_numbers'])) {\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n if ($phoneNumber['category'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);\n } else {\n $parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);\n }\n }\n }\n\n $name = $crmData['name'];\n\n if (empty($crmData['company_name'])) {\n $company = 'Unknown';\n } else {\n $company = mb_strimwidth($crmData['company_name'], 0, 191);\n }\n\n $domain = null;\n if (empty($crmData['websites']) === false) {\n $domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);\n $domain = StringUtil::resolveDomain($domain);\n }\n\n $email = null;\n if (empty($crmData['email']) === false) {\n $email = mb_strimwidth($crmData['email']['email'], 0, 80);\n }\n\n $stage = $this->config\n ->stages()\n ->where('crm_provider_id', (string) $crmData['status_id'])\n ->where('type', Stage::TYPE_LEAD)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_LEAD], $crmData['status_id']);\n }\n\n if (! $stage instanceof Stage) {\n return null;\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($name, 0, 191),\n 'company' => $company,\n 'domain' => $domain,\n 'title' => $crmData['title'] ? mb_strimwidth($crmData['title'], 0, 128) : null,\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'mobile_phone' => $mobilePhone,\n 'stage_id' => $stage->id,\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Lead::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'country_code' => $countryCode,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->leads()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n /**\n * @inheritdoc\n */\n public function syncAccounts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n $cpAccounts = $this->copperClient->accounts()->paginate([\n 'minimum_modified_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ]);\n\n foreach ($cpAccounts as $cpAccount) {\n // Only sync if previously imported.\n if ($this->hasAccount($cpAccount['id'])) {\n $this->importAccount($cpAccount);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncAccount(string $crmId): ?Account\n {\n $cpAccount = $this->copperClient->accounts()->find($crmId);\n\n if (empty($cpAccount)) {\n return null;\n }\n\n return $this->importAccount($cpAccount);\n }\n\n /**\n * @inheritdoc\n */\n private function importAccount($crmData): Account\n {\n $countryCode = null;\n if (empty($crmData['address']) === false && $crmData['address']['country']) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $name = $crmData['name'];\n\n $parsedNumber = null;\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n $parsedNumber = parsePhoneNumber($countryCode, $phoneNumber['number']);\n }\n\n $domain = null;\n if (empty($crmData['websites']) === false) {\n $domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);\n $domain = StringUtil::resolveDomain($domain);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($name, 0, 191),\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Account::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'country_code' => $countryCode,\n 'domain' => $domain,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->accounts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n public function syncOpportunities(array $parameters, ?string $strategy = null): int\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->copperClient,\n ]);\n $strategies = $strategyResolver->getStrategies($this->config, $strategy);\n\n $syncCount = 0;\n\n try {\n foreach ($strategies as $syncStrategy) {\n foreach ($syncStrategy->fetchOpportunities($parameters) as $opportunityData) {\n $this->importOpportunity($opportunityData);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n $this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => $exception->getMessage(),\n ]);\n }\n\n return $syncCount;\n }\n\n public function syncOpportunity(string $crmId): ?Opportunity\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->copperClient,\n ]);\n $strategy = $strategyResolver->resolve(\n $this->config,\n OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY\n );\n\n $parameters['crm_id'] = $crmId;\n\n $cpOpportunity = $strategy->fetchOpportunities($parameters);\n\n return $this->importOpportunity($cpOpportunity);\n }\n\n private function importOpportunity($crmData): ?Opportunity\n {\n $companyId = (string) $crmData['company_id'];\n\n if (empty($companyId)) {\n $this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => 'No company id',\n ]);\n\n return null;\n }\n\n $account = $this->config->accounts()->where('crm_provider_id', $companyId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($companyId);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', (string) $crmData['pipeline_id'])\n ->first();\n\n if ($businessProcess === null) {\n // It is possible for some deals to not be in a pipeline.\n $this->logger->warning(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => 'Missing pipeline',\n ]);\n\n return null;\n }\n\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', (string) $crmData['pipeline_stage_id'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n $this->logger->info('Stage not found, importing', [\n 'pipeline_id' => $crmData['pipeline_id'],\n 'stage_id' => $crmData['pipeline_stage_id'],\n ]);\n\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData['pipeline_stage_id']);\n }\n\n $recordType = $businessProcess->recordTypes()->first();\n $closeDate = null;\n $isClosed = $crmData['status'] !== self::OPPORTUNITY_STATUS_OPEN;\n\n if ($crmData['close_date']) {\n $closeDate = Carbon::parse($crmData['close_date'])->format('Y-m-d');\n }\n\n $data = [\n 'team_id' => $this->team->getId(),\n 'account_id' => $account->id,\n 'user_id' => $profile->user_id ?? null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($crmData['name'], 0, 128),\n 'value' => $crmData['monetary_value'],\n 'currency_code' => CurrencyFormatter::formatCode($crmData['monetary_unit']),\n 'close_date' => $closeDate,\n 'is_closed' => $isClosed,\n 'is_won' => $crmData['status'] === 'Won',\n 'stage_id' => $stage->id,\n 'record_type_id' => $recordType->id ?? null,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n /** @var Opportunity $opportunity */\n $opportunity = $this->config\n ->opportunities()\n ->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data)\n ;\n\n // import external fields into crm_field_data if present\n $dealInsightsFields = $this->getOpportunitySyncableFields();\n $this->importOpportunityCrmFieldData($crmData, $dealInsightsFields, $opportunity->id);\n\n return $opportunity;\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n * @param string[] $dealInsightsFields\n */\n public function importOpportunityCrmFieldData(\n array $opportunityData,\n array $dealInsightsFields,\n int $opportunityId\n ): void {\n foreach ($dealInsightsFields as $fieldName) {\n $field = $this->config->fields()->with('entities')\n ->where('crm_provider_id', $fieldName)\n ->where('object_type', Field::OBJECT_OPPORTUNITY)\n ->first();\n\n if (! $field instanceof Field) {\n $this->logger->warning('Field not found', [\n 'field' => $fieldName,\n 'opportunity_id' => $opportunityId,\n ]);\n\n continue;\n }\n\n $entity = $field->getEntities()->first();\n\n if (! $entity instanceof LayoutEntity) {\n continue;\n }\n\n $fieldValue = $this->extractFieldValue($opportunityData, $fieldName);\n $normalizedValue = $this->normalizeValue($field->getType(), (string) $fieldValue, true);\n\n $field->data()\n ->updateOrCreate([\n 'crm_layout_entity_id' => $entity->id,\n 'crm_field_id' => $field->id,\n 'object_type' => 'opportunity',\n 'object_id' => $opportunityId,\n ], ['value' => $normalizedValue])\n ;\n }\n }\n\n /**\n * @inheritdoc\n */\n public function syncContacts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n $cpContacts = $this->copperClient->contacts()->paginate([\n 'minimum_interaction_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ]);\n\n foreach ($cpContacts as $cpContact) {\n // Only sync if previously imported.\n if ($this->hasContact($cpContact['id'])) {\n $this->importContact($cpContact);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n throw $exception;\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncContact(string $crmId): ?Contact\n {\n $cpContact = $this->copperClient->contacts()->find($crmId);\n\n if (empty($cpContact)) {\n return null;\n }\n\n return $this->importContact($cpContact);\n }\n\n /**\n * @inheritdoc\n */\n private function importContact($crmData): Contact\n {\n $account = null;\n if ($crmData['company_id']) {\n $account = $this->team\n ->crm\n ->accounts()\n ->where('crm_provider_id', (string) $crmData['company_id'])\n ->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmData['company_id']);\n }\n }\n\n $countryCode = null;\n if (empty($crmData['address']) === false && $crmData['address']['country']) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $mobilePhone = $parsedNumber = null;\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n if ($phoneNumber['category'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);\n } else {\n $parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);\n }\n }\n\n $email = null;\n if (empty($crmData['emails']) === false) {\n $email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'account_id' => $account->id ?? null,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => $crmData['name'],\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'mobile_phone' => $mobilePhone ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'title' => $crmData['title'],\n 'country_code' => $countryCode,\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Contact::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n private function buildContactPhone(?string $countryCode, ?string $number): ?array\n {\n if ($number) {\n // Trim to our width and attempt to parse it.\n $number = mb_strimwidth($number, 0, 25);\n $parsedNumber = parsePhoneNumber($countryCode, $number);\n } else {\n $parsedNumber = [];\n }\n\n return $parsedNumber;\n }\n\n private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string\n {\n return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;\n }\n\n /**\n * @inheritdoc\n */\n public function syncOrganization(): void\n {\n $organization = $this->copperClient->organisation()->all();\n\n if ($this->config->crm_provider_id !== $organization['id']) {\n $this->config->update(['crm_provider_id' => $organization['id']]);\n }\n }\n\n private function syncCustomFields(): void\n {\n foreach ($this->getFieldTypes() as $fieldType) {\n $currentFields = $this->getFields($fieldType);\n\n foreach ($currentFields as $field) {\n /** @var Field $field */\n $field = $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => $field['name'],\n 'object_type' => $fieldType,\n ], [\n 'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),\n 'type' => $field['type'],\n ]);\n\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n }\n\n $this->config->save();\n }\n\n protected function getFieldTypes(): array\n {\n return [\n parent::OBJECT_TASK,\n parent::OBJECT_LEAD,\n parent::OBJECT_ACCOUNT,\n parent::OBJECT_CONTACT,\n parent::OBJECT_OPPORTUNITY,\n ];\n }\n\n /**\n * @inheritdoc\n */\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n $profiles = $this->copperClient->users()->all();\n\n foreach ($profiles as $profile) {\n $user = $this->userRepository->findByTeamAndEmailAddress($this->team, $profile['email'], onlyActive: true);\n\n // Only import profiles for users we have locally.\n if ($user) {\n $profile = $user->crmProfile()->updateOrCreate([\n 'crm_configuration_id' => $this->config->id,\n 'crm_provider_id' => $profile['id'],\n ]);\n\n if ($userToSearch && $userToSearch->id === $user->id) {\n return $profile;\n }\n }\n }\n\n return null;\n }\n\n /**\n * @inheritdoc\n */\n public function syncProfileFields(): void\n {\n $fieldTypes = [\n 'task',\n 'lead',\n 'account',\n 'contact',\n 'opportunity',\n ];\n\n foreach ($fieldTypes as $fieldType) {\n try {\n $currentFields = $this->getFields(ucfirst($fieldType));\n\n $newFields = array_column($currentFields, 'name');\n $changedFields = array_merge(\n array_diff($this->profile->getFieldsAsArray($fieldType), $newFields),\n array_diff($newFields, $this->profile->getFieldsAsArray($fieldType))\n );\n\n if (\\count($changedFields) > 0) {\n $fields = implode(',', $newFields);\n $this->logger->debug(\n ucfirst($fieldType)\n . ' fields changed from '\n . $this->profile->{$fieldType . '_fields'}\n . ' to: '\n . $fields\n );\n\n $this->profile->{$fieldType . '_fields'} = $fields;\n }\n } catch (\\Exception $exception) {\n $this->logger->error('No access to ' . $fieldType . ' object, skipping...');\n\n continue;\n }\n }\n\n $this->profile->save();\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n $scopeValues = array_map(fn ($scope) => is_string($scope) ? $scope : $scope->value, $scopes);\n $cacheKey = sprintf('copper-search-%d-%s-%s-%d-%d', $this->team->id, $name, implode('-', $scopeValues), $count, $offset);\n\n return Cache::remember($cacheKey, 300, function () use ($name, $scopes, $count, $offset) {\n // Try local search first\n $localResults = $this->searchLocally($name, $scopes, $count, $offset);\n\n // If no local results, fall back to remote API search\n if (empty($localResults)) {\n return $this->searchRemotely($name, $scopes, $count, $offset);\n }\n\n return $localResults;\n });\n }\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n $contact = null;\n $account = null;\n\n if ($crmAccountId) {\n $account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmAccountId);\n }\n }\n\n if ($crmContactId) {\n $contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();\n\n if ($contact === null) {\n $contact = $this->syncContact($crmContactId);\n }\n }\n\n if ($contact || $account) {\n if ($contact && $account === null) {\n $account = $contact->account;\n }\n\n if ($account === null) {\n return [];\n }\n\n $params = [\n 'company_ids' => [$account->crm_provider_id],\n 'status_ids' => [0], // The integer values are 0, 1, 2, 3, for \"Open\", \"Won\", \"Lost\", and \"Abandoned\".\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ];\n\n switch ($this->config->opportunity_assignment_rule) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['sort_by'] = 'date_modified';\n $params['sort_direction'] = 'desc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['sort_by'] = 'date_created';\n $params['sort_direction'] = 'desc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['sort_by'] = 'date_created';\n $params['sort_direction'] = 'asc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['sort_by'] = 'date_modified';\n $params['sort_direction'] = 'desc';\n $params['status_ids'] = [0, 1, 2, 3];\n }\n\n $cpOpportunities = $this->copperClient->opportunities()->search($params);\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n foreach ($cpOpportunities as $cpOpportunity) {\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', (string) $cpOpportunity['pipeline_id'])\n ->first();\n\n if ($businessProcess === null) {\n // Import it.\n $businessProcess = $this->importStages(\n [Stage::TYPE_OPPORTUNITY],\n $cpOpportunity['pipeline_stage_id']\n );\n }\n\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', (string) $cpOpportunity['pipeline_stage_id'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $cpOpportunity['pipeline_stage_id']);\n }\n\n $recordType = $businessProcess->recordTypes()->first();\n\n $record = [\n 'crmId' => $cpOpportunity['id'],\n 'name' => $cpOpportunity['name'],\n 'value' => currency_format($cpOpportunity['monetary_value'], $cpOpportunity['monetary_unit']),\n 'won' => $cpOpportunity['status'] === 'Won',\n 'stage' => [\n 'id' => $stage->id_string,\n 'name' => $stage->name,\n ],\n 'recordType' => [\n 'id' => $recordType->id_string,\n 'name' => $recordType->name,\n ],\n ];\n\n if ($ownerId && isset($cpOpportunity['assignee_id']) && $cpOpportunity['assignee_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = $cpTasks = [];\n\n switch ($objectType) {\n case 'lead':\n $cpTasks = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->relatedTasks($objectId)\n );\n\n break;\n\n case 'account':\n $cpTasks = $this->copperClient->accounts()->relatedTasks($objectId);\n\n break;\n case 'contact':\n if ($opportunityId) {\n $cpTasks = $this->copperClient->opportunities()->relatedTasks($opportunityId);\n } elseif ($objectType === 'contact') {\n $cpTasks = $this->copperClient->contacts()->relatedTasks($objectId);\n }\n\n break;\n }\n\n foreach ($cpTasks as $cpTask) {\n // We only get the ID itself returned, so pull out the full object.\n try {\n $cpTask = $this->copperClient->tasks()->find($cpTask['id']);\n } catch (Exception $exception) {\n $this->logger->error('[Copper] Error fetching task', [\n 'resource_id' => $cpTask['id'],\n 'error' => $exception->getMessage(),\n ]);\n\n continue;\n }\n\n // Only allow open tasks.\n if ($cpTask['status'] === 'Open') {\n $data[] = [\n 'crmId' => $cpTask['id'],\n 'subject' => $cpTask['name'],\n 'due' => $cpTask['due_date']\n ? Carbon::createFromTimestamp($cpTask['due_date'])->format('Y-m-d\\TH:i:sO')\n : null,\n 'type' => null,\n ];\n }\n }\n\n return $data;\n }\n\n /**\n * Try to find email address in CRM service\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $cpObjectType = 'contact';\n\n $cpObjects = $this->copperClient->contacts()->search([\n 'emails' => $email,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (empty($cpObjects)) {\n $cpObjectType = 'lead';\n $cpObjects = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'emails' => $email,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (empty($cpObjects)) {\n return null;\n }\n\n // Search returns an array of results, but we only want the first\n $cpObject = reset($cpObjects);\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n // Check if the user is internal.\n $teamMember = $this->team->users()->where('phone', $phone)->exists();\n\n // Skip the attendee if internal.\n if ($teamMember === false) {\n $cpObjectType = 'contact';\n $cpObject = $this->copperClient->contacts()->search([\n 'phone_number' => $phone,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (\\count($cpObject) === 0) {\n $cpObjectType = 'lead';\n $cpObject = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'phone_number' => $phone,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (empty($cpObject)) {\n return null;\n }\n\n $cpObject = reset($cpObject);\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n return null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $result = \\Cache::remember($this->team->id . $name, 60, function () use ($name, $userId) {\n $cpObjectType = 'contact';\n $cpObject = $this->copperClient->contacts()->search([\n 'name' => $name,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (\\count($cpObject) === 0) {\n $cpObjectType = 'lead';\n $cpObject = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'name' => $name,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (! empty($cpObject)) {\n $cpObject = reset($cpObject);\n }\n\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : false;\n });\n\n return is_array($result) ? $result : null;\n }\n\n private function convertCrmData(array $object, string $objectType, ?int $userId = null): array\n {\n $lead = null;\n $contact = null;\n $opportunity = null;\n $account = null;\n $stage = null;\n $countryCode = null;\n\n if ($objectType === 'lead') {\n $lead = $this->importLead($object);\n\n // Lead might not be imported if the Stage is null for example.\n if ($lead) {\n $countryCode = $lead->country_code;\n $stage = $lead->stage;\n }\n } else {\n $contact = $this->importContact($object);\n $account = $contact->account;\n\n if ($contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account) {\n $countryCode = $account->country_code;\n }\n\n try {\n $cpOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId,\n );\n\n if (! empty($cpOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($cpOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (\\Exception $e) {\n // Nothing to see here.\n }\n }\n\n return [\n $lead,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n public function saveActivity(Activity $activity): Activity\n {\n switch ($activity->type) {\n case Activity::TYPE_CONFERENCE:\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n $activity = $this->buildCallPayload($activity);\n\n break;\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $activity = $this->buildTextMessagePayload($activity);\n\n break;\n }\n\n return $activity;\n }\n\n private function convertActivityAssociations(Activity $activity): array\n {\n if ($activity->lead) {\n $type = 'lead';\n $id = $activity->lead->crm_provider_id;\n } elseif ($activity->contact) {\n $type = 'person';\n $id = $activity->contact->crm_provider_id;\n } elseif ($activity->opportunity) {\n $type = 'opportunity';\n $id = $activity->opportunity->crm_provider_id;\n } else {\n $type = 'company';\n $id = $activity->account->crm_provider_id;\n }\n\n return [\n 'type' => $type,\n 'id' => $id,\n ];\n }\n\n private function convertActivityType(PlaybookCategory $activityType): array\n {\n return [\n 'category' => 'user',\n 'id' => $this->getCrmType($activityType)->value,\n ];\n }\n\n /**\n * @throws CrmException\n */\n private function buildCallPayload(Activity $activity): Activity\n {\n try {\n if ($activity->crm_provider_id) {\n // The activity should be logged under the existing Task (not Activity).\n $newActivityType = $this->getCrmType($activity->category);\n if ($newActivityType === null) {\n $message = sprintf('[Copper] invalid CRM Custom Activity Type: %s', $activity->category);\n\n throw new CrmException($message, 400);\n }\n $this->copperClient->tasks()->update($activity->crm_provider_id, [\n 'status' => 'Completed',\n 'custom_activity_type_id' => $newActivityType->value,\n 'details' => $this->generateActivityDescription($activity),\n ]);\n } else {\n if ($this->getCrmType($activity->category) === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n if ($this->getCrmType($activity->category)->value === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n // Just create an activity.\n $cpActivity = $this->copperClient->activities()->create([\n 'user_id' => $this->profile->crm_provider_id,\n 'activity_date' => $activity->scheduled_start_time->timestamp,\n 'parent' => $this->convertActivityAssociations($activity),\n 'type' => $this->convertActivityType($activity->category),\n 'details' => $this->generateActivityDescription($activity),\n ]);\n\n $activity->crm_provider_id = $cpActivity['id'];\n $activity->save();\n }\n } catch (ClientException $exception) {\n //Log all errors to Sentry\n \\Sentry::captureException($exception);\n\n $response = $exception->getResponse();\n\n $responseBody = $response->getBody();\n $message = $responseBody;\n $errorCode = $response->getStatusCode();\n\n $jsonResponse = json_decode($responseBody, true);\n if (isset($jsonResponse[0]['message'])) {\n $message = $jsonResponse[0]['message'];\n }\n\n throw new CrmException($message, $errorCode);\n }\n\n return $activity;\n }\n\n private function buildTextMessagePayload(Activity $activity): Activity\n {\n if ($this->getCrmType($activity->category) === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n if ($this->getCrmType($activity->category)->value === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n $cpActivity = $this->copperClient->activities()->create([\n 'user_id' => $this->profile->crm_provider_id,\n 'activity_date' => $activity->created_at->timestamp,\n 'parent' => $this->convertActivityAssociations($activity),\n 'type' => $this->convertActivityType($activity->category),\n 'details' => $this->generateActivityDescription($activity),\n ]);\n\n $activity->crm_provider_id = $cpActivity['id'];\n $activity->save();\n\n return $activity;\n }\n\n private function generateActivityDescription(Activity $activity): string\n {\n $description = '';\n\n switch ($activity->type) {\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n case Activity::TYPE_CONFERENCE:\n\n $description = 'Jiminny Call Summary' . PHP_EOL . PHP_EOL;\n $description .= 'Call Duration: ' . $activity->duration_for_humans . PHP_EOL . PHP_EOL;\n\n // Tell them which number was dialed.\n if ($activity->to) {\n $description .= 'Dialed: ' . $activity->to->phone_number . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->hasReasonCodeBotKicked()) {\n $description .= 'Notetaker removed from this meeting' . PHP_EOL . PHP_EOL;\n // When we fix the state to be Activity::RECORDING_RECORDED as it should be this can change.\n } elseif ($activity->hasReasonCodeNotCompliant()) {\n $description .= 'Notetaker did not join due to recording consent not being provided by attendees' . PHP_EOL . PHP_EOL;\n } elseif ($activity->canReviewActivity()) {\n $playbackUrl = $activity->user->team->partner->getPlaybackUrl($activity);\n $description .= 'Review Activity:' . PHP_EOL . $playbackUrl . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->getCrmType() === Activity::TYPE_CONFERENCE) {\n $description .= 'Attendees:'\n . PHP_EOL\n . (new FilterJoinedParticipants())->toString($activity);\n }\n\n if (\\count($activity->notes) > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Notes: ' . PHP_EOL;\n\n foreach ($activity->notes as $note) {\n $nTime = (int) ceil($note->time);\n $time = ($nTime > 3600) ? gmdate('H:i:s', $nTime) : gmdate('i:s', $nTime);\n $description .= $time . ' ' . $note->note . PHP_EOL;\n }\n }\n\n // Get all private messages.\n $messages = $activity->messages()\n ->where('is_private', 1)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Coaching Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n // Get all public messages.\n $messages = $activity->messages()\n ->where('is_private', 0)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Customer Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n if ($activity->summary) {\n $description .= PHP_EOL . PHP_EOL . 'Summary: ' . PHP_EOL . $activity->summary;\n }\n\n break;\n\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $description = $activity->description;\n\n break;\n }\n\n return $description;\n }\n\n public function saveFollowupActivity(Activity $activity, array $fields): ?string\n {\n // This is the user provided activity subject field.\n if (empty($fields['type'])) {\n return null;\n }\n\n $reminder = null;\n if (empty($fields['reminder_date']) === false) {\n $formatReminder = Carbon::createFromFormat('Y-m-d\\TH:i:s\\Z', $fields['reminder_date']);\n $reminder = $formatReminder->getTimestamp();\n }\n\n $due = null;\n if (empty($fields['due_date']) === false) {\n $formatDue = Carbon::createFromFormat('Y-m-d\\TH:i:s\\Z', $fields['due_date']);\n $due = $formatDue->getTimestamp();\n }\n\n $data = [\n 'custom_activity_type_id' => $fields['type'],\n 'status' => 'Open',\n 'assignee_id' => $this->profile->crm_provider_id,\n 'due_date' => $due,\n 'details' => $fields['details'] ?? '',\n 'reminder_date' => $reminder,\n 'name' => $fields['name'] ?? 'Follow-up',\n 'related_resource' => $this->convertActivityAssociations($activity),\n 'custom_fields' => $this->fetchCustomFieldData($activity, Field::OBJECT_TASK),\n ];\n\n // We don't actually create a corresponding activity object on our side yet.\n return $this->copperClient->tasks()->create($data)['id'];\n }\n\n /**\n * Store transcripts as note.\n *\n * @throws \\Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, static::NOTE_BODY_MAX_LENGTH);\n\n $data = [\n 'user_id' => $this->profile->crm_provider_id,\n 'type' => [\n 'category' => 'user',\n 'id' => 0, // This creates a note.\n ],\n 'activity_date' => time(),\n 'details' => $transcripts,\n 'parent' => $this->convertActivityAssociations($activity),\n ];\n\n $cpActivity = $this->copperClient->activities()->create($data);\n\n // Store CRM Activity ID in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $cpActivity['id'];\n $transcription->save();\n }\n\n /**\n * @inheritdoc\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n if ($crmObject instanceof Lead) {\n $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->update($crmObject->crm_provider_id, [\n 'status_id' => $stage->crm_provider_id,\n ])\n );\n } else {\n $this->copperClient->opportunities()->update($crmObject->crm_provider_id, [\n 'pipeline_stage_id' => $stage->crm_provider_id,\n ]);\n }\n }\n\n public function prepareValueForUpdate(array $params): array\n {\n return [$params['fieldName'] => $params['fieldValue']];\n }\n\n /*\n * @inheritdoc\n */\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $preparedData = $data;\n\n if ($objectType === Field::OBJECT_OPPORTUNITY) {\n $preparedData = $this->prepareOpportunityFieldsForUpdate($data);\n }\n\n try {\n $this->copperClient\n ->createResourceFromObjectType($objectType)\n ->update($objectId, $preparedData)\n ;\n } catch (Exception $e) {\n $this->logger->error(self::RESOURCE_UPDATE_FAILED_ERROR_MESSAGE, [\n 'resource_id' => $objectId,\n 'data' => $preparedData,\n 'error' => $e->getMessage(),\n ]);\n\n throw new CrmException(self::RESOURCE_UPDATE_FAILED_ERROR_MESSAGE, $e->getCode(), $e);\n }\n }\n\n /**\n * @param array<string,string> $fieldData\n *\n * @throws CrmException\n *\n * @return array<string,array<int,array<string,bool|float|int|string|null>>|bool|float|int|string|null>\n */\n private function prepareOpportunityFieldsForUpdate(array $fieldData): array\n {\n $preparedData = [];\n $customFields = [];\n\n foreach ($fieldData as $fieldName => $fieldValue) {\n $field = $this->config\n ->fields()\n ->where('crm_provider_id', $fieldName)\n ->first();\n\n if (! $field instanceof Field) {\n throw new CrmException('Field not found');\n }\n\n $convertedValue = $this->fieldValueConverter->convertToCrm($field->getType(), $fieldValue);\n\n if ($this->isStandardField($fieldName)) {\n $preparedData[$fieldName] = $convertedValue;\n\n continue;\n }\n\n $customFields[] = [\n 'custom_field_definition_id' => $fieldName,\n 'value' => $convertedValue,\n ];\n }\n\n if (! empty($customFields)) {\n $preparedData['custom_fields'] = $customFields;\n }\n\n return $preparedData;\n }\n\n /*\n * @inheritdoc\n */\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n return $this->copperClient->createResourceFromObjectType($objectType)->find($objectId);\n }\n\n private function fetchCustomFieldData(Activity $activity, string $objectType): array\n {\n $payload = [];\n\n $fieldData = FieldData::where([\n 'object_id' => $activity->id,\n ])->whereHas('field', function ($query) use ($objectType) {\n $query->where('object_type', $objectType);\n })->get();\n\n foreach ($fieldData as $data) {\n // Add the field and value to the payload.\n $payload += [\n 'custom_field_definition_id' => $data->field->crm_provider_id,\n 'value' => $data->value,\n ];\n }\n\n return $payload;\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $baseUrl = 'https://app.prosperworks.com/companies/' . $this->config->crm_provider_id . '/app#/';\n switch ($objectType) {\n case 'lead':\n $url = $baseUrl . 'leads/' . $providerId;\n\n break;\n\n case 'account':\n $url = $baseUrl . 'organization/' . $providerId;\n\n break;\n\n case 'contact':\n $url = $baseUrl . 'contact/' . $providerId;\n\n break;\n\n case 'opportunity':\n $url = $baseUrl . 'deal/' . $providerId;\n\n break;\n\n default:\n case 'task':\n case 'activity':\n // Sadly we can't deeplink to these in Copper UI.\n $url = null;\n }\n\n return $url;\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! ($this->config->store_transcript)) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n return $this->transcriptionService\n ->findTranscriptionByActivity($activity)\n ->map(static function (array $transcriptionSegment): string {\n return $transcriptionSegment['formattedStartsAt'] . ' | ' . $transcriptionSegment['transcript'];\n })\n ->implode(PHP_EOL);\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n *\n * @return int|string|bool|float|null\n */\n private function extractFieldValue(array $opportunityData, string $fieldName)\n {\n $fieldValue = $this->isStandardField($fieldName)\n ? $opportunityData[$fieldName]\n : $this->resolveCustomFieldFromOpportunityData($opportunityData, $fieldName);\n\n if (is_array($fieldValue)) {\n $fieldValue = implode(', ', $fieldValue);\n }\n\n return $fieldValue;\n }\n\n private function isStandardField(string $fieldName): bool\n {\n return array_key_exists($fieldName, self::STANDARD_OPPORTUNITY_FIELDS);\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n *\n * @return string|int|float|bool|null|array<string, mixed>\n */\n private function resolveCustomFieldFromOpportunityData(array $opportunityData, string $fieldName)\n {\n $fieldData = array_filter(\n $opportunityData['custom_fields'],\n static fn ($field) => (string) $field['custom_field_definition_id'] === $fieldName\n );\n\n return array_pop($fieldData)['value'] ?? '';\n }\n\n private function isSupportedObjectType(string $objectType): bool\n {\n return $objectType !== self::UNSUPPORTED_OBJECT_TYPE;\n }\n\n private function syncStandardFields(): void\n {\n foreach (self::STANDARD_OPPORTUNITY_FIELDS as $fieldId => $fieldData) {\n $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => mb_strimwidth($fieldId, 0, 128),\n 'object_type' => Field::OBJECT_OPPORTUNITY,\n ], [\n 'label' => mb_strimwidth($fieldData['label'], 0, Field::LABEL_MAX_LENGTH),\n 'type' => $fieldData['type'],\n ]);\n }\n\n $this->importStages([Stage::TYPE_OPPORTUNITY]);\n }\n\n private function requestWithExceptionHandling(\\Closure $apiRequest): iterable\n {\n try {\n return $apiRequest();\n } catch (\\Exception $exception) {\n if ($exception->getCode() === 403) {\n // Object might not be supported\n return [];\n }\n\n \\Sentry::captureException($exception);\n\n return [];\n }\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n if ($this->copperClient === null) {\n return false;\n }\n\n $task = $this->copperClient->tasks()->find($crmProviderId);\n\n return ! empty($task);\n } catch (HttpNotFoundException) {\n // Task not found in CRM - this is expected and permanent\n $this->logger->info('[Copper] Task not found during verification', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n } catch (RequestFailedException $e) {\n // Handle 404 responses from Copper API\n if ($e->getCode() === 404) {\n $this->logger->info('[Copper] Task not found during verification (404)', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n\n // Re-throw other Copper exceptions for retry\n throw $e;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\n });\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Crm\\Copper;\n\nuse Carbon\\Carbon;\nuse Exception;\nuse GuzzleHttp\\Exception\\ClientException;\nuse Illuminate\\Support\\Facades\\Cache;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\CopperInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Crm\\LayoutEntity;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Copper\\Api\\Client;\nuse Jiminny\\Services\\Crm\\Copper\\Api\\ClientFactory;\nuse Jiminny\\Services\\Crm\\Copper\\Exception\\RequestFailedException;\nuse Jiminny\\Services\\Crm\\Helpers\\FilterJoinedParticipants;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Services\\Crm\\Copper\\Traits\\SearchesCrmEntities;\nuse Jiminny\\Utils\\CurrencyFormatter;\nuse Jiminny\\Utils\\StringUtil;\n\nclass Service extends BaseService implements\n CopperInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n RemoteEntityManipulationInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n VerifyTaskExistsInterface\n{\n use SearchesCrmEntities;\n private const int NOTE_BODY_MAX_LENGTH = 3000000;\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n private const array STANDARD_OPPORTUNITY_FIELDS = [\n 'monetary_value' => [\n 'label' => 'Value',\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n 'type' => Field::TYPE_CURRENCY,\n ],\n 'pipeline_stage_id' => [\n 'label' => 'Stage',\n 'type' => Field::TYPE_PICKLIST,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n 'close_date' => [\n 'label' => 'Close date',\n 'type' => Field::TYPE_DATE,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n 'win_probability' => [\n 'label' => 'Win probability',\n 'type' => Field::TYPE_NUMBER,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n ];\n private const string UNSUPPORTED_OBJECT_TYPE = 'unsupported';\n private const string OPPORTUNITY_STATUS_OPEN = 'Open';\n private const string OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE = 'Opportunity import failed';\n private const string RESOURCE_UPDATE_FAILED_ERROR_MESSAGE = 'Failed to update resource';\n\n private FieldValueConverter $fieldValueConverter;\n private ClientFactory $clientFactory;\n private ?Client $copperClient = null;\n\n public function __construct(\n ClientFactory $clientFactory,\n FieldValueConverter $fieldValueConverter,\n private readonly UserRepository $userRepository,\n private readonly ProspectPhotoPathService $prospectPhotoPathService,\n private readonly CrmEntityRepository $crmEntityRepository\n ) {\n parent::__construct();\n\n $this->clientFactory = $clientFactory;\n $this->fieldValueConverter = $fieldValueConverter;\n }\n\n public function getDisplayName(): string\n {\n return 'Copper';\n }\n\n /**\n * Get the CRM entity repository (used by SearchesCrmEntities trait)\n */\n protected function getCrmEntityRepository(): CrmEntityRepository\n {\n return $this->crmEntityRepository;\n }\n\n public function getMinimumApiVersion(): string\n {\n return Client::MIN_API_VERSION;\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n $owner = $user->team->owner;\n\n return $owner->getSocialAccount(SocialAccount::PROVIDER_COPPER);\n }\n\n public function setUser(User $user): void\n {\n $this->configureSentryScope($user);\n\n $this->team = $user->getTeam();\n $this->teamService->setTeam($user->getTeam());\n $this->setConfiguration($user->getTeam()->getCrmConfiguration());\n\n // Reset state.\n $this->profile = $user->getProfile();\n\n if (! $this->profile instanceof Profile) {\n // Try to fetch their profile, maybe it was not yet imported?\n $this->profile = $this->getProfile($user);\n }\n }\n\n public function setConfiguration(Configuration $configuration): void\n {\n $this->config = $configuration;\n $this->copperClient = $this->clientFactory->create($configuration);\n\n if ($this->team === null) {\n $this->team = $configuration->getTeam();\n }\n }\n\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);\n }\n\n private function mapObjectType(string $objectType): string\n {\n $objectType = strtolower($objectType);\n\n switch ($objectType) {\n case Field::OBJECT_TASK:\n case Field::OBJECT_OPPORTUNITY:\n case Field::OBJECT_LEAD:\n $mappedType = $objectType;\n\n break;\n case Field::OBJECT_ACCOUNT:\n $mappedType = 'company';\n\n break;\n case Field::OBJECT_CONTACT:\n $mappedType = 'person';\n\n break;\n default:\n $mappedType = self::UNSUPPORTED_OBJECT_TYPE;\n\n break;\n }\n\n return $mappedType;\n }\n\n /**\n * @param string $crmObject The name of the CRM object. i.e. Opportunity or Contact\n */\n protected function getFields(string $crmObject): array\n {\n $mappedObjectType = $this->mapObjectType($crmObject);\n\n if (! $this->isSupportedObjectType($mappedObjectType)) {\n return [];\n }\n\n $customFields = $this->copperClient->fields()->all();\n\n $filteredFields = array_filter(\n $customFields,\n static fn ($field) => in_array($mappedObjectType, $field['available_on'], true)\n );\n\n return array_map(\n fn (array $property) => [\n 'name' => $property['id'],\n 'label' => $property['name'],\n 'type' => $this->convertFieldType($property['data_type']),\n ],\n $filteredFields\n );\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n // Setup the activity field as the default Type.\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'type',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n $fieldFilters = FieldDefinitions::taskFollowupFieldsFilter();\n\n foreach ($fieldFilters as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n public function syncFields(): void\n {\n $this->syncStandardFields();\n $this->syncCustomFields();\n }\n\n public function syncField(Field $field): void\n {\n if ($field->getCrmProviderId() === 'type') {\n /**\n * This field is a special case, it is not a custom field and is not returned by the Copper API.\n *\n * The field is created manually during layout setup.\n *\n * @see getDefaultFields()\n *\n * There is a separate endpoint to get the activity types.\n * @see importPicklistValues()\n */\n return;\n }\n\n if ($field->getCrmProviderId() === 'pipeline_stage_id') {\n // Not a custom type\n return;\n }\n\n $crmField = $this->copperClient->fields()->find($field->getCrmProviderId());\n $field->label = $crmField['name'];\n $field->type = $this->convertFieldType($crmField['data_type']);\n\n $field->save();\n }\n\n /**\n * @param string $fieldType How the data should be input\n */\n private function convertFieldType(string $fieldType): string\n {\n $fieldType = strtolower($fieldType);\n\n switch ($fieldType) {\n case 'dropdown':\n $convertedType = Field::TYPE_PICKLIST;\n\n break;\n case 'string':\n $convertedType = Field::TYPE_TEXT;\n\n break;\n case 'float':\n case 'percentage':\n $convertedType = Field::TYPE_NUMBER;\n\n break;\n case 'text':\n $convertedType = Field::TYPE_TEXTAREA;\n\n break;\n case 'checkbox':\n $convertedType = Field::TYPE_BOOLEAN;\n\n break;\n case Field::TYPE_DATE:\n case Field::TYPE_CURRENCY:\n case Field::TYPE_URL:\n $convertedType = $fieldType;\n\n break;\n default:\n $convertedType = Field::TYPE_UNSUPPORTED;\n\n break;\n }\n\n return $convertedType;\n }\n\n /**\n * @inheritdoc\n */\n public function importPicklistValues(Field $field): array\n {\n $fieldValues = [];\n\n if ($field->object_type === 'opportunity' && $field->crm_provider_id === 'pipeline_stage_id') {\n return $this->importFieldValuesForDealInsights($field);\n }\n\n $values = [];\n\n if ($field->object_type === Field::OBJECT_TASK && $field->crm_provider_id === 'type') {\n $activityTypes = $this->copperClient->activityTypes()->all();\n\n /**\n * We ignore \"system\" activity types, disabled activity types and the \"Note\" activity type.\n */\n $activityTypes = array_filter(\n $activityTypes['user'],\n fn (array $activityType) => ! $activityType['is_disabled'] && $activityType['id'] !== 0\n );\n\n // Import all activity values.\n $i = 0;\n foreach ($activityTypes as $activityType) {\n $values[] = [\n 'value' => $activityType['id'],\n 'label' => mb_strimwidth($activityType['name'], 0, Field::LABEL_MAX_LENGTH),\n 'sequence' => $i++,\n ];\n }\n } else {\n // We just check for the field in the custom definitions.\n $crmField = $this->copperClient->fields()->find($field->crm_provider_id);\n\n // Import all values.\n foreach ($crmField['options'] as $option) {\n $values[] = [\n 'value' => $option['id'],\n 'label' => mb_strimwidth($option['name'], 0, 191),\n 'sequence' => $option['rank'],\n ];\n }\n }\n\n // Take the existing set of field values.\n $fieldsToPurge = $field->values()->get()->pluck('value')->toArray();\n\n foreach ($values as $value) {\n // For all current values, upsert the field.\n $value['value'] = substr($value['value'] ?? '', 0, 255);\n $fieldValues[] = $field->values()->updateOrCreate([\n 'value' => $value['value'],\n ], $value);\n\n // Remove this value from the ones we are going to purge.\n $key = array_search($value['value'], $fieldsToPurge, false);\n if ($key !== false) {\n unset($fieldsToPurge[$key]);\n }\n }\n\n // Delete the old values that are no longer used.\n $field->values()->whereIn('value', $fieldsToPurge)->delete();\n\n return $fieldValues;\n }\n\n /**\n *\n * @return FieldValue[]\n */\n private function importFieldValuesForDealInsights(Field $field): array\n {\n $fieldValues = [];\n $pipelines = $this->copperClient->pipelines()->all();\n\n foreach ($pipelines as $pipeline) {\n foreach ($pipeline['stages'] as $i => $dealStage) {\n $fieldValues[] = $field->values()->updateOrCreate(\n ['value' => $dealStage['id']],\n [\n 'label' => $dealStage['name'],\n 'sequence' => $i,\n ]\n );\n }\n }\n\n return $fieldValues;\n }\n\n /**\n * @inheritdoc\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n if ($types === null) {\n $types = [Stage::TYPE_LEAD, Stage::TYPE_OPPORTUNITY];\n }\n $missingStage = null;\n\n foreach ($types as $type) {\n if ($type === Stage::TYPE_LEAD) {\n $statuses = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leadStatuses()->all()\n );\n\n if (count($statuses) > 0) {\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => BusinessProcess::TYPE_LEAD,\n ], [\n 'team_id' => $this->team->id,\n 'name' => BusinessProcess::TYPE_LEAD,\n 'type' => BusinessProcess::TYPE_LEAD,\n 'is_selectable' => true,\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => BusinessProcess::TYPE_LEAD,\n ], [\n 'team_id' => $this->team->id,\n 'name' => BusinessProcess::TYPE_LEAD,\n 'is_selectable' => true,\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n $leadStatuses = [];\n foreach ($statuses as $status) {\n // Upsert all statuses for the team.\n $status = $this->config->stages()->updateOrCreate([\n 'crm_provider_id' => $status['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($status['name'], 0, 50),\n 'label' => mb_strimwidth($status['name'], 0, 191),\n 'type' => Stage::TYPE_LEAD,\n 'sequence' => $status['order'],\n 'is_selectable' => true,\n ]);\n\n if ($missingStageName && $missingStageName === $status['id']) {\n $missingStage = $status;\n }\n\n $leadStatuses[] = $status['id'];\n }\n\n $businessProcess->stages()->sync($leadStatuses);\n }\n } else {\n // We create a business process to contain the pipeline, and later store all stages against it.\n foreach ($this->copperClient->pipelines()->all() as $pipeline) {\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => $pipeline['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($pipeline['name'], 0, 150),\n 'type' => BusinessProcess::TYPE_OPPORTUNITY,\n 'is_selectable' => true,\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => $pipeline['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($pipeline['name'], 0, 150),\n 'is_selectable' => true,\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n $stages = [];\n\n foreach ($pipeline['stages'] as $i => $dealStage) {\n // Upsert all stages for the team.\n $stage = $this->config->stages()->updateOrCreate([\n 'crm_provider_id' => $dealStage['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($dealStage['name'], 0, 50),\n 'label' => mb_strimwidth($dealStage['name'], 0, 191),\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'sequence' => $i,\n 'is_selectable' => true,\n 'probability' => $dealStage['win_probability'],\n ]);\n\n if ($missingStageName && $missingStageName === $dealStage['id']) {\n $missingStage = $stage;\n }\n\n $stages[] = $stage['id'];\n }\n\n $businessProcess->stages()->sync($stages);\n }\n }\n }\n\n return $missingStage;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int\n {\n $syncCount = 0;\n\n $cpLeads = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->paginate([\n 'minimum_modified_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ])\n );\n\n foreach ($cpLeads as $cpLead) {\n // Only sync if previously imported.\n if ($this->hasLead($cpLead['id']) === false) {\n $this->importLead($cpLead);\n $syncCount++;\n }\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLead(string $crmId): ?Lead\n {\n $cpLead = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->find($crmId)\n );\n\n if (\\count($cpLead) === 0) {\n return null;\n }\n\n return $this->importLead($cpLead);\n }\n\n /**\n * @inheritdoc\n */\n private function importLead($crmData): ?Lead\n {\n $countryCode = null;\n if (! empty($crmData['address']) && isset($crmData['address']['country'])) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $mobilePhone = $parsedNumber = null;\n if (! empty($crmData['phone_numbers'])) {\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n if ($phoneNumber['category'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);\n } else {\n $parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);\n }\n }\n }\n\n $name = $crmData['name'];\n\n if (empty($crmData['company_name'])) {\n $company = 'Unknown';\n } else {\n $company = mb_strimwidth($crmData['company_name'], 0, 191);\n }\n\n $domain = null;\n if (empty($crmData['websites']) === false) {\n $domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);\n $domain = StringUtil::resolveDomain($domain);\n }\n\n $email = null;\n if (empty($crmData['email']) === false) {\n $email = mb_strimwidth($crmData['email']['email'], 0, 80);\n }\n\n $stage = $this->config\n ->stages()\n ->where('crm_provider_id', (string) $crmData['status_id'])\n ->where('type', Stage::TYPE_LEAD)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_LEAD], $crmData['status_id']);\n }\n\n if (! $stage instanceof Stage) {\n return null;\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($name, 0, 191),\n 'company' => $company,\n 'domain' => $domain,\n 'title' => $crmData['title'] ? mb_strimwidth($crmData['title'], 0, 128) : null,\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'mobile_phone' => $mobilePhone,\n 'stage_id' => $stage->id,\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Lead::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'country_code' => $countryCode,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->leads()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n /**\n * @inheritdoc\n */\n public function syncAccounts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n $cpAccounts = $this->copperClient->accounts()->paginate([\n 'minimum_modified_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ]);\n\n foreach ($cpAccounts as $cpAccount) {\n // Only sync if previously imported.\n if ($this->hasAccount($cpAccount['id'])) {\n $this->importAccount($cpAccount);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncAccount(string $crmId): ?Account\n {\n $cpAccount = $this->copperClient->accounts()->find($crmId);\n\n if (empty($cpAccount)) {\n return null;\n }\n\n return $this->importAccount($cpAccount);\n }\n\n /**\n * @inheritdoc\n */\n private function importAccount($crmData): Account\n {\n $countryCode = null;\n if (empty($crmData['address']) === false && $crmData['address']['country']) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $name = $crmData['name'];\n\n $parsedNumber = null;\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n $parsedNumber = parsePhoneNumber($countryCode, $phoneNumber['number']);\n }\n\n $domain = null;\n if (empty($crmData['websites']) === false) {\n $domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);\n $domain = StringUtil::resolveDomain($domain);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($name, 0, 191),\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Account::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'country_code' => $countryCode,\n 'domain' => $domain,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->accounts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n public function syncOpportunities(array $parameters, ?string $strategy = null): int\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->copperClient,\n ]);\n $strategies = $strategyResolver->getStrategies($this->config, $strategy);\n\n $syncCount = 0;\n\n try {\n foreach ($strategies as $syncStrategy) {\n foreach ($syncStrategy->fetchOpportunities($parameters) as $opportunityData) {\n $this->importOpportunity($opportunityData);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n $this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => $exception->getMessage(),\n ]);\n }\n\n return $syncCount;\n }\n\n public function syncOpportunity(string $crmId): ?Opportunity\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->copperClient,\n ]);\n $strategy = $strategyResolver->resolve(\n $this->config,\n OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY\n );\n\n $parameters['crm_id'] = $crmId;\n\n $cpOpportunity = $strategy->fetchOpportunities($parameters);\n\n return $this->importOpportunity($cpOpportunity);\n }\n\n private function importOpportunity($crmData): ?Opportunity\n {\n $companyId = (string) $crmData['company_id'];\n\n if (empty($companyId)) {\n $this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => 'No company id',\n ]);\n\n return null;\n }\n\n $account = $this->config->accounts()->where('crm_provider_id', $companyId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($companyId);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', (string) $crmData['pipeline_id'])\n ->first();\n\n if ($businessProcess === null) {\n // It is possible for some deals to not be in a pipeline.\n $this->logger->warning(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => 'Missing pipeline',\n ]);\n\n return null;\n }\n\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', (string) $crmData['pipeline_stage_id'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n $this->logger->info('Stage not found, importing', [\n 'pipeline_id' => $crmData['pipeline_id'],\n 'stage_id' => $crmData['pipeline_stage_id'],\n ]);\n\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData['pipeline_stage_id']);\n }\n\n $recordType = $businessProcess->recordTypes()->first();\n $closeDate = null;\n $isClosed = $crmData['status'] !== self::OPPORTUNITY_STATUS_OPEN;\n\n if ($crmData['close_date']) {\n $closeDate = Carbon::parse($crmData['close_date'])->format('Y-m-d');\n }\n\n $data = [\n 'team_id' => $this->team->getId(),\n 'account_id' => $account->id,\n 'user_id' => $profile->user_id ?? null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($crmData['name'], 0, 128),\n 'value' => $crmData['monetary_value'],\n 'currency_code' => CurrencyFormatter::formatCode($crmData['monetary_unit']),\n 'close_date' => $closeDate,\n 'is_closed' => $isClosed,\n 'is_won' => $crmData['status'] === 'Won',\n 'stage_id' => $stage->id,\n 'record_type_id' => $recordType->id ?? null,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n /** @var Opportunity $opportunity */\n $opportunity = $this->config\n ->opportunities()\n ->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data)\n ;\n\n // import external fields into crm_field_data if present\n $dealInsightsFields = $this->getOpportunitySyncableFields();\n $this->importOpportunityCrmFieldData($crmData, $dealInsightsFields, $opportunity->id);\n\n return $opportunity;\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n * @param string[] $dealInsightsFields\n */\n public function importOpportunityCrmFieldData(\n array $opportunityData,\n array $dealInsightsFields,\n int $opportunityId\n ): void {\n foreach ($dealInsightsFields as $fieldName) {\n $field = $this->config->fields()->with('entities')\n ->where('crm_provider_id', $fieldName)\n ->where('object_type', Field::OBJECT_OPPORTUNITY)\n ->first();\n\n if (! $field instanceof Field) {\n $this->logger->warning('Field not found', [\n 'field' => $fieldName,\n 'opportunity_id' => $opportunityId,\n ]);\n\n continue;\n }\n\n $entity = $field->getEntities()->first();\n\n if (! $entity instanceof LayoutEntity) {\n continue;\n }\n\n $fieldValue = $this->extractFieldValue($opportunityData, $fieldName);\n $normalizedValue = $this->normalizeValue($field->getType(), (string) $fieldValue, true);\n\n $field->data()\n ->updateOrCreate([\n 'crm_layout_entity_id' => $entity->id,\n 'crm_field_id' => $field->id,\n 'object_type' => 'opportunity',\n 'object_id' => $opportunityId,\n ], ['value' => $normalizedValue])\n ;\n }\n }\n\n /**\n * @inheritdoc\n */\n public function syncContacts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n $cpContacts = $this->copperClient->contacts()->paginate([\n 'minimum_interaction_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ]);\n\n foreach ($cpContacts as $cpContact) {\n // Only sync if previously imported.\n if ($this->hasContact($cpContact['id'])) {\n $this->importContact($cpContact);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n throw $exception;\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncContact(string $crmId): ?Contact\n {\n $cpContact = $this->copperClient->contacts()->find($crmId);\n\n if (empty($cpContact)) {\n return null;\n }\n\n return $this->importContact($cpContact);\n }\n\n /**\n * @inheritdoc\n */\n private function importContact($crmData): Contact\n {\n $account = null;\n if ($crmData['company_id']) {\n $account = $this->team\n ->crm\n ->accounts()\n ->where('crm_provider_id', (string) $crmData['company_id'])\n ->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmData['company_id']);\n }\n }\n\n $countryCode = null;\n if (empty($crmData['address']) === false && $crmData['address']['country']) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $mobilePhone = $parsedNumber = null;\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n if ($phoneNumber['category'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);\n } else {\n $parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);\n }\n }\n\n $email = null;\n if (empty($crmData['emails']) === false) {\n $email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'account_id' => $account->id ?? null,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => $crmData['name'],\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'mobile_phone' => $mobilePhone ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'title' => $crmData['title'],\n 'country_code' => $countryCode,\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Contact::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n private function buildContactPhone(?string $countryCode, ?string $number): ?array\n {\n if ($number) {\n // Trim to our width and attempt to parse it.\n $number = mb_strimwidth($number, 0, 25);\n $parsedNumber = parsePhoneNumber($countryCode, $number);\n } else {\n $parsedNumber = [];\n }\n\n return $parsedNumber;\n }\n\n private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string\n {\n return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;\n }\n\n /**\n * @inheritdoc\n */\n public function syncOrganization(): void\n {\n $organization = $this->copperClient->organisation()->all();\n\n if ($this->config->crm_provider_id !== $organization['id']) {\n $this->config->update(['crm_provider_id' => $organization['id']]);\n }\n }\n\n private function syncCustomFields(): void\n {\n foreach ($this->getFieldTypes() as $fieldType) {\n $currentFields = $this->getFields($fieldType);\n\n foreach ($currentFields as $field) {\n /** @var Field $field */\n $field = $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => $field['name'],\n 'object_type' => $fieldType,\n ], [\n 'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),\n 'type' => $field['type'],\n ]);\n\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n }\n\n $this->config->save();\n }\n\n protected function getFieldTypes(): array\n {\n return [\n parent::OBJECT_TASK,\n parent::OBJECT_LEAD,\n parent::OBJECT_ACCOUNT,\n parent::OBJECT_CONTACT,\n parent::OBJECT_OPPORTUNITY,\n ];\n }\n\n /**\n * @inheritdoc\n */\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n $profiles = $this->copperClient->users()->all();\n\n foreach ($profiles as $profile) {\n $user = $this->userRepository->findByTeamAndEmailAddress($this->team, $profile['email'], onlyActive: true);\n\n // Only import profiles for users we have locally.\n if ($user) {\n $profile = $user->crmProfile()->updateOrCreate([\n 'crm_configuration_id' => $this->config->id,\n 'crm_provider_id' => $profile['id'],\n ]);\n\n if ($userToSearch && $userToSearch->id === $user->id) {\n return $profile;\n }\n }\n }\n\n return null;\n }\n\n /**\n * @inheritdoc\n */\n public function syncProfileFields(): void\n {\n $fieldTypes = [\n 'task',\n 'lead',\n 'account',\n 'contact',\n 'opportunity',\n ];\n\n foreach ($fieldTypes as $fieldType) {\n try {\n $currentFields = $this->getFields(ucfirst($fieldType));\n\n $newFields = array_column($currentFields, 'name');\n $changedFields = array_merge(\n array_diff($this->profile->getFieldsAsArray($fieldType), $newFields),\n array_diff($newFields, $this->profile->getFieldsAsArray($fieldType))\n );\n\n if (\\count($changedFields) > 0) {\n $fields = implode(',', $newFields);\n $this->logger->debug(\n ucfirst($fieldType)\n . ' fields changed from '\n . $this->profile->{$fieldType . '_fields'}\n . ' to: '\n . $fields\n );\n\n $this->profile->{$fieldType . '_fields'} = $fields;\n }\n } catch (\\Exception $exception) {\n $this->logger->error('No access to ' . $fieldType . ' object, skipping...');\n\n continue;\n }\n }\n\n $this->profile->save();\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n $scopeValues = array_map(fn ($scope) => is_string($scope) ? $scope : $scope->value, $scopes);\n $cacheKey = sprintf('copper-search-%d-%s-%s-%d-%d', $this->team->id, $name, implode('-', $scopeValues), $count, $offset);\n\n return Cache::remember($cacheKey, 300, function () use ($name, $scopes, $count, $offset) {\n // Try local search first\n $localResults = $this->searchLocally($name, $scopes, $count, $offset);\n\n // If no local results, fall back to remote API search\n if (empty($localResults)) {\n return $this->searchRemotely($name, $scopes, $count, $offset);\n }\n\n return $localResults;\n });\n }\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n $contact = null;\n $account = null;\n\n if ($crmAccountId) {\n $account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmAccountId);\n }\n }\n\n if ($crmContactId) {\n $contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();\n\n if ($contact === null) {\n $contact = $this->syncContact($crmContactId);\n }\n }\n\n if ($contact || $account) {\n if ($contact && $account === null) {\n $account = $contact->account;\n }\n\n if ($account === null) {\n return [];\n }\n\n $params = [\n 'company_ids' => [$account->crm_provider_id],\n 'status_ids' => [0], // The integer values are 0, 1, 2, 3, for \"Open\", \"Won\", \"Lost\", and \"Abandoned\".\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ];\n\n switch ($this->config->opportunity_assignment_rule) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['sort_by'] = 'date_modified';\n $params['sort_direction'] = 'desc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['sort_by'] = 'date_created';\n $params['sort_direction'] = 'desc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['sort_by'] = 'date_created';\n $params['sort_direction'] = 'asc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['sort_by'] = 'date_modified';\n $params['sort_direction'] = 'desc';\n $params['status_ids'] = [0, 1, 2, 3];\n }\n\n $cpOpportunities = $this->copperClient->opportunities()->search($params);\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n foreach ($cpOpportunities as $cpOpportunity) {\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', (string) $cpOpportunity['pipeline_id'])\n ->first();\n\n if ($businessProcess === null) {\n // Import it.\n $businessProcess = $this->importStages(\n [Stage::TYPE_OPPORTUNITY],\n $cpOpportunity['pipeline_stage_id']\n );\n }\n\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', (string) $cpOpportunity['pipeline_stage_id'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $cpOpportunity['pipeline_stage_id']);\n }\n\n $recordType = $businessProcess->recordTypes()->first();\n\n $record = [\n 'crmId' => $cpOpportunity['id'],\n 'name' => $cpOpportunity['name'],\n 'value' => currency_format($cpOpportunity['monetary_value'], $cpOpportunity['monetary_unit']),\n 'won' => $cpOpportunity['status'] === 'Won',\n 'stage' => [\n 'id' => $stage->id_string,\n 'name' => $stage->name,\n ],\n 'recordType' => [\n 'id' => $recordType->id_string,\n 'name' => $recordType->name,\n ],\n ];\n\n if ($ownerId && isset($cpOpportunity['assignee_id']) && $cpOpportunity['assignee_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = $cpTasks = [];\n\n switch ($objectType) {\n case 'lead':\n $cpTasks = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->relatedTasks($objectId)\n );\n\n break;\n\n case 'account':\n $cpTasks = $this->copperClient->accounts()->relatedTasks($objectId);\n\n break;\n case 'contact':\n if ($opportunityId) {\n $cpTasks = $this->copperClient->opportunities()->relatedTasks($opportunityId);\n } elseif ($objectType === 'contact') {\n $cpTasks = $this->copperClient->contacts()->relatedTasks($objectId);\n }\n\n break;\n }\n\n foreach ($cpTasks as $cpTask) {\n // We only get the ID itself returned, so pull out the full object.\n try {\n $cpTask = $this->copperClient->tasks()->find($cpTask['id']);\n } catch (Exception $exception) {\n $this->logger->error('[Copper] Error fetching task', [\n 'resource_id' => $cpTask['id'],\n 'error' => $exception->getMessage(),\n ]);\n\n continue;\n }\n\n // Only allow open tasks.\n if ($cpTask['status'] === 'Open') {\n $data[] = [\n 'crmId' => $cpTask['id'],\n 'subject' => $cpTask['name'],\n 'due' => $cpTask['due_date']\n ? Carbon::createFromTimestamp($cpTask['due_date'])->format('Y-m-d\\TH:i:sO')\n : null,\n 'type' => null,\n ];\n }\n }\n\n return $data;\n }\n\n /**\n * Try to find email address in CRM service\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $cpObjectType = 'contact';\n\n $cpObjects = $this->copperClient->contacts()->search([\n 'emails' => $email,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (empty($cpObjects)) {\n $cpObjectType = 'lead';\n $cpObjects = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'emails' => $email,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (empty($cpObjects)) {\n return null;\n }\n\n // Search returns an array of results, but we only want the first\n $cpObject = reset($cpObjects);\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n // Check if the user is internal.\n $teamMember = $this->team->users()->where('phone', $phone)->exists();\n\n // Skip the attendee if internal.\n if ($teamMember === false) {\n $cpObjectType = 'contact';\n $cpObject = $this->copperClient->contacts()->search([\n 'phone_number' => $phone,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (\\count($cpObject) === 0) {\n $cpObjectType = 'lead';\n $cpObject = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'phone_number' => $phone,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (empty($cpObject)) {\n return null;\n }\n\n $cpObject = reset($cpObject);\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n return null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $result = \\Cache::remember($this->team->id . $name, 60, function () use ($name, $userId) {\n $cpObjectType = 'contact';\n $cpObject = $this->copperClient->contacts()->search([\n 'name' => $name,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (\\count($cpObject) === 0) {\n $cpObjectType = 'lead';\n $cpObject = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'name' => $name,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (! empty($cpObject)) {\n $cpObject = reset($cpObject);\n }\n\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : false;\n });\n\n return is_array($result) ? $result : null;\n }\n\n private function convertCrmData(array $object, string $objectType, ?int $userId = null): array\n {\n $lead = null;\n $contact = null;\n $opportunity = null;\n $account = null;\n $stage = null;\n $countryCode = null;\n\n if ($objectType === 'lead') {\n $lead = $this->importLead($object);\n\n // Lead might not be imported if the Stage is null for example.\n if ($lead) {\n $countryCode = $lead->country_code;\n $stage = $lead->stage;\n }\n } else {\n $contact = $this->importContact($object);\n $account = $contact->account;\n\n if ($contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account) {\n $countryCode = $account->country_code;\n }\n\n try {\n $cpOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId,\n );\n\n if (! empty($cpOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($cpOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (\\Exception $e) {\n // Nothing to see here.\n }\n }\n\n return [\n $lead,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n public function saveActivity(Activity $activity): Activity\n {\n switch ($activity->type) {\n case Activity::TYPE_CONFERENCE:\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n $activity = $this->buildCallPayload($activity);\n\n break;\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $activity = $this->buildTextMessagePayload($activity);\n\n break;\n }\n\n return $activity;\n }\n\n private function convertActivityAssociations(Activity $activity): array\n {\n if ($activity->lead) {\n $type = 'lead';\n $id = $activity->lead->crm_provider_id;\n } elseif ($activity->contact) {\n $type = 'person';\n $id = $activity->contact->crm_provider_id;\n } elseif ($activity->opportunity) {\n $type = 'opportunity';\n $id = $activity->opportunity->crm_provider_id;\n } else {\n $type = 'company';\n $id = $activity->account->crm_provider_id;\n }\n\n return [\n 'type' => $type,\n 'id' => $id,\n ];\n }\n\n private function convertActivityType(PlaybookCategory $activityType): array\n {\n return [\n 'category' => 'user',\n 'id' => $this->getCrmType($activityType)->value,\n ];\n }\n\n /**\n * @throws CrmException\n */\n private function buildCallPayload(Activity $activity): Activity\n {\n try {\n if ($activity->crm_provider_id) {\n // The activity should be logged under the existing Task (not Activity).\n $newActivityType = $this->getCrmType($activity->category);\n if ($newActivityType === null) {\n $message = sprintf('[Copper] invalid CRM Custom Activity Type: %s', $activity->category);\n\n throw new CrmException($message, 400);\n }\n $this->copperClient->tasks()->update($activity->crm_provider_id, [\n 'status' => 'Completed',\n 'custom_activity_type_id' => $newActivityType->value,\n 'details' => $this->generateActivityDescription($activity),\n ]);\n } else {\n if ($this->getCrmType($activity->category) === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n if ($this->getCrmType($activity->category)->value === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n // Just create an activity.\n $cpActivity = $this->copperClient->activities()->create([\n 'user_id' => $this->profile->crm_provider_id,\n 'activity_date' => $activity->scheduled_start_time->timestamp,\n 'parent' => $this->convertActivityAssociations($activity),\n 'type' => $this->convertActivityType($activity->category),\n 'details' => $this->generateActivityDescription($activity),\n ]);\n\n $activity->crm_provider_id = $cpActivity['id'];\n $activity->save();\n }\n } catch (ClientException $exception) {\n //Log all errors to Sentry\n \\Sentry::captureException($exception);\n\n $response = $exception->getResponse();\n\n $responseBody = $response->getBody();\n $message = $responseBody;\n $errorCode = $response->getStatusCode();\n\n $jsonResponse = json_decode($responseBody, true);\n if (isset($jsonResponse[0]['message'])) {\n $message = $jsonResponse[0]['message'];\n }\n\n throw new CrmException($message, $errorCode);\n }\n\n return $activity;\n }\n\n private function buildTextMessagePayload(Activity $activity): Activity\n {\n if ($this->getCrmType($activity->category) === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n if ($this->getCrmType($activity->category)->value === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n $cpActivity = $this->copperClient->activities()->create([\n 'user_id' => $this->profile->crm_provider_id,\n 'activity_date' => $activity->created_at->timestamp,\n 'parent' => $this->convertActivityAssociations($activity),\n 'type' => $this->convertActivityType($activity->category),\n 'details' => $this->generateActivityDescription($activity),\n ]);\n\n $activity->crm_provider_id = $cpActivity['id'];\n $activity->save();\n\n return $activity;\n }\n\n private function generateActivityDescription(Activity $activity): string\n {\n $description = '';\n\n switch ($activity->type) {\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n case Activity::TYPE_CONFERENCE:\n\n $description = 'Jiminny Call Summary' . PHP_EOL . PHP_EOL;\n $description .= 'Call Duration: ' . $activity->duration_for_humans . PHP_EOL . PHP_EOL;\n\n // Tell them which number was dialed.\n if ($activity->to) {\n $description .= 'Dialed: ' . $activity->to->phone_number . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->hasReasonCodeBotKicked()) {\n $description .= 'Notetaker removed from this meeting' . PHP_EOL . PHP_EOL;\n // When we fix the state to be Activity::RECORDING_RECORDED as it should be this can change.\n } elseif ($activity->hasReasonCodeNotCompliant()) {\n $description .= 'Notetaker did not join due to recording consent not being provided by attendees' . PHP_EOL . PHP_EOL;\n } elseif ($activity->canReviewActivity()) {\n $playbackUrl = $activity->user->team->partner->getPlaybackUrl($activity);\n $description .= 'Review Activity:' . PHP_EOL . $playbackUrl . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->getCrmType() === Activity::TYPE_CONFERENCE) {\n $description .= 'Attendees:'\n . PHP_EOL\n . (new FilterJoinedParticipants())->toString($activity);\n }\n\n if (\\count($activity->notes) > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Notes: ' . PHP_EOL;\n\n foreach ($activity->notes as $note) {\n $nTime = (int) ceil($note->time);\n $time = ($nTime > 3600) ? gmdate('H:i:s', $nTime) : gmdate('i:s', $nTime);\n $description .= $time . ' ' . $note->note . PHP_EOL;\n }\n }\n\n // Get all private messages.\n $messages = $activity->messages()\n ->where('is_private', 1)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Coaching Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n // Get all public messages.\n $messages = $activity->messages()\n ->where('is_private', 0)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Customer Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n if ($activity->summary) {\n $description .= PHP_EOL . PHP_EOL . 'Summary: ' . PHP_EOL . $activity->summary;\n }\n\n break;\n\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $description = $activity->description;\n\n break;\n }\n\n return $description;\n }\n\n public function saveFollowupActivity(Activity $activity, array $fields): ?string\n {\n // This is the user provided activity subject field.\n if (empty($fields['type'])) {\n return null;\n }\n\n $reminder = null;\n if (empty($fields['reminder_date']) === false) {\n $formatReminder = Carbon::createFromFormat('Y-m-d\\TH:i:s\\Z', $fields['reminder_date']);\n $reminder = $formatReminder->getTimestamp();\n }\n\n $due = null;\n if (empty($fields['due_date']) === false) {\n $formatDue = Carbon::createFromFormat('Y-m-d\\TH:i:s\\Z', $fields['due_date']);\n $due = $formatDue->getTimestamp();\n }\n\n $data = [\n 'custom_activity_type_id' => $fields['type'],\n 'status' => 'Open',\n 'assignee_id' => $this->profile->crm_provider_id,\n 'due_date' => $due,\n 'details' => $fields['details'] ?? '',\n 'reminder_date' => $reminder,\n 'name' => $fields['name'] ?? 'Follow-up',\n 'related_resource' => $this->convertActivityAssociations($activity),\n 'custom_fields' => $this->fetchCustomFieldData($activity, Field::OBJECT_TASK),\n ];\n\n // We don't actually create a corresponding activity object on our side yet.\n return $this->copperClient->tasks()->create($data)['id'];\n }\n\n /**\n * Store transcripts as note.\n *\n * @throws \\Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, static::NOTE_BODY_MAX_LENGTH);\n\n $data = [\n 'user_id' => $this->profile->crm_provider_id,\n 'type' => [\n 'category' => 'user',\n 'id' => 0, // This creates a note.\n ],\n 'activity_date' => time(),\n 'details' => $transcripts,\n 'parent' => $this->convertActivityAssociations($activity),\n ];\n\n $cpActivity = $this->copperClient->activities()->create($data);\n\n // Store CRM Activity ID in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $cpActivity['id'];\n $transcription->save();\n }\n\n /**\n * @inheritdoc\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n if ($crmObject instanceof Lead) {\n $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->update($crmObject->crm_provider_id, [\n 'status_id' => $stage->crm_provider_id,\n ])\n );\n } else {\n $this->copperClient->opportunities()->update($crmObject->crm_provider_id, [\n 'pipeline_stage_id' => $stage->crm_provider_id,\n ]);\n }\n }\n\n public function prepareValueForUpdate(array $params): array\n {\n return [$params['fieldName'] => $params['fieldValue']];\n }\n\n /*\n * @inheritdoc\n */\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $preparedData = $data;\n\n if ($objectType === Field::OBJECT_OPPORTUNITY) {\n $preparedData = $this->prepareOpportunityFieldsForUpdate($data);\n }\n\n try {\n $this->copperClient\n ->createResourceFromObjectType($objectType)\n ->update($objectId, $preparedData)\n ;\n } catch (Exception $e) {\n $this->logger->error(self::RESOURCE_UPDATE_FAILED_ERROR_MESSAGE, [\n 'resource_id' => $objectId,\n 'data' => $preparedData,\n 'error' => $e->getMessage(),\n ]);\n\n throw new CrmException(self::RESOURCE_UPDATE_FAILED_ERROR_MESSAGE, $e->getCode(), $e);\n }\n }\n\n /**\n * @param array<string,string> $fieldData\n *\n * @throws CrmException\n *\n * @return array<string,array<int,array<string,bool|float|int|string|null>>|bool|float|int|string|null>\n */\n private function prepareOpportunityFieldsForUpdate(array $fieldData): array\n {\n $preparedData = [];\n $customFields = [];\n\n foreach ($fieldData as $fieldName => $fieldValue) {\n $field = $this->config\n ->fields()\n ->where('crm_provider_id', $fieldName)\n ->first();\n\n if (! $field instanceof Field) {\n throw new CrmException('Field not found');\n }\n\n $convertedValue = $this->fieldValueConverter->convertToCrm($field->getType(), $fieldValue);\n\n if ($this->isStandardField($fieldName)) {\n $preparedData[$fieldName] = $convertedValue;\n\n continue;\n }\n\n $customFields[] = [\n 'custom_field_definition_id' => $fieldName,\n 'value' => $convertedValue,\n ];\n }\n\n if (! empty($customFields)) {\n $preparedData['custom_fields'] = $customFields;\n }\n\n return $preparedData;\n }\n\n /*\n * @inheritdoc\n */\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n return $this->copperClient->createResourceFromObjectType($objectType)->find($objectId);\n }\n\n private function fetchCustomFieldData(Activity $activity, string $objectType): array\n {\n $payload = [];\n\n $fieldData = FieldData::where([\n 'object_id' => $activity->id,\n ])->whereHas('field', function ($query) use ($objectType) {\n $query->where('object_type', $objectType);\n })->get();\n\n foreach ($fieldData as $data) {\n // Add the field and value to the payload.\n $payload += [\n 'custom_field_definition_id' => $data->field->crm_provider_id,\n 'value' => $data->value,\n ];\n }\n\n return $payload;\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $baseUrl = 'https://app.prosperworks.com/companies/' . $this->config->crm_provider_id . '/app#/';\n switch ($objectType) {\n case 'lead':\n $url = $baseUrl . 'leads/' . $providerId;\n\n break;\n\n case 'account':\n $url = $baseUrl . 'organization/' . $providerId;\n\n break;\n\n case 'contact':\n $url = $baseUrl . 'contact/' . $providerId;\n\n break;\n\n case 'opportunity':\n $url = $baseUrl . 'deal/' . $providerId;\n\n break;\n\n default:\n case 'task':\n case 'activity':\n // Sadly we can't deeplink to these in Copper UI.\n $url = null;\n }\n\n return $url;\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! ($this->config->store_transcript)) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n return $this->transcriptionService\n ->findTranscriptionByActivity($activity)\n ->map(static function (array $transcriptionSegment): string {\n return $transcriptionSegment['formattedStartsAt'] . ' | ' . $transcriptionSegment['transcript'];\n })\n ->implode(PHP_EOL);\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n *\n * @return int|string|bool|float|null\n */\n private function extractFieldValue(array $opportunityData, string $fieldName)\n {\n $fieldValue = $this->isStandardField($fieldName)\n ? $opportunityData[$fieldName]\n : $this->resolveCustomFieldFromOpportunityData($opportunityData, $fieldName);\n\n if (is_array($fieldValue)) {\n $fieldValue = implode(', ', $fieldValue);\n }\n\n return $fieldValue;\n }\n\n private function isStandardField(string $fieldName): bool\n {\n return array_key_exists($fieldName, self::STANDARD_OPPORTUNITY_FIELDS);\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n *\n * @return string|int|float|bool|null|array<string, mixed>\n */\n private function resolveCustomFieldFromOpportunityData(array $opportunityData, string $fieldName)\n {\n $fieldData = array_filter(\n $opportunityData['custom_fields'],\n static fn ($field) => (string) $field['custom_field_definition_id'] === $fieldName\n );\n\n return array_pop($fieldData)['value'] ?? '';\n }\n\n private function isSupportedObjectType(string $objectType): bool\n {\n return $objectType !== self::UNSUPPORTED_OBJECT_TYPE;\n }\n\n private function syncStandardFields(): void\n {\n foreach (self::STANDARD_OPPORTUNITY_FIELDS as $fieldId => $fieldData) {\n $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => mb_strimwidth($fieldId, 0, 128),\n 'object_type' => Field::OBJECT_OPPORTUNITY,\n ], [\n 'label' => mb_strimwidth($fieldData['label'], 0, Field::LABEL_MAX_LENGTH),\n 'type' => $fieldData['type'],\n ]);\n }\n\n $this->importStages([Stage::TYPE_OPPORTUNITY]);\n }\n\n private function requestWithExceptionHandling(\\Closure $apiRequest): iterable\n {\n try {\n return $apiRequest();\n } catch (\\Exception $exception) {\n if ($exception->getCode() === 403) {\n // Object might not be supported\n return [];\n }\n\n \\Sentry::captureException($exception);\n\n return [];\n }\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n if ($this->copperClient === null) {\n return false;\n }\n\n $task = $this->copperClient->tasks()->find($crmProviderId);\n\n return ! empty($task);\n } catch (HttpNotFoundException) {\n // Task not found in CRM - this is expected and permanent\n $this->logger->info('[Copper] Task not found during verification', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n } catch (RequestFailedException $e) {\n // Handle 404 responses from Copper API\n if ($e->getCode() === 404) {\n $this->logger->info('[Copper] Task not found during verification (404)', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n\n // Re-throw other Copper exceptions for retry\n throw $e;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\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.85486114,"top":0.31,"width":0.018055556,"height":0.026666667},"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.87291664,"top":0.31,"width":0.018055556,"height":0.026666667},"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":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"on_screen":false,"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":false,"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":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"on_screen":false,"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":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"bounds":{"left":0.9138889,"top":0.31,"width":0.059027776,"height":0.026666667},"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":"8","depth":4,"bounds":{"left":0.8645833,"top":0.34444445,"width":0.016666668,"height":0.02111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.8854167,"top":0.34444445,"width":0.015277778,"height":0.02111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.9048611,"top":0.34444445,"width":0.016666668,"height":0.02111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"bounds":{"left":0.92569447,"top":0.34444445,"width":0.016666668,"height":0.02111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9458333,"top":0.3422222,"width":0.015277778,"height":0.025555555},"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.9611111,"top":0.3422222,"width":0.014583333,"height":0.025555555},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"SELECT\n# DISTINCT\nopp.id as opp_id, opp.uuid, opp.name,\n# COUNT(dr.id) AS deal_risk_count,\n\n# dr.id,\n# cfd.value,\nusr.name AS owner_name,\nopp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,\nusr.uuid as owner_uuid,\nusr.photo_path as owner_photo,\nusr.id AS owner_id,\njt.name as owner_job,\nopp.stage_id, opp.stage_updated_at,\nacc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,\nrt.business_process_id AS pipeline_id\nFROM opportunities opp\nLEFT JOIN record_types rt ON opp.record_type_id = rt.id\nLEFT JOIN users usr ON opp.user_id = usr.id\nLEFT JOIN accounts acc ON opp.account_id = acc.id\nLEFT JOIN job_titles jt ON usr.job_title_id = jt.id\n\n# LEFT JOIN group_deal_risk_types gdrt ON gdrt.group_id = usr.group_id\n# LEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id AND dr.group_deal_risk_type_id = gdrt.id\n\nLEFT JOIN crm_field_data cfd ON (cfd.object_id = opp.id and cfd.crm_field_id = 66814)\n\nWHERE opp.user_id IS NOT NULL\nAND opp.deleted_at IS NULL\nAND opp.is_closed = 1\nAND opp.is_won = 0\nAND opp.close_date >= '2024-01-01 00:00:00'\nAND opp.close_date <= '2024-12-31 23:59:59'\nAND usr.team_id = 1\n\n# and opp.id = 4823179\n\nGROUP BY opp.id, cfd.value\nORDER BY\n# cfd.value\n CAST(cfd.value AS UNSIGNED)\n# owner_name\n# (SELECT COUNT(dr.id)\n# FROM deal_risks dr\n# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n# WHERE dr.opportunity_id = opp.id\n# AND dr.is_active = 1\n# AND gdrt.is_enabled = 1)\nDESC\nLIMIT 25\n# OFFSET 0\n;\n\nselect * from crm_fields where crm_configuration_id = 1 and object_type = 'opportunity';\nselect * from crm_layout_entities where crm_layout_id = 1493;\n\nSELECT * FROM opportunities WHERE id = 4584045;\nSELECT * FROM crm_field_data WHERE object_id = 4584045;\n\nSELECT * FROM opportunities where team_id = 1 and crm_provider_id = '0061K00000lfb9IQAQ'\n\nSELECT\n opp.id as opportunity_id,\n opp.name,\n COUNT(dr.id) as risk_count\nFROM opportunities opp\nLEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id\nWHERE opp.id IN (\n 6069574,8900938,9507638,9524799,9660490,9662824,9705675,9749758,4158460,4391812,6450439,4448422,5118945,5590675,4584045,7228149,9002408,9165534,9446720,9641778,9665149,9703344,9709280,5747948,4158491,6182565,6263970,5798120,5111315,4536978,6062352,6548383,6072095,6548225,4480986,5011422,6548381,8760540,8917554,9509986,9514392,9569009,9569011,9578490,9713604,5784397,7276612,7288405,8994421,9118219,9608148,9818911,4510535,6479693,5958049,6271674,6550448,4158331,4158483,6126571,6171615,6540943,4897466,5190896,5796182,5932762,8572433,8723698,8892697,9711001,9789264,4549188,6100831,6170064,6260799,6263653,6449936,6530871,6538978,7777651,8059269,8319918,8787049,8901150,9263153,9453207,9514738,9696700,9791062,5752018,6421452,7439134,7878923,9354763,9369285,9514396,9582506,9889949,9890216,4094311,4158495,4158496,6098128,5585661,3872564,6442149,5891604,6164746,6199593,6583474,6519684,9018490,9809006,4496897,5041324,5829430,6198319,6253504,6555763,7242914,7931055,8024125,8797814,8058559,8673347,8892695,8994420,9616219,9714970,9722004,9809439,9818918,6523177,8134147,9002915,9711422,9892713,9901719,9954210,9978435,5800810,6243518,6416114,6222251,6411974,6512456,5791953,6545606,9914780,5805540,6238986,6463838,6547680,9767049,9809437,9810885,9890855,6673493,9902036,4335521,6379871,6503799,6546077,8018765,9907556,9958433,9905855,9916179,9946741,9957877,5563344,6271838,6450815,7641128,7762567,7780592,8684810,8685786,8685787,8685788\n)\nGROUP BY opp.id;\n\nSELECT COUNT(dr.id)\n FROM deal_risks dr\n JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n WHERE dr.opportunity_id = 5563344\n# AND gdrt.group_id = usr.group_id\n\n\n\nEXPLAIN SELECT\n opp.id as opp_id, opp.uuid, opp.name,\n\ncfd.value,\ncfv.sequence,\ncfv.value,\n# MAX(cfd.value) AS max_cfd_value,\nusr.name AS owner_name,\nopp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,\nusr.uuid as owner_uuid,\nusr.photo_path as owner_photo,\nusr.id AS owner_id,\njt.name as owner_job,\nopp.stage_id, opp.stage_updated_at,\nacc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,\nrt.business_process_id AS pipeline_id\nFROM opportunities opp\n\nLEFT JOIN record_types rt ON opp.record_type_id = rt.id\nLEFT JOIN users usr ON opp.user_id = usr.id\nLEFT JOIN accounts acc ON opp.account_id = acc.id\nLEFT JOIN job_titles jt ON usr.job_title_id = jt.id\n\nLEFT JOIN crm_field_data cfd ON cfd.id = (SELECT sub_cfd.id\n FROM crm_field_data sub_cfd\n WHERE sub_cfd.object_id = opp.id\n AND sub_cfd.crm_field_id = 66810\n ORDER BY sub_cfd.updated_at DESC\n LIMIT 1)\n\nLEFT JOIN crm_field_values cfv ON cfv.crm_field_id = 66810 AND cfv.value = cfd.value\n\nWHERE opp.user_id IS NOT NULL\nAND opp.deleted_at IS NULL\nAND opp.is_closed = 0\n# AND opp.is_closed = 1\n# AND opp.is_won = 0\nAND opp.close_date >= '2024-01-01 00:00:00'\nAND opp.close_date <= '2024-12-31 23:59:59'\nAND usr.team_id = 1\n\n# and opp.id = 4823179\n\n# GROUP BY opp.id\nORDER BY\n cfv.sequence DESC,\n# opp.name\n# owner_name\n cfd.value\n# CAST(cfd.value AS UNSIGNED)\n# CAST(MAX(cfd.value) AS UNSIGNED)\n# (SELECT COUNT(dr.id)\n# FROM deal_risks dr\n# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n# WHERE dr.opportunity_id = opp.id\n# AND dr.is_active = 1 AND gdrt.is_enabled = 1)\nDESC\n# LIMIT 75, 25\n;\n\n\n\nSELECT * FROM crm_field_values WHERE crm_field_id = 66810;\n\nSELECT f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value, fd.updated_at, fd.id, fd.created_at\nFROM crm_fields f\nINNER JOIN crm_field_data fd ON fd.crm_field_id = f.id\n WHERE (f.crm_configuration_id = 1)\n AND (f.object_type = 'opportunity')\n# AND (fd.object_id IN (4158331,4158483,4158495,4158496,6069574,6263970,6171615,6540943,6545606,5829430,6198319,6263653,6548381,7242914,8797814,7228149,7439134,7878923,8134147,9002915,9118219,9165534,9354763,9369285,9446720))\n AND (fd.object_id IN (4158460))\n AND (f.crm_provider_id IN ('ForecastCategoryName'))\n ORDER BY fd.object_id ASC, fd.updated_at DESC;\n\nselect * from crm_layouts where crm_configuration_id = 1;\nselect cf.* from crm_fields cf\njoin crm_layout_entities cle on cf.id = cle.crm_field_id\nwhere crm_layout_id = 1493;\n\nSELECT * FROM opportunities WHERE id = 4158460;\nSELECT * FROM crm_field_data WHERE object_id = 4158460;\n\nselect * from users where team_id = 1;\nSELECT * FROM users WHERE id = 7160;\nselect * from role_user where user_id = 3248;\n\nselect * from crm_field_values where crm_field_id = 66824;\n\nSELECT * FROM users WHERE id = 23470;\nselect * from crm_configurations;\n\n# ******************************************\nselect * from teams where id = 1038; # 23521, 966\nselect * from users where team_id = 1038;\nselect * from crm_configurations where id = 966;\nSELECT * FROM activities WHERE uuid_to_bin('e8dc7c34-31f6-4430-bd81-2d9d8f00dd07') = uuid; # 54965762\nSELECT * FROM activities WHERE uuid_to_bin('4b5727c0-69d1-428f-b8d9-b649055166e2') = uuid; # 54965764\nSELECT * FROM participants WHERE activity_id = 54965764;\n\nSELECT id, uuid, title, recording_state FROM activities WHERE uuid_to_bin('355f105d-5606-4379-b0c5-d91daf59f4ce') = uuid; # 54964075\nSELECT * FROM participants WHERE activity_id = 54964075;\nselect f.id, slug, title, tf.team_id from team_features tf JOIN features f on tf.feature_id = f.id\n where tf.team_id = 1038;\n\n\n# ****************************************** PD *************************\nselect * from teams where id = 1029;\nSELECT * FROM crm_configurations WHERE id = 957;\nSELECT * FROM activities WHERE uuid_to_bin('581a33cb-4343-44bd-ac0c-4a5cee71c5ec') = uuid; # 54963423\nSELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433\n\nSELECT * FROM activities WHERE uuid_to_bin('8b6bb2f7-e7a7-4aec-8806-fbfea7093ccd') = uuid; # 54963421\n\n# ****************************************** Close *************************\nselect * from teams where id = 1031;\nSELECT * FROM crm_configurations WHERE id = 959;\nSELECT * FROM activities WHERE uuid_to_bin('59c517e0-96c9-4dad-bfeb-b7bef72f8725') = uuid; # 54963517\n\n\nSELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433\n\nSELECT * FROM activities WHERE uuid_to_bin('d68311e3-ac34-49bd-bf04-88323a7e5352') = uuid; # 54966009\n\n# ****************************************** SF *************************\nSELECT * FROM activities WHERE uuid_to_bin('2bd4cfa3-4eb5-4c77-84a7-9ed46a21c988') = uuid;\n\nselect * from roles;\nselect * from permissions;\nselect * from permission_role where permission_id = 136;\n\nselect * from migrations order by id desc;\n\nselect * from teams where id IN (1, 1037);\nselect * from crm_layouts where crm_configuration_id = 1;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1493;\nSELECT * FROM crm_fields WHERE id IN (1652,1661,66799,66814,66821,66836,66843,66846,66864,84752,182306,323580,380378);\n\nselect * from features;\nselect * from team_features where feature_id = 33;\nselect * from opportunities;\n\nselect * from teams;\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 = 1052 and sa.provider = 'hubspot';\n\nSELECT * FROM accounts where id = 11512582;\nselect * from activities where account_id = 11512582;","depth":4,"on_screen":true,"value":"SELECT\n# DISTINCT\nopp.id as opp_id, opp.uuid, opp.name,\n# COUNT(dr.id) AS deal_risk_count,\n\n# dr.id,\n# cfd.value,\nusr.name AS owner_name,\nopp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,\nusr.uuid as owner_uuid,\nusr.photo_path as owner_photo,\nusr.id AS owner_id,\njt.name as owner_job,\nopp.stage_id, opp.stage_updated_at,\nacc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,\nrt.business_process_id AS pipeline_id\nFROM opportunities opp\nLEFT JOIN record_types rt ON opp.record_type_id = rt.id\nLEFT JOIN users usr ON opp.user_id = usr.id\nLEFT JOIN accounts acc ON opp.account_id = acc.id\nLEFT JOIN job_titles jt ON usr.job_title_id = jt.id\n\n# LEFT JOIN group_deal_risk_types gdrt ON gdrt.group_id = usr.group_id\n# LEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id AND dr.group_deal_risk_type_id = gdrt.id\n\nLEFT JOIN crm_field_data cfd ON (cfd.object_id = opp.id and cfd.crm_field_id = 66814)\n\nWHERE opp.user_id IS NOT NULL\nAND opp.deleted_at IS NULL\nAND opp.is_closed = 1\nAND opp.is_won = 0\nAND opp.close_date >= '2024-01-01 00:00:00'\nAND opp.close_date <= '2024-12-31 23:59:59'\nAND usr.team_id = 1\n\n# and opp.id = 4823179\n\nGROUP BY opp.id, cfd.value\nORDER BY\n# cfd.value\n CAST(cfd.value AS UNSIGNED)\n# owner_name\n# (SELECT COUNT(dr.id)\n# FROM deal_risks dr\n# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n# WHERE dr.opportunity_id = opp.id\n# AND dr.is_active = 1\n# AND gdrt.is_enabled = 1)\nDESC\nLIMIT 25\n# OFFSET 0\n;\n\nselect * from crm_fields where crm_configuration_id = 1 and object_type = 'opportunity';\nselect * from crm_layout_entities where crm_layout_id = 1493;\n\nSELECT * FROM opportunities WHERE id = 4584045;\nSELECT * FROM crm_field_data WHERE object_id = 4584045;\n\nSELECT * FROM opportunities where team_id = 1 and crm_provider_id = '0061K00000lfb9IQAQ'\n\nSELECT\n opp.id as opportunity_id,\n opp.name,\n COUNT(dr.id) as risk_count\nFROM opportunities opp\nLEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id\nWHERE opp.id IN (\n 6069574,8900938,9507638,9524799,9660490,9662824,9705675,9749758,4158460,4391812,6450439,4448422,5118945,5590675,4584045,7228149,9002408,9165534,9446720,9641778,9665149,9703344,9709280,5747948,4158491,6182565,6263970,5798120,5111315,4536978,6062352,6548383,6072095,6548225,4480986,5011422,6548381,8760540,8917554,9509986,9514392,9569009,9569011,9578490,9713604,5784397,7276612,7288405,8994421,9118219,9608148,9818911,4510535,6479693,5958049,6271674,6550448,4158331,4158483,6126571,6171615,6540943,4897466,5190896,5796182,5932762,8572433,8723698,8892697,9711001,9789264,4549188,6100831,6170064,6260799,6263653,6449936,6530871,6538978,7777651,8059269,8319918,8787049,8901150,9263153,9453207,9514738,9696700,9791062,5752018,6421452,7439134,7878923,9354763,9369285,9514396,9582506,9889949,9890216,4094311,4158495,4158496,6098128,5585661,3872564,6442149,5891604,6164746,6199593,6583474,6519684,9018490,9809006,4496897,5041324,5829430,6198319,6253504,6555763,7242914,7931055,8024125,8797814,8058559,8673347,8892695,8994420,9616219,9714970,9722004,9809439,9818918,6523177,8134147,9002915,9711422,9892713,9901719,9954210,9978435,5800810,6243518,6416114,6222251,6411974,6512456,5791953,6545606,9914780,5805540,6238986,6463838,6547680,9767049,9809437,9810885,9890855,6673493,9902036,4335521,6379871,6503799,6546077,8018765,9907556,9958433,9905855,9916179,9946741,9957877,5563344,6271838,6450815,7641128,7762567,7780592,8684810,8685786,8685787,8685788\n)\nGROUP BY opp.id;\n\nSELECT COUNT(dr.id)\n FROM deal_risks dr\n JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n WHERE dr.opportunity_id = 5563344\n# AND gdrt.group_id = usr.group_id\n\n\n\nEXPLAIN SELECT\n opp.id as opp_id, opp.uuid, opp.name,\n\ncfd.value,\ncfv.sequence,\ncfv.value,\n# MAX(cfd.value) AS max_cfd_value,\nusr.name AS owner_name,\nopp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,\nusr.uuid as owner_uuid,\nusr.photo_path as owner_photo,\nusr.id AS owner_id,\njt.name as owner_job,\nopp.stage_id, opp.stage_updated_at,\nacc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,\nrt.business_process_id AS pipeline_id\nFROM opportunities opp\n\nLEFT JOIN record_types rt ON opp.record_type_id = rt.id\nLEFT JOIN users usr ON opp.user_id = usr.id\nLEFT JOIN accounts acc ON opp.account_id = acc.id\nLEFT JOIN job_titles jt ON usr.job_title_id = jt.id\n\nLEFT JOIN crm_field_data cfd ON cfd.id = (SELECT sub_cfd.id\n FROM crm_field_data sub_cfd\n WHERE sub_cfd.object_id = opp.id\n AND sub_cfd.crm_field_id = 66810\n ORDER BY sub_cfd.updated_at DESC\n LIMIT 1)\n\nLEFT JOIN crm_field_values cfv ON cfv.crm_field_id = 66810 AND cfv.value = cfd.value\n\nWHERE opp.user_id IS NOT NULL\nAND opp.deleted_at IS NULL\nAND opp.is_closed = 0\n# AND opp.is_closed = 1\n# AND opp.is_won = 0\nAND opp.close_date >= '2024-01-01 00:00:00'\nAND opp.close_date <= '2024-12-31 23:59:59'\nAND usr.team_id = 1\n\n# and opp.id = 4823179\n\n# GROUP BY opp.id\nORDER BY\n cfv.sequence DESC,\n# opp.name\n# owner_name\n cfd.value\n# CAST(cfd.value AS UNSIGNED)\n# CAST(MAX(cfd.value) AS UNSIGNED)\n# (SELECT COUNT(dr.id)\n# FROM deal_risks dr\n# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n# WHERE dr.opportunity_id = opp.id\n# AND dr.is_active = 1 AND gdrt.is_enabled = 1)\nDESC\n# LIMIT 75, 25\n;\n\n\n\nSELECT * FROM crm_field_values WHERE crm_field_id = 66810;\n\nSELECT f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value, fd.updated_at, fd.id, fd.created_at\nFROM crm_fields f\nINNER JOIN crm_field_data fd ON fd.crm_field_id = f.id\n WHERE (f.crm_configuration_id = 1)\n AND (f.object_type = 'opportunity')\n# AND (fd.object_id IN (4158331,4158483,4158495,4158496,6069574,6263970,6171615,6540943,6545606,5829430,6198319,6263653,6548381,7242914,8797814,7228149,7439134,7878923,8134147,9002915,9118219,9165534,9354763,9369285,9446720))\n AND (fd.object_id IN (4158460))\n AND (f.crm_provider_id IN ('ForecastCategoryName'))\n ORDER BY fd.object_id ASC, fd.updated_at DESC;\n\nselect * from crm_layouts where crm_configuration_id = 1;\nselect cf.* from crm_fields cf\njoin crm_layout_entities cle on cf.id = cle.crm_field_id\nwhere crm_layout_id = 1493;\n\nSELECT * FROM opportunities WHERE id = 4158460;\nSELECT * FROM crm_field_data WHERE object_id = 4158460;\n\nselect * from users where team_id = 1;\nSELECT * FROM users WHERE id = 7160;\nselect * from role_user where user_id = 3248;\n\nselect * from crm_field_values where crm_field_id = 66824;\n\nSELECT * FROM users WHERE id = 23470;\nselect * from crm_configurations;\n\n# ******************************************\nselect * from teams where id = 1038; # 23521, 966\nselect * from users where team_id = 1038;\nselect * from crm_configurations where id = 966;\nSELECT * FROM activities WHERE uuid_to_bin('e8dc7c34-31f6-4430-bd81-2d9d8f00dd07') = uuid; # 54965762\nSELECT * FROM activities WHERE uuid_to_bin('4b5727c0-69d1-428f-b8d9-b649055166e2') = uuid; # 54965764\nSELECT * FROM participants WHERE activity_id = 54965764;\n\nSELECT id, uuid, title, recording_state FROM activities WHERE uuid_to_bin('355f105d-5606-4379-b0c5-d91daf59f4ce') = uuid; # 54964075\nSELECT * FROM participants WHERE activity_id = 54964075;\nselect f.id, slug, title, tf.team_id from team_features tf JOIN features f on tf.feature_id = f.id\n where tf.team_id = 1038;\n\n\n# ****************************************** PD *************************\nselect * from teams where id = 1029;\nSELECT * FROM crm_configurations WHERE id = 957;\nSELECT * FROM activities WHERE uuid_to_bin('581a33cb-4343-44bd-ac0c-4a5cee71c5ec') = uuid; # 54963423\nSELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433\n\nSELECT * FROM activities WHERE uuid_to_bin('8b6bb2f7-e7a7-4aec-8806-fbfea7093ccd') = uuid; # 54963421\n\n# ****************************************** Close *************************\nselect * from teams where id = 1031;\nSELECT * FROM crm_configurations WHERE id = 959;\nSELECT * FROM activities WHERE uuid_to_bin('59c517e0-96c9-4dad-bfeb-b7bef72f8725') = uuid; # 54963517\n\n\nSELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433\n\nSELECT * FROM activities WHERE uuid_to_bin('d68311e3-ac34-49bd-bf04-88323a7e5352') = uuid; # 54966009\n\n# ****************************************** SF *************************\nSELECT * FROM activities WHERE uuid_to_bin('2bd4cfa3-4eb5-4c77-84a7-9ed46a21c988') = uuid;\n\nselect * from roles;\nselect * from permissions;\nselect * from permission_role where permission_id = 136;\n\nselect * from migrations order by id desc;\n\nselect * from teams where id IN (1, 1037);\nselect * from crm_layouts where crm_configuration_id = 1;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1493;\nSELECT * FROM crm_fields WHERE id IN (1652,1661,66799,66814,66821,66836,66843,66846,66864,84752,182306,323580,380378);\n\nselect * from features;\nselect * from team_features where feature_id = 33;\nselect * from opportunities;\n\nselect * from teams;\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 = 1052 and sa.provider = 'hubspot';\n\nSELECT * FROM accounts where id = 11512582;\nselect * from activities where account_id = 11512582;","role_description":"text entry area","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.025,"top":0.06666667,"width":0.050694443,"height":0.034444444},"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.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":"Expand Selected","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":"Collapse All","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":"Options","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":"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}]...
|
8957564869086018857
|
-7959665055215941403
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
11
72
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Copper;
use Carbon\Carbon;
use Exception;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Support\Facades\Cache;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\CopperInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Crm\LayoutEntity;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Repositories\UserRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Copper\Api\Client;
use Jiminny\Services\Crm\Copper\Api\ClientFactory;
use Jiminny\Services\Crm\Copper\Exception\RequestFailedException;
use Jiminny\Services\Crm\Helpers\FilterJoinedParticipants;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\Copper\Traits\SearchesCrmEntities;
use Jiminny\Utils\CurrencyFormatter;
use Jiminny\Utils\StringUtil;
class Service extends BaseService implements
CopperInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
RemoteEntityManipulationInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use SearchesCrmEntities;
private const int NOTE_BODY_MAX_LENGTH = 3000000;
private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day
private const array STANDARD_OPPORTUNITY_FIELDS = [
'monetary_value' => [
'label' => 'Value',
'available_on' => Field::OBJECT_OPPORTUNITY,
'type' => Field::TYPE_CURRENCY,
],
'pipeline_stage_id' => [
'label' => 'Stage',
'type' => Field::TYPE_PICKLIST,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
'close_date' => [
'label' => 'Close date',
'type' => Field::TYPE_DATE,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
'win_probability' => [
'label' => 'Win probability',
'type' => Field::TYPE_NUMBER,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
];
private const string UNSUPPORTED_OBJECT_TYPE = 'unsupported';
private const string OPPORTUNITY_STATUS_OPEN = 'Open';
private const string OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE = 'Opportunity import failed';
private const string RESOURCE_UPDATE_FAILED_ERROR_MESSAGE = 'Failed to update resource';
private FieldValueConverter $fieldValueConverter;
private ClientFactory $clientFactory;
private ?Client $copperClient = null;
public function __construct(
ClientFactory $clientFactory,
FieldValueConverter $fieldValueConverter,
private readonly UserRepository $userRepository,
private readonly ProspectPhotoPathService $prospectPhotoPathService,
private readonly CrmEntityRepository $crmEntityRepository
) {
parent::__construct();
$this->clientFactory = $clientFactory;
$this->fieldValueConverter = $fieldValueConverter;
}
public function getDisplayName(): string
{
return 'Copper';
}
/**
* Get the CRM entity repository (used by SearchesCrmEntities trait)
*/
protected function getCrmEntityRepository(): CrmEntityRepository
{
return $this->crmEntityRepository;
}
public function getMinimumApiVersion(): string
{
return Client::MIN_API_VERSION;
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
$owner = $user->team->owner;
return $owner->getSocialAccount(SocialAccount::PROVIDER_COPPER);
}
public function setUser(User $user): void
{
$this->configureSentryScope($user);
$this->team = $user->getTeam();
$this->teamService->setTeam($user->getTeam());
$this->setConfiguration($user->getTeam()->getCrmConfiguration());
// Reset state.
$this->profile = $user->getProfile();
if (! $this->profile instanceof Profile) {
// Try to fetch their profile, maybe it was not yet imported?
$this->profile = $this->getProfile($user);
}
}
public function setConfiguration(Configuration $configuration): void
{
$this->config = $configuration;
$this->copperClient = $this->clientFactory->create($configuration);
if ($this->team === null) {
$this->team = $configuration->getTeam();
}
}
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);
}
private function mapObjectType(string $objectType): string
{
$objectType = strtolower($objectType);
switch ($objectType) {
case Field::OBJECT_TASK:
case Field::OBJECT_OPPORTUNITY:
case Field::OBJECT_LEAD:
$mappedType = $objectType;
break;
case Field::OBJECT_ACCOUNT:
$mappedType = 'company';
break;
case Field::OBJECT_CONTACT:
$mappedType = 'person';
break;
default:
$mappedType = self::UNSUPPORTED_OBJECT_TYPE;
break;
}
return $mappedType;
}
/**
* @param string $crmObject The name of the CRM object. i.e. Opportunity or Contact
*/
protected function getFields(string $crmObject): array
{
$mappedObjectType = $this->mapObjectType($crmObject);
if (! $this->isSupportedObjectType($mappedObjectType)) {
return [];
}
$customFields = $this->copperClient->fields()->all();
$filteredFields = array_filter(
$customFields,
static fn ($field) => in_array($mappedObjectType, $field['available_on'], true)
);
return array_map(
fn (array $property) => [
'name' => $property['id'],
'label' => $property['name'],
'type' => $this->convertFieldType($property['data_type']),
],
$filteredFields
);
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
// Setup the activity field as the default Type.
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'type',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldFilters = FieldDefinitions::taskFollowupFieldsFilter();
foreach ($fieldFilters as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
public function syncFields(): void
{
$this->syncStandardFields();
$this->syncCustomFields();
}
public function syncField(Field $field): void
{
if ($field->getCrmProviderId() === 'type') {
/**
* This field is a special case, it is not a custom field and is not returned by the Copper API.
*
* The field is created manually during layout setup.
*
* @see getDefaultFields()
*
* There is a separate endpoint to get the activity types.
* @see importPicklistValues()
*/
return;
}
if ($field->getCrmProviderId() === 'pipeline_stage_id') {
// Not a custom type
return;
}
$crmField = $this->copperClient->fields()->find($field->getCrmProviderId());
$field->label = $crmField['name'];
$field->type = $this->convertFieldType($crmField['data_type']);
$field->save();
}
/**
* @param string $fieldType How the data should be input
*/
private function convertFieldType(string $fieldType): string
{
$fieldType = strtolower($fieldType);
switch ($fieldType) {
case 'dropdown':
$convertedType = Field::TYPE_PICKLIST;
break;
case 'string':
$convertedType = Field::TYPE_TEXT;
break;
case 'float':
case 'percentage':
$convertedType = Field::TYPE_NUMBER;
break;
case 'text':
$convertedType = Field::TYPE_TEXTAREA;
break;
case 'checkbox':
$convertedType = Field::TYPE_BOOLEAN;
break;
case Field::TYPE_DATE:
case Field::TYPE_CURRENCY:
case Field::TYPE_URL:
$convertedType = $fieldType;
break;
default:
$convertedType = Field::TYPE_UNSUPPORTED;
break;
}
return $convertedType;
}
/**
* @inheritdoc
*/
public function importPicklistValues(Field $field): array
{
$fieldValues = [];
if ($field->object_type === 'opportunity' && $field->crm_provider_id === 'pipeline_stage_id') {
return $this->importFieldValuesForDealInsights($field);
}
$values = [];
if ($field->object_type === Field::OBJECT_TASK && $field->crm_provider_id === 'type') {
$activityTypes = $this->copperClient->activityTypes()->all();
/**
* We ignore "system" activity types, disabled activity types and the "Note" activity type.
*/
$activityTypes = array_filter(
$activityTypes['user'],
fn (array $activityType) => ! $activityType['is_disabled'] && $activityType['id'] !== 0
);
// Import all activity values.
$i = 0;
foreach ($activityTypes as $activityType) {
$values[] = [
'value' => $activityType['id'],
'label' => mb_strimwidth($activityType['name'], 0, Field::LABEL_MAX_LENGTH),
'sequence' => $i++,
];
}
} else {
// We just check for the field in the custom definitions.
$crmField = $this->copperClient->fields()->find($field->crm_provider_id);
// Import all values.
foreach ($crmField['options'] as $option) {
$values[] = [
'value' => $option['id'],
'label' => mb_strimwidth($option['name'], 0, 191),
'sequence' => $option['rank'],
];
}
}
// Take the existing set of field values.
$fieldsToPurge = $field->values()->get()->pluck('value')->toArray();
foreach ($values as $value) {
// For all current values, upsert the field.
$value['value'] = substr($value['value'] ?? '', 0, 255);
$fieldValues[] = $field->values()->updateOrCreate([
'value' => $value['value'],
], $value);
// Remove this value from the ones we are going to purge.
$key = array_search($value['value'], $fieldsToPurge, false);
if ($key !== false) {
unset($fieldsToPurge[$key]);
}
}
// Delete the old values that are no longer used.
$field->values()->whereIn('value', $fieldsToPurge)->delete();
return $fieldValues;
}
/**
*
* @return FieldValue[]
*/
private function importFieldValuesForDealInsights(Field $field): array
{
$fieldValues = [];
$pipelines = $this->copperClient->pipelines()->all();
foreach ($pipelines as $pipeline) {
foreach ($pipeline['stages'] as $i => $dealStage) {
$fieldValues[] = $field->values()->updateOrCreate(
['value' => $dealStage['id']],
[
'label' => $dealStage['name'],
'sequence' => $i,
]
);
}
}
return $fieldValues;
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
if ($types === null) {
$types = [Stage::TYPE_LEAD, Stage::TYPE_OPPORTUNITY];
}
$missingStage = null;
foreach ($types as $type) {
if ($type === Stage::TYPE_LEAD) {
$statuses = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leadStatuses()->all()
);
if (count($statuses) > 0) {
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => BusinessProcess::TYPE_LEAD,
], [
'team_id' => $this->team->id,
'name' => BusinessProcess::TYPE_LEAD,
'type' => BusinessProcess::TYPE_LEAD,
'is_selectable' => true,
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => BusinessProcess::TYPE_LEAD,
], [
'team_id' => $this->team->id,
'name' => BusinessProcess::TYPE_LEAD,
'is_selectable' => true,
'business_process_id' => $businessProcess->id ?? null,
]);
$leadStatuses = [];
foreach ($statuses as $status) {
// Upsert all statuses for the team.
$status = $this->config->stages()->updateOrCreate([
'crm_provider_id' => $status['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($status['name'], 0, 50),
'label' => mb_strimwidth($status['name'], 0, 191),
'type' => Stage::TYPE_LEAD,
'sequence' => $status['order'],
'is_selectable' => true,
]);
if ($missingStageName && $missingStageName === $status['id']) {
$missingStage = $status;
}
$leadStatuses[] = $status['id'];
}
$businessProcess->stages()->sync($leadStatuses);
}
} else {
// We create a business process to contain the pipeline, and later store all stages against it.
foreach ($this->copperClient->pipelines()->all() as $pipeline) {
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $pipeline['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($pipeline['name'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => true,
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $pipeline['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($pipeline['name'], 0, 150),
'is_selectable' => true,
'business_process_id' => $businessProcess->id ?? null,
]);
$stages = [];
foreach ($pipeline['stages'] as $i => $dealStage) {
// Upsert all stages for the team.
$stage = $this->config->stages()->updateOrCreate([
'crm_provider_id' => $dealStage['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($dealStage['name'], 0, 50),
'label' => mb_strimwidth($dealStage['name'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $i,
'is_selectable' => true,
'probability' => $dealStage['win_probability'],
]);
if ($missingStageName && $missingStageName === $dealStage['id']) {
$missingStage = $stage;
}
$stages[] = $stage['id'];
}
$businessProcess->stages()->sync($stages);
}
}
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int
{
$syncCount = 0;
$cpLeads = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->paginate([
'minimum_modified_date' => $since->timestamp,
'sort_by' => 'date_modified',
])
);
foreach ($cpLeads as $cpLead) {
// Only sync if previously imported.
if ($this->hasLead($cpLead['id']) === false) {
$this->importLead($cpLead);
$syncCount++;
}
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncLead(string $crmId): ?Lead
{
$cpLead = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->find($crmId)
);
if (\count($cpLead) === 0) {
return null;
}
return $this->importLead($cpLead);
}
/**
* @inheritdoc
*/
private function importLead($crmData): ?Lead
{
$countryCode = null;
if (! empty($crmData['address']) && isset($crmData['address']['country'])) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$mobilePhone = $parsedNumber = null;
if (! empty($crmData['phone_numbers'])) {
foreach ($crmData['phone_numbers'] as $phoneNumber) {
if ($phoneNumber['category'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);
} else {
$parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);
}
}
}
$name = $crmData['name'];
if (empty($crmData['company_name'])) {
$company = 'Unknown';
} else {
$company = mb_strimwidth($crmData['company_name'], 0, 191);
}
$domain = null;
if (empty($crmData['websites']) === false) {
$domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);
$domain = StringUtil::resolveDomain($domain);
}
$email = null;
if (empty($crmData['email']) === false) {
$email = mb_strimwidth($crmData['email']['email'], 0, 80);
}
$stage = $this->config
->stages()
->where('crm_provider_id', (string) $crmData['status_id'])
->where('type', Stage::TYPE_LEAD)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_LEAD], $crmData['status_id']);
}
if (! $stage instanceof Stage) {
return null;
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($name, 0, 191),
'company' => $company,
'domain' => $domain,
'title' => $crmData['title'] ? mb_strimwidth($crmData['title'], 0, 128) : null,
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'mobile_phone' => $mobilePhone,
'stage_id' => $stage->id,
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Lead::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'country_code' => $countryCode,
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->leads()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
/**
* @inheritdoc
*/
public function syncAccounts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
$cpAccounts = $this->copperClient->accounts()->paginate([
'minimum_modified_date' => $since->timestamp,
'sort_by' => 'date_modified',
]);
foreach ($cpAccounts as $cpAccount) {
// Only sync if previously imported.
if ($this->hasAccount($cpAccount['id'])) {
$this->importAccount($cpAccount);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncAccount(string $crmId): ?Account
{
$cpAccount = $this->copperClient->accounts()->find($crmId);
if (empty($cpAccount)) {
return null;
}
return $this->importAccount($cpAccount);
}
/**
* @inheritdoc
*/
private function importAccount($crmData): Account
{
$countryCode = null;
if (empty($crmData['address']) === false && $crmData['address']['country']) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$name = $crmData['name'];
$parsedNumber = null;
foreach ($crmData['phone_numbers'] as $phoneNumber) {
$parsedNumber = parsePhoneNumber($countryCode, $phoneNumber['number']);
}
$domain = null;
if (empty($crmData['websites']) === false) {
$domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);
$domain = StringUtil::resolveDomain($domain);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($name, 0, 191),
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Account::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'country_code' => $countryCode,
'domain' => $domain,
'phone' => $parsedNumber['phone'] ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->accounts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
public function syncOpportunities(array $parameters, ?string $strategy = null): int
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->copperClient,
]);
$strategies = $strategyResolver->getStrategies($this->config, $strategy);
$syncCount = 0;
try {
foreach ($strategies as $syncStrategy) {
foreach ($syncStrategy->fetchOpportunities($parameters) as $opportunityData) {
$this->importOpportunity($opportunityData);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
$this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => $exception->getMessage(),
]);
}
return $syncCount;
}
public function syncOpportunity(string $crmId): ?Opportunity
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->copperClient,
]);
$strategy = $strategyResolver->resolve(
$this->config,
OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY
);
$parameters['crm_id'] = $crmId;
$cpOpportunity = $strategy->fetchOpportunities($parameters);
return $this->importOpportunity($cpOpportunity);
}
private function importOpportunity($crmData): ?Opportunity
{
$companyId = (string) $crmData['company_id'];
if (empty($companyId)) {
$this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => 'No company id',
]);
return null;
}
$account = $this->config->accounts()->where('crm_provider_id', $companyId)->first();
if ($account === null) {
$account = $this->syncAccount($companyId);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', (string) $crmData['pipeline_id'])
->first();
if ($businessProcess === null) {
// It is possible for some deals to not be in a pipeline.
$this->logger->warning(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => 'Missing pipeline',
]);
return null;
}
$stage = $businessProcess
->stages()
->where('crm_provider_id', (string) $crmData['pipeline_stage_id'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
$this->logger->info('Stage not found, importing', [
'pipeline_id' => $crmData['pipeline_id'],
'stage_id' => $crmData['pipeline_stage_id'],
]);
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData['pipeline_stage_id']);
}
$recordType = $businessProcess->recordTypes()->first();
$closeDate = null;
$isClosed = $crmData['status'] !== self::OPPORTUNITY_STATUS_OPEN;
if ($crmData['close_date']) {
$closeDate = Carbon::parse($crmData['close_date'])->format('Y-m-d');
}
$data = [
'team_id' => $this->team->getId(),
'account_id' => $account->id,
'user_id' => $profile->user_id ?? null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($crmData['name'], 0, 128),
'value' => $crmData['monetary_value'],
'currency_code' => CurrencyFormatter::formatCode($crmData['monetary_unit']),
'close_date' => $closeDate,
'is_closed' => $isClosed,
'is_won' => $crmData['status'] === 'Won',
'stage_id' => $stage->id,
'record_type_id' => $recordType->id ?? null,
'remotely_created_at' => $crmData['date_created'],
];
/** @var Opportunity $opportunity */
$opportunity = $this->config
->opportunities()
->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data)
;
// import external fields into crm_field_data if present
$dealInsightsFields = $this->getOpportunitySyncableFields();
$this->importOpportunityCrmFieldData($crmData, $dealInsightsFields, $opportunity->id);
return $opportunity;
}
/**
* @param array<string, mixed> $opportunityData
* @param string[] $dealInsightsFields
*/
public function importOpportunityCrmFieldData(
array $opportunityData,
array $dealInsightsFields,
int $opportunityId
): void {
foreach ($dealInsightsFields as $fieldName) {
$field = $this->config->fields()->with('entities')
->where('crm_provider_id', $fieldName)
->where('object_type', Field::OBJECT_OPPORTUNITY)
->first();
if (! $field instanceof Field) {
$this->logger->warning('Field not found', [
'field' => $fieldName,
'opportunity_id' => $opportunityId,
]);
continue;
}
$entity = $field->getEntities()->first();
if (! $entity instanceof LayoutEntity) {
continue;
}
$fieldValue = $this->extractFieldValue($opportunityData, $fieldName);
$normalizedValue = $this->normalizeValue($field->getType(), (string) $fieldValue, true);
$field->data()
->updateOrCreate([
'crm_layout_entity_id' => $entity->id,
'crm_field_id' => $field->id,
'object_type' => 'opportunity',
'object_id' => $opportunityId,
], ['value' => $normalizedValue])
;
}
}
/**
* @inheritdoc
*/
public function syncContacts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
$cpContacts = $this->copperClient->contacts()->paginate([
'minimum_interaction_date' => $since->timestamp,
'sort_by' => 'date_modified',
]);
foreach ($cpContacts as $cpContact) {
// Only sync if previously imported.
if ($this->hasContact($cpContact['id'])) {
$this->importContact($cpContact);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
throw $exception;
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncContact(string $crmId): ?Contact
{
$cpContact = $this->copperClient->contacts()->find($crmId);
if (empty($cpContact)) {
return null;
}
return $this->importContact($cpContact);
}
/**
* @inheritdoc
*/
private function importContact($crmData): Contact
{
$account = null;
if ($crmData['company_id']) {
$account = $this->team
->crm
->accounts()
->where('crm_provider_id', (string) $crmData['company_id'])
->first();
if ($account === null) {
$account = $this->syncAccount($crmData['company_id']);
}
}
$countryCode = null;
if (empty($crmData['address']) === false && $crmData['address']['country']) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$mobilePhone = $parsedNumber = null;
foreach ($crmData['phone_numbers'] as $phoneNumber) {
if ($phoneNumber['category'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);
} else {
$parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);
}
}
$email = null;
if (empty($crmData['emails']) === false) {
$email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'account_id' => $account->id ?? null,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => $crmData['name'],
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'mobile_phone' => $mobilePhone ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'title' => $crmData['title'],
'country_code' => $countryCode,
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Contact::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
private function buildContactPhone(?string $countryCode, ?string $number): ?array
{
if ($number) {
// Trim to our width and attempt to parse it.
$number = mb_strimwidth($number, 0, 25);
$parsedNumber = parsePhoneNumber($countryCode, $number);
} else {
$parsedNumber = [];
}
return $parsedNumber;
}
private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string
{
return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
$organization = $this->copperClient->organisation()->all();
if ($this->config->crm_provider_id !== $organization['id']) {
$this->config->update(['crm_provider_id' => $organization['id']]);
}
}
private function syncCustomFields(): void
{
foreach ($this->getFieldTypes() as $fieldType) {
$currentFields = $this->getFields($fieldType);
foreach ($currentFields as $field) {
/** @var Field $field */
$field = $this->config->fields()->updateOrCreate([
'crm_provider_id' => $field['name'],
'object_type' => $fieldType,
], [
'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),
'type' => $field['type'],
]);
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
}
$this->config->save();
}
protected function getFieldTypes(): array
{
return [
parent::OBJECT_TASK,
parent::OBJECT_LEAD,
parent::OBJECT_ACCOUNT,
parent::OBJECT_CONTACT,
parent::OBJECT_OPPORTUNITY,
];
}
/**
* @inheritdoc
*/
public function syncProfiles(?User $userToSearch = null): ?Profile
{
$profiles = $this->copperClient->users()->all();
foreach ($profiles as $profile) {
$user = $this->userRepository->findByTeamAndEmailAddress($this->team, $profile['email'], onlyActive: true);
// Only import profiles for users we have locally.
if ($user) {
$profile = $user->crmProfile()->updateOrCreate([
'crm_configuration_id' => $this->config->id,
'crm_provider_id' => $profile['id'],
]);
if ($userToSearch && $userToSearch->id === $user->id) {
return $profile;
}
}
}
return null;
}
/**
* @inheritdoc
*/
public function syncProfileFields(): void
{
$fieldTypes = [
'task',
'lead',
'account',
'contact',
'opportunity',
];
foreach ($fieldTypes as $fieldType) {
try {
$currentFields = $this->getFields(ucfirst($fieldType));
$newFields = array_column($currentFields, 'name');
$changedFields = array_merge(
array_diff($this->profile->getFieldsAsArray($fieldType), $newFields),
array_diff($newFields, $this->profile->getFieldsAsArray($fieldType))
);
if (\count($changedFields) > 0) {
$fields = implode(',', $newFields);
$this->logger->debug(
ucfirst($fieldType)
. ' fields changed from '
. $this->profile->{$fieldType . '_fields'}
. ' to: '
. $fields
);
$this->profile->{$fieldType . '_fields'} = $fields;
}
} catch (\Exception $exception) {
$this->logger->error('No access to ' . $fieldType . ' object, skipping...');
continue;
}
}
$this->profile->save();
}
/**
* @inheritdoc
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
$scopeValues = array_map(fn ($scope) => is_string($scope) ? $scope : $scope->value, $scopes);
$cacheKey = sprintf('copper-search-%d-%s-%s-%d-%d', $this->team->id, $name, implode('-', $scopeValues), $count, $offset);
return Cache::remember($cacheKey, 300, function () use ($name, $scopes, $count, $offset) {
// Try local search first
$localResults = $this->searchLocally($name, $scopes, $count, $offset);
// If no local results, fall back to remote API search
if (empty($localResults)) {
return $this->searchRemotely($name, $scopes, $count, $offset);
}
return $localResults;
});
}
/**
* @inheritdoc
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
$contact = null;
$account = null;
if ($crmAccountId) {
$account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();
if ($account === null) {
$account = $this->syncAccount($crmAccountId);
}
}
if ($crmContactId) {
$contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();
if ($contact === null) {
$contact = $this->syncContact($crmContactId);
}
}
if ($contact || $account) {
if ($contact && $account === null) {
$account = $contact->account;
}
if ($account === null) {
return [];
}
$params = [
'company_ids' => [$account->crm_provider_id],
'status_ids' => [0], // The integer values are 0, 1, 2, 3, for "Open", "Won", "Lost", and "Abandoned".
'sort_by' => 'date_modified',
'sort_direction' => 'desc',
];
switch ($this->config->opportunity_assignment_rule) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['sort_by'] = 'date_modified';
$params['sort_direction'] = 'desc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['sort_by'] = 'date_created';
$params['sort_direction'] = 'desc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['sort_by'] = 'date_created';
$params['sort_direction'] = 'asc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['sort_by'] = 'date_modified';
$params['sort_direction'] = 'desc';
$params['status_ids'] = [0, 1, 2, 3];
}
$cpOpportunities = $this->copperClient->opportunities()->search($params);
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
foreach ($cpOpportunities as $cpOpportunity) {
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', (string) $cpOpportunity['pipeline_id'])
->first();
if ($businessProcess === null) {
// Import it.
$businessProcess = $this->importStages(
[Stage::TYPE_OPPORTUNITY],
$cpOpportunity['pipeline_stage_id']
);
}
$stage = $businessProcess
->stages()
->where('crm_provider_id', (string) $cpOpportunity['pipeline_stage_id'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $cpOpportunity['pipeline_stage_id']);
}
$recordType = $businessProcess->recordTypes()->first();
$record = [
'crmId' => $cpOpportunity['id'],
'name' => $cpOpportunity['name'],
'value' => currency_format($cpOpportunity['monetary_value'], $cpOpportunity['monetary_unit']),
'won' => $cpOpportunity['status'] === 'Won',
'stage' => [
'id' => $stage->id_string,
'name' => $stage->name,
],
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
if ($ownerId && isset($cpOpportunity['assignee_id']) && $cpOpportunity['assignee_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
}
if (! empty($ownerData)) {
return $ownerData;
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array
{
$data = $cpTasks = [];
switch ($objectType) {
case 'lead':
$cpTasks = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->relatedTasks($objectId)
);
break;
case 'account':
$cpTasks = $this->copperClient->accounts()->relatedTasks($objectId);
break;
case 'contact':
if ($opportunityId) {
$cpTasks = $this->copperClient->opportunities()->relatedTasks($opportunityId);
} elseif ($objectType === 'contact') {
$cpTasks = $this->copperClient->contacts()->relatedTasks($objectId);
}
break;
}
foreach ($cpTasks as $cpTask) {
// We only get the ID itself returned, so pull out the full object.
try {
$cpTask = $this->copperClient->tasks()->find($cpTask['id']);
} catch (Exception $exception) {
$this->logger->error('[Copper] Error fetching task', [
'resource_id' => $cpTask['id'],
'error' => $exception->getMessage(),
]);
continue;
}
// Only allow open tasks.
if ($cpTask['status'] === 'Open') {
$data[] = [
'crmId' => $cpTask['id'],
'subject' => $cpTask['name'],
'due' => $cpTask['due_date']
? Carbon::createFromTimestamp($cpTask['due_date'])->format('Y-m-d\TH:i:sO')
: null,
'type' => null,
];
}
}
return $data;
}
/**
* Try to find email address in CRM service
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$cpObjectType = 'contact';
$cpObjects = $this->copperClient->contacts()->search([
'emails' => $email,
'sort_by' => 'date_modified',
'sort_direction' => 'desc',
]);
if (empty($cpObjects)) {
$cpObjectType = 'lead';
$cpObjects = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->search([
'emails' => ...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
45374
|
1625
|
24
|
2026-05-14T14:33:21.074066+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769201074_m1.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
PhpStormFileEditViewNavigateCodeLaravelRefactorRun PhpStormFileEditViewNavigateCodeLaravelRefactorRunToolsGitWindowHelpabl100% C•FV faVsco.jsv* #12066 on JY-20725-handle-HS-search-rate-limit k vHandleHubspotRateLimitTest v8• Thu 14 May 17:33:20* :QProjectv:=custom.logAutomatedReportGenerated.phpTrackAutomatedReportGeneratedEvent.phpPlaybackController.php© FieldDefinitions.phpUserAutomatedReportsController.phpPlanhatService.phpAutomatedReportResult.phpSendReportJob.php=laravel.log© FieldValueConverter.php• DeleteCrmEntityTrait.phpDeleteAccountJob.php© ImportActivityTypes.phpT WriteCrmTrait.php© Service.php© DecorateActivity.phpSF [jiminny@localhost]> D CrmObjects© Salesforce/Service.php© LogActivityTrait.phpPipedrive/Service.php© Close/Service.phpCopper/Service.php XA HS_local [jiminny@localho:W• DecorateActivity© PlainTextDecorateActivity.phpT ActivityPlaybookTrait.php© CrmHelperRepository.phpAccountController.php4 console [QAI PROD] X18© BaseDecorateActivity.php© PlainTextDecorateActivity.plT IntegrationAppTrait.php.env.stagingE.env© DetachActivityObject.phpRematchActivityOnCrmObjectDetach.php4 console [PROD]> D Dummyv Helpers52T ActivityPlaybookTrait.php1664© Arraylterator.php1678© MatchActivityCrmData.php© Client.php© HubspotPaginationService.phpclass Service extends BaseService implementsprivate function buildCallPayload(Activity $activity): Activityaetarts'= $tnis->generateActIvityuescription(sactivity),© HandleHubspotRateLimit.phpA console (EU]811 472 M1 м4 лT ConnectionStateTrait.php1679© CrmHelperRepository.php16801):• else {© FilterJoinedParticipants.php1681+ OpportunitySyncableFieldsT1682v D Hubspot1683• AccountSyncStrategy1684DGo jiminny084143 ×4 л215•m_layout_id =2162,1661, 66799,66217itn(Sthis-2getCrmType(SactivitX->categacV2mmm0ulVnt218$message = sprintf( format: '[Copper] Invalid CRM Activity Type: %s', $activity->category->getName()):_* 219=220=221.id = 33;throw new CrmException(Smessage,code: 400);> OJ Actions |1685• ContactSyncStrategy1686> ODTO1687D Fields1688› O Journal1689D Metadata1698code: 400):v C OpportunitySyncStrategy1691› D Concerns1692© HubspotLastModifiedByF 1693© HubspotLastModifiedCre 1694© HubspotLastModifiedCre 1695© HubspotLastModifiedOpe 1696© HubspotLastModifiedSyn 169711698if (Sthis->getCrmType($activity->category)->value === null) {=223$messagel = sprintf( format: '[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName224225Extract Surround //tnrow new Crmexception(smessage,=226=227228229=: 230|231232233V=234id THEN •(own© HubspotSingleSyncStrate// Just create an activity.$cpActivity = $this->copperClient-›activities()->create(['user_id' => $this->profile->crm_provider_id,'activity_date' => $activity->scheduled_start_time->timestamp,'parent' => $this->convertActivityAssociations(Sactivity),'type' => $this->convertActivityType(Sactivity->category),'details' => $this->generateActivityDescription(Sactivity),hubspot":-= 11512582;© HubspotSyncStrategyBa: 16991):© HubspotWebhookBatchS1700v [ Pagination1701• HubspotPaginationServic 1702Sactivity->crm_provider_id = $cpActivity['id'];Sactivity->save):A DaninatinnCanfin nhnWorkspace associated with branch 'JY-20725-handle-HS-search-rate-limit' has been restored // Rollback // Configure... (today 16:17)W Windsurf Teams1688:29 (8 chars)UTF-8Ca 4 spaces...
|
NULL
|
-1341745411075778780
|
NULL
|
click
|
ocr
|
NULL
|
PhpStormFileEditViewNavigateCodeLaravelRefactorRun PhpStormFileEditViewNavigateCodeLaravelRefactorRunToolsGitWindowHelpabl100% C•FV faVsco.jsv* #12066 on JY-20725-handle-HS-search-rate-limit k vHandleHubspotRateLimitTest v8• Thu 14 May 17:33:20* :QProjectv:=custom.logAutomatedReportGenerated.phpTrackAutomatedReportGeneratedEvent.phpPlaybackController.php© FieldDefinitions.phpUserAutomatedReportsController.phpPlanhatService.phpAutomatedReportResult.phpSendReportJob.php=laravel.log© FieldValueConverter.php• DeleteCrmEntityTrait.phpDeleteAccountJob.php© ImportActivityTypes.phpT WriteCrmTrait.php© Service.php© DecorateActivity.phpSF [jiminny@localhost]> D CrmObjects© Salesforce/Service.php© LogActivityTrait.phpPipedrive/Service.php© Close/Service.phpCopper/Service.php XA HS_local [jiminny@localho:W• DecorateActivity© PlainTextDecorateActivity.phpT ActivityPlaybookTrait.php© CrmHelperRepository.phpAccountController.php4 console [QAI PROD] X18© BaseDecorateActivity.php© PlainTextDecorateActivity.plT IntegrationAppTrait.php.env.stagingE.env© DetachActivityObject.phpRematchActivityOnCrmObjectDetach.php4 console [PROD]> D Dummyv Helpers52T ActivityPlaybookTrait.php1664© Arraylterator.php1678© MatchActivityCrmData.php© Client.php© HubspotPaginationService.phpclass Service extends BaseService implementsprivate function buildCallPayload(Activity $activity): Activityaetarts'= $tnis->generateActIvityuescription(sactivity),© HandleHubspotRateLimit.phpA console (EU]811 472 M1 м4 лT ConnectionStateTrait.php1679© CrmHelperRepository.php16801):• else {© FilterJoinedParticipants.php1681+ OpportunitySyncableFieldsT1682v D Hubspot1683• AccountSyncStrategy1684DGo jiminny084143 ×4 л215•m_layout_id =2162,1661, 66799,66217itn(Sthis-2getCrmType(SactivitX->categacV2mmm0ulVnt218$message = sprintf( format: '[Copper] Invalid CRM Activity Type: %s', $activity->category->getName()):_* 219=220=221.id = 33;throw new CrmException(Smessage,code: 400);> OJ Actions |1685• ContactSyncStrategy1686> ODTO1687D Fields1688› O Journal1689D Metadata1698code: 400):v C OpportunitySyncStrategy1691› D Concerns1692© HubspotLastModifiedByF 1693© HubspotLastModifiedCre 1694© HubspotLastModifiedCre 1695© HubspotLastModifiedOpe 1696© HubspotLastModifiedSyn 169711698if (Sthis->getCrmType($activity->category)->value === null) {=223$messagel = sprintf( format: '[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName224225Extract Surround //tnrow new Crmexception(smessage,=226=227228229=: 230|231232233V=234id THEN •(own© HubspotSingleSyncStrate// Just create an activity.$cpActivity = $this->copperClient-›activities()->create(['user_id' => $this->profile->crm_provider_id,'activity_date' => $activity->scheduled_start_time->timestamp,'parent' => $this->convertActivityAssociations(Sactivity),'type' => $this->convertActivityType(Sactivity->category),'details' => $this->generateActivityDescription(Sactivity),hubspot":-= 11512582;© HubspotSyncStrategyBa: 16991):© HubspotWebhookBatchS1700v [ Pagination1701• HubspotPaginationServic 1702Sactivity->crm_provider_id = $cpActivity['id'];Sactivity->save):A DaninatinnCanfin nhnWorkspace associated with branch 'JY-20725-handle-HS-search-rate-limit' has been restored // Rollback // Configure... (today 16:17)W Windsurf Teams1688:29 (8 chars)UTF-8Ca 4 spaces...
|
45371
|
NULL
|
NULL
|
NULL
|
|
45373
|
1626
|
16
|
2026-05-14T14:33:18.940443+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769198940_m2.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Jiminny... ~ActivityFilesLater@ jiminny-x-integrat Jiminny... ~ActivityFilesLater@ jiminny-x-integrati• plattorm-inner-teamE Channels# ai-chapter# alertsi backend# bugscontusion-cllnia# curiosity lab# engineering# general#jiminny-bgac nlattorm-nckets# product launches# random# releases# sofia-officed sunport# thank-yous# the people of iimi... Direct messages• 8la 62% Galya Dimitrovavasil VasilevM Stefka StovanovaSg: Todor StamatovMario GeorgievNiudlay lanay. James Graham "* Stoyan Tanevo Stelivan Georgiev( Petko Kashinski*. Lukas Kovali...::: AnnsToastS lira Gloud6d Huddle with Aneliva Angelova* Aneliya Angelova &• Messagest Add canvasur FilesAneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук,нали?пои останалите скМі тоябва оъчно ла се въвелат.Lukas Kovalik 2:47 PMтряова да се за всички, някъде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725X Preuiew in sact[HubSpotl Optimise CRM rematct(7 OpenRosdy for OA- MediumAA Aneliya AngelovaAs of today at 4:00 PM RetreshOpen in Jira* SummariseLukas Kovalik 4:02 PMzean-iurwiniareelYou joined the huddle (LIVE 4:06 PMAneliva Angelova is here toolAneliva Angelova 4:44 PN11512582Lukas Kovalik M 5.16 PNcurl --location "httns:ani.hubani.com/crm/v3/obiects/contacts/search--header 'Content-vne' annlication/ison'--header "Authorization: BearerC|Kvma?iMx7OINOM8kOFwrAowAcAkUAhIR24?A05D?xiVrIYMILuP6SA01Kwcmhr=n.v2 hytorDniMvDalYck-CMalovolNOM9kOFwrAUAcrkcaws-ThwRARIRAOF-ATFSAOFRAO-ROIEBAQUBEggBAQEBAYICFIr7Au8O2Nwal9YW2CbCCxYvwngmSgNldTFSAFoAYABoAHAAeAA'\--data "{ "limit", 13'Message Aneliva Angelova+ AaIđ 0Pmv Q SearchDate ModifiedYesterday at 13.3Yesterday at 13:36Yesterday at 13:36Yesterday at 13.30Yesterdav at 13:35Yesterday at 13:34Yesterday at 13:34Yesterdav at 13:3kYesterday at 13:33Yesterday at 13.32Yesterdav at 13:31resterday at 15:30Yesterdav at 13:30Yesterday at 13:29Yesterday at 13:29Yesterday at 13:28Yecterdav at 12:28resterday at 13-21Yesterdav at 13:26Yesterday at 13:26Yesterday at 13:25Yesterday at 13:25Voctorday at 12:01Yesterday at 13.23Yesterdav at 13:22resterady al 15.clYesterday at 13:20Yesterday at 13.19Yecterdav at 12:19Yesterdav at 13:18Yesterday at 13-1/Yesterdav at 13:17Yesterday at 13:16Yesterday at 13:15Yecterdav at 12:15Yesterday at 13.14Yecterdav at 13:10Yesterday at 13:13Yesterday at 13:12Yoctorday at 12:11Yesterday at 13.10Yecterdav at 12:10Yesterdav at 13:09Yesterdav at 13:08v Size23 KB9 KB13 Kb16 KE17 KB29 KB16 K:12 KB9 KEIKBn8 KBI37 KB10 KB7 KE8 KB9 KB8 KB172 KR14 KB13 KB9 KE18 KB12 KB10 KBI16 KB6 KB6KB12 KE23 KB8 KB16 K:11 KB20 KP34 KB10 KB7 K:5 KB11 KB26 KBMPEG-4 movieMPEG-4 movieMPEG-4 movieMPEG-4 movieMPE0"4 movieMDSG-A movieMP2G-4 movieMPEG-4 movieMPEG"4 movieMPEG-4 movieMoEeh movioMPEG-4 movieMPEG-1 movieMPEG-4 movieMPEG-4 movieMPEG-4 movieMPEG-4 movieMDEG.A movicMPEG-4 movieMPEG-4 movieMPEG-4 movieMPEG-4 movieMDEC A movidMPEG-4 movieMDEG-A movieMPEG-4 movieMPEG-4 movieMDEC.A moviaMPEG-4 movie111 KC102 KB88 KBMDEG-A moviaMPEG-4 movie59 KB1MPEG-A movie98 KB MPEG-4 movie97 KB66 K3MPEG-4 movieMDEG.A movioAAKP93 KB/8 KBMPEG-4 movie50 KгMDEG-A movid58 KBMPEG-4 movie27 KB7KBMPEG-4 movieAl Notes: OffLeave• • CFavourites• jiminny• Recents* ApplicationsiCloud• iCloud Drive992 Svnc tolde0 DXP4800PLUS-B5F49 Networl• CRMI• Orange• Red|• Yellow• Green• Purple•) All lags..IhlDownloadsNameLoom.pkgAlfred copv.alfredoreterences=KeychronAssist-1.0.2 (1).dmeKeychronAssist-1.0.2.dmgmazanoke-images-yWJo.zioPhotos-3-001.zip• Transcript.pd→mage U.loge1 Orioninstaller.dma_image.jpg- image (2).1pc• ПO-22221726037035-004-001_ORGES.pdf%D0%9F%D0%9E-22221726037035-004-001 archive.zipПO-22221726037035-004-001_archive (1).zip• repon 4).XmAltred copy2.altredoreterencesСE 060209С О000000026571172 CWICT 0Р70501260015900 ndt= 27022026_0000000026574472_ SWIFT_ [IBAN].pdf= 03042026 [CREDIT_CARD] SWIFT [CREDIT_CARD].001reportxmmi=pdt.odiB pdf-1.pdfD pdf-2.pdf-pdf-5.pd1= ndf-1 ndipdf-3.pdfKoválik Family Tree.gedbitwarden export 20251031122528.isonlKoválik Family Tree.zip*macOS Storage_Cleanup.mdal favicon icofirst aid_notes_complete.docxrenortl2).esv1 config.vmlIteration run Search HS.postman_collection.jsonm licence bettertouchtoalMariusHosting Config.isonnokc.901a6502.6667.A62h-062 ccu•AlfredwPmazanoko.imnaoc.YWIfана Ковалик.jpg•искане даниел Ковалик..pg• Фактура Март Даниел Ковалик.jрс• Фактура Април Даниел Ковалик iро• Dhotac 2.001Q SearchKind00,4 MD55.9 MBinstdlle..dckageAlfred...ferences10,1 MB10,1 MBIL MBDisk ImageDisk ImageLiP archive6.6 MBZIp archive2,5 MB PDF Document2,5 MBJreo lmage2.2 MBDisk Image2,2 MB PDF Document2 MBJPEG image1,9 MBJPEG imaqe192 KBPDE Document140 KbZIP archive148 KВ148 KB122 KBZIP archivelZIP archiveXML document111 KBAlfred...ferences94 KBDDE Documont92 KBPDr DocumentK:PDF Document91 KB91 KBXML document30 KBn0kpDDE Nocumont28 KBPDF Document28 KRPDE Document28 KB27 KBDocument14 KB11 KB6 KB6KBJSONINCV NacumontZIP archiveMarkdo…..ument5KRWindo...n image4 KB3 KBword ..cumentCSV Document2 KBVAMI dosumon1 KB029 buteccSV Documenthttlicence183 bytesZero butesJSONAlfrod foronso!Zero bytesFolde1.9 MB1,8 MB17 MB1,7 MBColdorJPEG imageJPEG ImageIPEG imadeJPEG imageColdo1 of 58 selected, 8.49 GB availabld• Inu 14 May 1/.33.10Date AddedIs Mdl ZUzo dl 19:4530 Jan 2026 at 12:3617 Mar 2026 at 20:2717 Mar 2026 at 20:26Z3 Aor 2020 al 13:0229 ,Jan 2026 at 15:2019 Dec 2025 at 10:1619 Dec 2025 at 12:238 Aor 2026 at 20:3519 Dec 2025 at 10:2919 Dec 2025 at 12:1819 Dec 2025 at 12:4026 Mar 2026 at 11:2410 May 2026 at 13:5326 Mar 2026 at 11:2426 Mar 2026 at 11:2426 Mar 2026 at 11:2310 May 2026 at 14:3730 Jan 2026 at 12:3712 Goh 2006 9t 11:5 A1Z3 Apr 2026 at 13.0823 Aor 2026 at 13:0810 May 2026 at 13:5410 May 2026 at 14:3710 May 2026 at 13:4910 May 2026 at 13:5010 May 2026 at 13:5110 Mav 2026 at 12:51110 May 2026 at 13:5019 Dec 2025 at 11:3431 Oct 2025 at 12:2525 Nau 2025 г+ 17:506 Mar 2026 at 11.2224 Anr 2026 at 16:5220 Oct 2025 at 11:0218 Mar 2026 at 15:29• Mav 2026 at 11:09129 Oct 2025 at 19:329 May 2026 at 10:0419 Mar 2026 at 11:55|10 May 2026 at 13:5712 Jun 2025 at 19:0430 Jan 2026 at 12:362616 Oct 2025 aт 16:0122 Aar 2026 at 12:0223 Apr 2026 at 13:0223 Apr 2026 at 13:0222 Anr 2026 at 12:0223 Apr 2026 at 13:0229 Jan 2026 at 15:20...
|
NULL
|
-2134816872056375722
|
NULL
|
visual_change
|
ocr
|
NULL
|
Jiminny... ~ActivityFilesLater@ jiminny-x-integrat Jiminny... ~ActivityFilesLater@ jiminny-x-integrati• plattorm-inner-teamE Channels# ai-chapter# alertsi backend# bugscontusion-cllnia# curiosity lab# engineering# general#jiminny-bgac nlattorm-nckets# product launches# random# releases# sofia-officed sunport# thank-yous# the people of iimi... Direct messages• 8la 62% Galya Dimitrovavasil VasilevM Stefka StovanovaSg: Todor StamatovMario GeorgievNiudlay lanay. James Graham "* Stoyan Tanevo Stelivan Georgiev( Petko Kashinski*. Lukas Kovali...::: AnnsToastS lira Gloud6d Huddle with Aneliva Angelova* Aneliya Angelova &• Messagest Add canvasur FilesAneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук,нали?пои останалите скМі тоябва оъчно ла се въвелат.Lukas Kovalik 2:47 PMтряова да се за всички, някъде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725X Preuiew in sact[HubSpotl Optimise CRM rematct(7 OpenRosdy for OA- MediumAA Aneliya AngelovaAs of today at 4:00 PM RetreshOpen in Jira* SummariseLukas Kovalik 4:02 PMzean-iurwiniareelYou joined the huddle (LIVE 4:06 PMAneliva Angelova is here toolAneliva Angelova 4:44 PN11512582Lukas Kovalik M 5.16 PNcurl --location "httns:ani.hubani.com/crm/v3/obiects/contacts/search--header 'Content-vne' annlication/ison'--header "Authorization: BearerC|Kvma?iMx7OINOM8kOFwrAowAcAkUAhIR24?A05D?xiVrIYMILuP6SA01Kwcmhr=n.v2 hytorDniMvDalYck-CMalovolNOM9kOFwrAUAcrkcaws-ThwRARIRAOF-ATFSAOFRAO-ROIEBAQUBEggBAQEBAYICFIr7Au8O2Nwal9YW2CbCCxYvwngmSgNldTFSAFoAYABoAHAAeAA'\--data "{ "limit", 13'Message Aneliva Angelova+ AaIđ 0Pmv Q SearchDate ModifiedYesterday at 13.3Yesterday at 13:36Yesterday at 13:36Yesterday at 13.30Yesterdav at 13:35Yesterday at 13:34Yesterday at 13:34Yesterdav at 13:3kYesterday at 13:33Yesterday at 13.32Yesterdav at 13:31resterday at 15:30Yesterdav at 13:30Yesterday at 13:29Yesterday at 13:29Yesterday at 13:28Yecterdav at 12:28resterday at 13-21Yesterdav at 13:26Yesterday at 13:26Yesterday at 13:25Yesterday at 13:25Voctorday at 12:01Yesterday at 13.23Yesterdav at 13:22resterady al 15.clYesterday at 13:20Yesterday at 13.19Yecterdav at 12:19Yesterdav at 13:18Yesterday at 13-1/Yesterdav at 13:17Yesterday at 13:16Yesterday at 13:15Yecterdav at 12:15Yesterday at 13.14Yecterdav at 13:10Yesterday at 13:13Yesterday at 13:12Yoctorday at 12:11Yesterday at 13.10Yecterdav at 12:10Yesterdav at 13:09Yesterdav at 13:08v Size23 KB9 KB13 Kb16 KE17 KB29 KB16 K:12 KB9 KEIKBn8 KBI37 KB10 KB7 KE8 KB9 KB8 KB172 KR14 KB13 KB9 KE18 KB12 KB10 KBI16 KB6 KB6KB12 KE23 KB8 KB16 K:11 KB20 KP34 KB10 KB7 K:5 KB11 KB26 KBMPEG-4 movieMPEG-4 movieMPEG-4 movieMPEG-4 movieMPE0"4 movieMDSG-A movieMP2G-4 movieMPEG-4 movieMPEG"4 movieMPEG-4 movieMoEeh movioMPEG-4 movieMPEG-1 movieMPEG-4 movieMPEG-4 movieMPEG-4 movieMPEG-4 movieMDEG.A movicMPEG-4 movieMPEG-4 movieMPEG-4 movieMPEG-4 movieMDEC A movidMPEG-4 movieMDEG-A movieMPEG-4 movieMPEG-4 movieMDEC.A moviaMPEG-4 movie111 KC102 KB88 KBMDEG-A moviaMPEG-4 movie59 KB1MPEG-A movie98 KB MPEG-4 movie97 KB66 K3MPEG-4 movieMDEG.A movioAAKP93 KB/8 KBMPEG-4 movie50 KгMDEG-A movid58 KBMPEG-4 movie27 KB7KBMPEG-4 movieAl Notes: OffLeave• • CFavourites• jiminny• Recents* ApplicationsiCloud• iCloud Drive992 Svnc tolde0 DXP4800PLUS-B5F49 Networl• CRMI• Orange• Red|• Yellow• Green• Purple•) All lags..IhlDownloadsNameLoom.pkgAlfred copv.alfredoreterences=KeychronAssist-1.0.2 (1).dmeKeychronAssist-1.0.2.dmgmazanoke-images-yWJo.zioPhotos-3-001.zip• Transcript.pd→mage U.loge1 Orioninstaller.dma_image.jpg- image (2).1pc• ПO-22221726037035-004-001_ORGES.pdf%D0%9F%D0%9E-22221726037035-004-001 archive.zipПO-22221726037035-004-001_archive (1).zip• repon 4).XmAltred copy2.altredoreterencesСE 060209С О000000026571172 CWICT 0Р70501260015900 ndt= 27022026_0000000026574472_ SWIFT_ [IBAN].pdf= 03042026 [CREDIT_CARD] SWIFT [CREDIT_CARD].001reportxmmi=pdt.odiB pdf-1.pdfD pdf-2.pdf-pdf-5.pd1= ndf-1 ndipdf-3.pdfKoválik Family Tree.gedbitwarden export 20251031122528.isonlKoválik Family Tree.zip*macOS Storage_Cleanup.mdal favicon icofirst aid_notes_complete.docxrenortl2).esv1 config.vmlIteration run Search HS.postman_collection.jsonm licence bettertouchtoalMariusHosting Config.isonnokc.901a6502.6667.A62h-062 ccu•AlfredwPmazanoko.imnaoc.YWIfана Ковалик.jpg•искане даниел Ковалик..pg• Фактура Март Даниел Ковалик.jрс• Фактура Април Даниел Ковалик iро• Dhotac 2.001Q SearchKind00,4 MD55.9 MBinstdlle..dckageAlfred...ferences10,1 MB10,1 MBIL MBDisk ImageDisk ImageLiP archive6.6 MBZIp archive2,5 MB PDF Document2,5 MBJreo lmage2.2 MBDisk Image2,2 MB PDF Document2 MBJPEG image1,9 MBJPEG imaqe192 KBPDE Document140 KbZIP archive148 KВ148 KB122 KBZIP archivelZIP archiveXML document111 KBAlfred...ferences94 KBDDE Documont92 KBPDr DocumentK:PDF Document91 KB91 KBXML document30 KBn0kpDDE Nocumont28 KBPDF Document28 KRPDE Document28 KB27 KBDocument14 KB11 KB6 KB6KBJSONINCV NacumontZIP archiveMarkdo…..ument5KRWindo...n image4 KB3 KBword ..cumentCSV Document2 KBVAMI dosumon1 KB029 buteccSV Documenthttlicence183 bytesZero butesJSONAlfrod foronso!Zero bytesFolde1.9 MB1,8 MB17 MB1,7 MBColdorJPEG imageJPEG ImageIPEG imadeJPEG imageColdo1 of 58 selected, 8.49 GB availabld• Inu 14 May 1/.33.10Date AddedIs Mdl ZUzo dl 19:4530 Jan 2026 at 12:3617 Mar 2026 at 20:2717 Mar 2026 at 20:26Z3 Aor 2020 al 13:0229 ,Jan 2026 at 15:2019 Dec 2025 at 10:1619 Dec 2025 at 12:238 Aor 2026 at 20:3519 Dec 2025 at 10:2919 Dec 2025 at 12:1819 Dec 2025 at 12:4026 Mar 2026 at 11:2410 May 2026 at 13:5326 Mar 2026 at 11:2426 Mar 2026 at 11:2426 Mar 2026 at 11:2310 May 2026 at 14:3730 Jan 2026 at 12:3712 Goh 2006 9t 11:5 A1Z3 Apr 2026 at 13.0823 Aor 2026 at 13:0810 May 2026 at 13:5410 May 2026 at 14:3710 May 2026 at 13:4910 May 2026 at 13:5010 May 2026 at 13:5110 Mav 2026 at 12:51110 May 2026 at 13:5019 Dec 2025 at 11:3431 Oct 2025 at 12:2525 Nau 2025 г+ 17:506 Mar 2026 at 11.2224 Anr 2026 at 16:5220 Oct 2025 at 11:0218 Mar 2026 at 15:29• Mav 2026 at 11:09129 Oct 2025 at 19:329 May 2026 at 10:0419 Mar 2026 at 11:55|10 May 2026 at 13:5712 Jun 2025 at 19:0430 Jan 2026 at 12:362616 Oct 2025 aт 16:0122 Aar 2026 at 12:0223 Apr 2026 at 13:0223 Apr 2026 at 13:0222 Anr 2026 at 12:0223 Apr 2026 at 13:0229 Jan 2026 at 15:20...
|
45372
|
NULL
|
NULL
|
NULL
|
|
45372
|
1626
|
15
|
2026-05-14T14:33:15.868866+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769195868_m2.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
ActivityFilesLaterJiminny... ~@ jiminny-x-integrat ActivityFilesLaterJiminny... ~@ jiminny-x-integrati& platform-inner-team© Channels# ai-chapter# alertsi backend# bugscontusion-cllnia# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the people of iimi..• Direct messages8. A...• A3 62P. Galya Dimitrova Mvasil VasilevA. Stefka Stoyanova%: Todor Stamatovf. Mario GeorgievP. Nikolay Ivanov2o James Graham "2. Stoyan Tanev. Steliyan Georgiev. Petko Kashinski*. Lukas Kovali...a: Apps® ToastS lira Gloud6 Huddle with Aneliya Angelova& R. Aneliya Angelova •• Messagest Add canvasur FilesAneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук,нали?пои останалите скМі тоябва оъчно ла се въвелат.Lukas Kovalik 2:47 PMтряова да се за всички, някьде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova @ 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725X Preview insackt[HubSpot] Optimise CRM rematctC OpenReady for QA- MediumAA Aneliya AngelovaAs of today at 4:00 PM RetreshOpen in Jira+ SummariseLukas Kovalik 4:02 PMzean-iurwiniareelYou joined the huddle LIVE 4:06 PMAneliva Angelova is here toolAneliya Angelova 4:44 PM11512582Lukas Kovalik O 5:16 PMcurl --location "httns:ani.hubani.com/crm/v3/obiects/contacts/search--header 'Content-Type: application/json'\--header "Authorization: BearerC|Kvma?iMx7OINOM8kOFwrAowAcAkUAhIR24?A05D?xiVrIYMILuP6SA01Kwcmhr=n.v2 hytorDniMvDalYck-CMalovolNOM9kOFwrAUAcrkcaws-ThwRARIRAOF-ATFSAOFRAO-ROIEBAQUBEggBAQEBAYICFIґ7Au8O2Nwal9YW2CbCCxYvwngmSgNldTFSAFoAYABoAHAAeAA'\--data "{ "limit", 13'Message Aneliva Angelova+ AaIAl Notes: OffLeave~ (Q SearchDate ModifiedYesterday at 13:37Yesterday at 13.30Yesterday at 13:35resterady al 15.54Yesterdav at 13:34Yesterday at 13:33Yesterday at 13:33Yesterday at 13:32Yesterday at 13:32resterday at 15.3Yesterdav at 13:30Yesterday at 13:30Yesterday at 13:29Yesterday at 13:29Yesterday at 13:28Yesterday at 13.21Yesterday at 13:27Yesterday at 13:26Yesterday at 13:26Yesterday at 13:25Yesterday at 13.24Yecterdav at 12:22Yesterday at 13:22resterday at 13.2lYesterday at 13:20Yesterday at 13.19Yecterdav at 12:10Yesterday at 13:18resterday at 13.10Yesterday at 13:16Yesterday at 13:15Yesterday at 13.14Yesterday at 13:13Yesterday at 13:13Yesterdav at 13:12Yesterday at 13:12Yesterday at 13.11Yecterdav at 12:10Yesterday at 13:10Yesterdav at 13:09Yesterday at 13:0871 KBMPEG-4 movie23 KBMPEG-4 movieMPEG-4 movie13 KE16 KB17 KBMPEO"4 movie29 KBMPEG-4 movie6 KBMPEG-4 movie12 KB9KBMPEG-4 movie7 KBMPEG-4 movie8 KB37 KBMPEO-4 moVie10 K:MPEG-4 movie7 KBMPEG-4 movie8 KB9K:MPEG-4 movie8 KBMPEG-4 movie72 KB14 KbMPEG-4 movie13 KEMPEG-4 movie9 KBMPEG-4 movie18 KBMPEG-4 movie12 K:MPEG-4 movie10 KBMPEG-4 movie16 KB6 KBMPEG-4 movieMPEG-4 movie12 KBMPEG-4 movie23 KBMPEG-4 movie8 K:MPEG-4 movie6 KBMPEG-4 movie6 KB11 KBMPEG-4 movie11 KPMDEG-A movid20 KBMPEG-4 movie34 KBMPEG-4 movie10 KI.MPEG-4 movie7KBMPEG-4 movie5 KB11 KBMPEG-4 movie26 KBMPEG-4 movie111 KB102 KBMPEG-4 movie88 KEMPEG-A movid59 KBMPEG-4 movie98 KB97 K866 KBMPEG-4 movie.MPEG-4 movie44 KB93 KBMPEG-4 movie78 KPMPEG-A movie50 KBMPEG-4 movie58 KB27 KEMPEG-4 movie7KBMPEG-4 movie• 0FavouritesE jiminny© Recents* ApplicationsiCloudiCloud Drive228 Sync folderLocationsQ DXP4800PLUS-B5FA@ Network|• CRM• Orange• Red• Yellow• Green• Purple•) All lags..lohlDownloadsNameLoom.pkgAlfred copv.alfredoreterencesB KeychronAssist-1.0.2 (1).dmgA Keychron Assist-1.0.2.dmgmazanoke-images-yWJo.zioPhotos-3-001.zip→mage U.loge1 Orioninstaller.dma- image (2).1pc• ПО-22221726037035-004-001_ORGES.pdf• %D0%9F%D0%9E-22221726037035-004-001_archive.zipПO-22221726037035-004-001_archive (1).zipD report(2) xmlAltred copy2.altredoreterences05012026_0000000026574472_ SWIFT_OB70501260015890.pdf27022026_0000000026574472_SWIFT_OB72702260049200.pdf= 03042026 [CREDIT_CARD] SWIFT [CREDIT_CARD].001B reporti) xm=pdt.odipdf-1.pdfD pdf-2.pdf-pdf-5.pd1= ndf-1 ndipdf-3.pdfB Rovaix Famly Treo gedbitwarden export 20251031122528.isonKoválik Family Tree.zip*macOS Storage_Cleanup.mdal favicon icofirst_aid_notes_complete.docxconfig.ymlIteration run Search HS.postman_collection.json--report(1).csvm licence hettertouchtoalMariusHosting Config.json1ooks-891a6503-bbb7-4b2b-9c3.csv•Alfredmazanoke-images-YWJ6ана Ковалик.jpg•искане даниел Ковалик..pa• Фактура Март Даниел Ковалик.jрс• Фактура Април Даниел Ковалик.jpg• Dhotac 2.001Q SearchKind00,4 MDinstdlle..dckage55.9 MBAlfred...ferences10,1 MBDisk Image10,1 MBDisk ImageIL MBLiP archive6,6 MBZIP archive2,5 MB PDF Document2,5 MBJreo lmage2.2 MBDisk Image2,2 MB PDF Document2 MBJPEG image1,9 MBJPEG imaqe192 KBPDF Document140 Kb148 KВ148 KB122 KB111 KB94 KBZIP archiveZIP archivelZIP archiveXML documentAlfred...ferencesPDF Document92 KBPDr DocumentPDF Document91 KB91 KB30 KB29 KBXML documentPDF Document28 KB28 KR28 KB27 KB14 KB11 KB6 KB6KB5KR4 KB3 KBPDF DocumentPDE DocumentDocumentJSONICSV DocumentZIP archiveMarkdo…..umentWindo...n imageword ..cumentCSV Document2 KBYAML document1 KBcSV Document928 byteshttlicence183 bytesZero butesJSONAlfred.. ferencesZero bytes1,9 MB1,8 MB17 MB1,7 MBFoldeColdorJPEG imageJPEG ImageJPEG imageJPEG imageColdo1 of 58 selected, 8.5 GB availab!i• Inu 14 May 1/.33.10Date AddedIs Mdl ZUzo dl 19:4530 Jan 2026 at 12:3617 Mar 2026 at 20:2717 Mar 2026 at 20:26Z3 Aor 2020 al 13:0229 Jan 2026 at 15:2019 Dec 2025 at 10:1619 Dec 2025 at 12:238 Aor 2026 at 20:3519 Dec 2025 at 10:2919 Dec 2025 at 12:1819 Dec 2025 at 12:4026 Mar 2026 at 11:2410 May 2026 at 13:5326 Mar 2026 at 11:2426 Mar 2026 at 11:2426 Mar 2026 at 11:2310 May 2026 at 14:3730 Jan 2026 at 12:3713 Feb 2026 at 11:54Z3 Apr 2026 at 13.0823 Aor 2026 at 13:0810 May 2026 at 13:5410 May 2026 at 14:3710 May 2026 at 13:4910 May 2026 at 13:5010 May 2026 at 13:5110 Mav 2026 at 12:51110 May 2026 at 13:5019 Dec 2025 at 11:3431 Oct 2025 at 12:2525 Nov 2025 at 17:596 Mar 2026 at 11.2224 Anr 2026 at 16:5220 Oct 2025 at 11:0218 Mar 2026 at 15:29• Mav 2026 at 11:09129 Oct 2025 at 19:329 May 2026 at 10:0418 Mar 2026 at 11:5510 May 2026 at 13:5712 Jun 2025 at 19:0430 Jan 2026 at 12:3630 Jan 2026 at 12:3616 Oct 2025 aт 16:0123 Apr 2026 at 13:0223 Apr 2026 at 13:0223 Apr 2026 at 13:0222 Anr 2026 at 12:0223 Apr 2026 at 13:0229 Jan 2026 at 15:20...
|
NULL
|
-6205760700402177095
|
NULL
|
visual_change
|
ocr
|
NULL
|
ActivityFilesLaterJiminny... ~@ jiminny-x-integrat ActivityFilesLaterJiminny... ~@ jiminny-x-integrati& platform-inner-team© Channels# ai-chapter# alertsi backend# bugscontusion-cllnia# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the people of iimi..• Direct messages8. A...• A3 62P. Galya Dimitrova Mvasil VasilevA. Stefka Stoyanova%: Todor Stamatovf. Mario GeorgievP. Nikolay Ivanov2o James Graham "2. Stoyan Tanev. Steliyan Georgiev. Petko Kashinski*. Lukas Kovali...a: Apps® ToastS lira Gloud6 Huddle with Aneliya Angelova& R. Aneliya Angelova •• Messagest Add canvasur FilesAneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук,нали?пои останалите скМі тоябва оъчно ла се въвелат.Lukas Kovalik 2:47 PMтряова да се за всички, някьде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova @ 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725X Preview insackt[HubSpot] Optimise CRM rematctC OpenReady for QA- MediumAA Aneliya AngelovaAs of today at 4:00 PM RetreshOpen in Jira+ SummariseLukas Kovalik 4:02 PMzean-iurwiniareelYou joined the huddle LIVE 4:06 PMAneliva Angelova is here toolAneliya Angelova 4:44 PM11512582Lukas Kovalik O 5:16 PMcurl --location "httns:ani.hubani.com/crm/v3/obiects/contacts/search--header 'Content-Type: application/json'\--header "Authorization: BearerC|Kvma?iMx7OINOM8kOFwrAowAcAkUAhIR24?A05D?xiVrIYMILuP6SA01Kwcmhr=n.v2 hytorDniMvDalYck-CMalovolNOM9kOFwrAUAcrkcaws-ThwRARIRAOF-ATFSAOFRAO-ROIEBAQUBEggBAQEBAYICFIґ7Au8O2Nwal9YW2CbCCxYvwngmSgNldTFSAFoAYABoAHAAeAA'\--data "{ "limit", 13'Message Aneliva Angelova+ AaIAl Notes: OffLeave~ (Q SearchDate ModifiedYesterday at 13:37Yesterday at 13.30Yesterday at 13:35resterady al 15.54Yesterdav at 13:34Yesterday at 13:33Yesterday at 13:33Yesterday at 13:32Yesterday at 13:32resterday at 15.3Yesterdav at 13:30Yesterday at 13:30Yesterday at 13:29Yesterday at 13:29Yesterday at 13:28Yesterday at 13.21Yesterday at 13:27Yesterday at 13:26Yesterday at 13:26Yesterday at 13:25Yesterday at 13.24Yecterdav at 12:22Yesterday at 13:22resterday at 13.2lYesterday at 13:20Yesterday at 13.19Yecterdav at 12:10Yesterday at 13:18resterday at 13.10Yesterday at 13:16Yesterday at 13:15Yesterday at 13.14Yesterday at 13:13Yesterday at 13:13Yesterdav at 13:12Yesterday at 13:12Yesterday at 13.11Yecterdav at 12:10Yesterday at 13:10Yesterdav at 13:09Yesterday at 13:0871 KBMPEG-4 movie23 KBMPEG-4 movieMPEG-4 movie13 KE16 KB17 KBMPEO"4 movie29 KBMPEG-4 movie6 KBMPEG-4 movie12 KB9KBMPEG-4 movie7 KBMPEG-4 movie8 KB37 KBMPEO-4 moVie10 K:MPEG-4 movie7 KBMPEG-4 movie8 KB9K:MPEG-4 movie8 KBMPEG-4 movie72 KB14 KbMPEG-4 movie13 KEMPEG-4 movie9 KBMPEG-4 movie18 KBMPEG-4 movie12 K:MPEG-4 movie10 KBMPEG-4 movie16 KB6 KBMPEG-4 movieMPEG-4 movie12 KBMPEG-4 movie23 KBMPEG-4 movie8 K:MPEG-4 movie6 KBMPEG-4 movie6 KB11 KBMPEG-4 movie11 KPMDEG-A movid20 KBMPEG-4 movie34 KBMPEG-4 movie10 KI.MPEG-4 movie7KBMPEG-4 movie5 KB11 KBMPEG-4 movie26 KBMPEG-4 movie111 KB102 KBMPEG-4 movie88 KEMPEG-A movid59 KBMPEG-4 movie98 KB97 K866 KBMPEG-4 movie.MPEG-4 movie44 KB93 KBMPEG-4 movie78 KPMPEG-A movie50 KBMPEG-4 movie58 KB27 KEMPEG-4 movie7KBMPEG-4 movie• 0FavouritesE jiminny© Recents* ApplicationsiCloudiCloud Drive228 Sync folderLocationsQ DXP4800PLUS-B5FA@ Network|• CRM• Orange• Red• Yellow• Green• Purple•) All lags..lohlDownloadsNameLoom.pkgAlfred copv.alfredoreterencesB KeychronAssist-1.0.2 (1).dmgA Keychron Assist-1.0.2.dmgmazanoke-images-yWJo.zioPhotos-3-001.zip→mage U.loge1 Orioninstaller.dma- image (2).1pc• ПО-22221726037035-004-001_ORGES.pdf• %D0%9F%D0%9E-22221726037035-004-001_archive.zipПO-22221726037035-004-001_archive (1).zipD report(2) xmlAltred copy2.altredoreterences05012026_0000000026574472_ SWIFT_OB70501260015890.pdf27022026_0000000026574472_SWIFT_OB72702260049200.pdf= 03042026 [CREDIT_CARD] SWIFT [CREDIT_CARD].001B reporti) xm=pdt.odipdf-1.pdfD pdf-2.pdf-pdf-5.pd1= ndf-1 ndipdf-3.pdfB Rovaix Famly Treo gedbitwarden export 20251031122528.isonKoválik Family Tree.zip*macOS Storage_Cleanup.mdal favicon icofirst_aid_notes_complete.docxconfig.ymlIteration run Search HS.postman_collection.json--report(1).csvm licence hettertouchtoalMariusHosting Config.json1ooks-891a6503-bbb7-4b2b-9c3.csv•Alfredmazanoke-images-YWJ6ана Ковалик.jpg•искане даниел Ковалик..pa• Фактура Март Даниел Ковалик.jрс• Фактура Април Даниел Ковалик.jpg• Dhotac 2.001Q SearchKind00,4 MDinstdlle..dckage55.9 MBAlfred...ferences10,1 MBDisk Image10,1 MBDisk ImageIL MBLiP archive6,6 MBZIP archive2,5 MB PDF Document2,5 MBJreo lmage2.2 MBDisk Image2,2 MB PDF Document2 MBJPEG image1,9 MBJPEG imaqe192 KBPDF Document140 Kb148 KВ148 KB122 KB111 KB94 KBZIP archiveZIP archivelZIP archiveXML documentAlfred...ferencesPDF Document92 KBPDr DocumentPDF Document91 KB91 KB30 KB29 KBXML documentPDF Document28 KB28 KR28 KB27 KB14 KB11 KB6 KB6KB5KR4 KB3 KBPDF DocumentPDE DocumentDocumentJSONICSV DocumentZIP archiveMarkdo…..umentWindo...n imageword ..cumentCSV Document2 KBYAML document1 KBcSV Document928 byteshttlicence183 bytesZero butesJSONAlfred.. ferencesZero bytes1,9 MB1,8 MB17 MB1,7 MBFoldeColdorJPEG imageJPEG ImageJPEG imageJPEG imageColdo1 of 58 selected, 8.5 GB availab!i• Inu 14 May 1/.33.10Date AddedIs Mdl ZUzo dl 19:4530 Jan 2026 at 12:3617 Mar 2026 at 20:2717 Mar 2026 at 20:26Z3 Aor 2020 al 13:0229 Jan 2026 at 15:2019 Dec 2025 at 10:1619 Dec 2025 at 12:238 Aor 2026 at 20:3519 Dec 2025 at 10:2919 Dec 2025 at 12:1819 Dec 2025 at 12:4026 Mar 2026 at 11:2410 May 2026 at 13:5326 Mar 2026 at 11:2426 Mar 2026 at 11:2426 Mar 2026 at 11:2310 May 2026 at 14:3730 Jan 2026 at 12:3713 Feb 2026 at 11:54Z3 Apr 2026 at 13.0823 Aor 2026 at 13:0810 May 2026 at 13:5410 May 2026 at 14:3710 May 2026 at 13:4910 May 2026 at 13:5010 May 2026 at 13:5110 Mav 2026 at 12:51110 May 2026 at 13:5019 Dec 2025 at 11:3431 Oct 2025 at 12:2525 Nov 2025 at 17:596 Mar 2026 at 11.2224 Anr 2026 at 16:5220 Oct 2025 at 11:0218 Mar 2026 at 15:29• Mav 2026 at 11:09129 Oct 2025 at 19:329 May 2026 at 10:0418 Mar 2026 at 11:5510 May 2026 at 13:5712 Jun 2025 at 19:0430 Jan 2026 at 12:3630 Jan 2026 at 12:3616 Oct 2025 aт 16:0123 Apr 2026 at 13:0223 Apr 2026 at 13:0223 Apr 2026 at 13:0222 Anr 2026 at 12:0223 Apr 2026 at 13:0229 Jan 2026 at 15:20...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
45371
|
1625
|
23
|
2026-05-14T14:33:10.101263+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769190101_m1.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
PhpStormFileEditViewNavigateCodeLaravelRefactorRun PhpStormFileEditViewNavigateCodeLaravelRefactorRunToolsGitWindowHelplhl•FV faVsco.jsv#12066 on JY-20725-handle-HS-search-rate-limit k vHandleHubspotRateLimitTestv100% <8• Thu 14 May 17:33:09QProjectv= custom.logAutomatedReportGenerated.phpTrackAutomatedReportGeneratedEvent.phpPlaybackController.php© FieldDefinitions.phpUserAutomatedReportsController.phpPlanhatService.phpAutomatedReportResult.phpSendReportJob.php=laravel.log© FieldValueConverter.php• DeleteCrmEntityTrait.phpDeleteAccountJob.php© ImportActivityTypes.phpT WriteCrmTrait.php© Service.php© DecorateActivity.phpSF [jiminny@localhost]> D CrmObjects© Salesforce/Service.php© LogActivityTrait.phpPipedrive/Service.phpClose/Service.phpCopper/Service.php XA HS_local [jiminny@localho:W• DecorateActivity© PlainTextDecorateActivity.phpT ActivityPlaybookTrait.phpCrmHelperRepository.phpAccountController.php4 console [QAI PROD] X18© BaseDecorateActivity.php© PlainTextDecorateActivity.plT IntegrationAppTrait.php.env.stagingE.env© DetachActivityObject.phpRematchActivityOnCrmObjectDetach.php4 console [PROD]> D Dummy© HandleHubspotRateLimit.phpv Helpers52811 472 M1 ×4T ActivityPlaybookTrait.php1664© Arraylterator.php1681T ConnectionStateTrait.php1682© MatchActivityCrmData.php© Client.php© HubspotPaginationService.phpclass Service extends BaseService implementsprivate function buildCallPayload(Activity $activity): Activityif(Sthis->getCrmType(Sactivitx->category2mmnull2ntSmessage = sprintf( format:'[Copper] Invalid CRM Activity Type: %s', Sactivity->category->getNameO);A console (EU]© CrmHelperRepository.php1683© FilterJoinedParticipants.php1684+ OpportunitySyncableFieldsTthrow new CrmException(Smessage,code:400);1685v D Hubspot1686• AccountSyncStrategy1687> OJ Actions |1688if (Sthis->getCrmType($activity->category)->value === null) {$message = sprintf( format: '[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName 222• ContactSyncStrategy1689> ODTO1690throw new CrmException(Smessage,code: 400):D Fields1691› O Journal1692D Metadata1693v C OpportunitySyncStrategy1694> D Concerns1695© HubspotLastModifiedByF1696© HubspotLastModifiedCre1697© HubspotLastModifiedCre1698// Just create an activity.$cpActivity = $this->copperClient->activities()->create(['user_id' = $this->profile->crm_provider_id,'activity_date' => $activity->scheduled_start_time->timestamp,'parent' => $this->convertActivityAssociations($activity),'type' => Sthis->convertActivityType($activity->category),'details' => $this->generateActivityDescription(Sactivity),© HubspotLastModifiedOpe16991):© HubspotLastModifiedSyn1700DGojiminny v084143 ×4 л215•m_layout_id =2162,1661,66799,66217218219id = 33;=220221=223= 224id THEN '(own225=226= 227228229= 230hubspot';2312322:233V= 11512582;234© HubspotSingleSyncStrate1701© HubspotSyncStrategyBa:1702Sactivity->crm_provider_id = $cpActivity['id']:Sactivity->saveO:© HubspotWebhookBatchS1703v [ Pagination1704ch (ClientException $exception) {© HubspotPaginationServic1705A DaninatinnCanfin nhn/Log all ercons to SentryWorkspace associated with branch 'JY-20725-handle-HS-search-rate-limit' has been restored // Rollback // Configure... (today 16:17)W Windsurf Teams1688:29 (8 chars)UTF-8Co 4 spaces...
|
NULL
|
-7097145309050108631
|
NULL
|
visual_change
|
ocr
|
NULL
|
PhpStormFileEditViewNavigateCodeLaravelRefactorRun PhpStormFileEditViewNavigateCodeLaravelRefactorRunToolsGitWindowHelplhl•FV faVsco.jsv#12066 on JY-20725-handle-HS-search-rate-limit k vHandleHubspotRateLimitTestv100% <8• Thu 14 May 17:33:09QProjectv= custom.logAutomatedReportGenerated.phpTrackAutomatedReportGeneratedEvent.phpPlaybackController.php© FieldDefinitions.phpUserAutomatedReportsController.phpPlanhatService.phpAutomatedReportResult.phpSendReportJob.php=laravel.log© FieldValueConverter.php• DeleteCrmEntityTrait.phpDeleteAccountJob.php© ImportActivityTypes.phpT WriteCrmTrait.php© Service.php© DecorateActivity.phpSF [jiminny@localhost]> D CrmObjects© Salesforce/Service.php© LogActivityTrait.phpPipedrive/Service.phpClose/Service.phpCopper/Service.php XA HS_local [jiminny@localho:W• DecorateActivity© PlainTextDecorateActivity.phpT ActivityPlaybookTrait.phpCrmHelperRepository.phpAccountController.php4 console [QAI PROD] X18© BaseDecorateActivity.php© PlainTextDecorateActivity.plT IntegrationAppTrait.php.env.stagingE.env© DetachActivityObject.phpRematchActivityOnCrmObjectDetach.php4 console [PROD]> D Dummy© HandleHubspotRateLimit.phpv Helpers52811 472 M1 ×4T ActivityPlaybookTrait.php1664© Arraylterator.php1681T ConnectionStateTrait.php1682© MatchActivityCrmData.php© Client.php© HubspotPaginationService.phpclass Service extends BaseService implementsprivate function buildCallPayload(Activity $activity): Activityif(Sthis->getCrmType(Sactivitx->category2mmnull2ntSmessage = sprintf( format:'[Copper] Invalid CRM Activity Type: %s', Sactivity->category->getNameO);A console (EU]© CrmHelperRepository.php1683© FilterJoinedParticipants.php1684+ OpportunitySyncableFieldsTthrow new CrmException(Smessage,code:400);1685v D Hubspot1686• AccountSyncStrategy1687> OJ Actions |1688if (Sthis->getCrmType($activity->category)->value === null) {$message = sprintf( format: '[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName 222• ContactSyncStrategy1689> ODTO1690throw new CrmException(Smessage,code: 400):D Fields1691› O Journal1692D Metadata1693v C OpportunitySyncStrategy1694> D Concerns1695© HubspotLastModifiedByF1696© HubspotLastModifiedCre1697© HubspotLastModifiedCre1698// Just create an activity.$cpActivity = $this->copperClient->activities()->create(['user_id' = $this->profile->crm_provider_id,'activity_date' => $activity->scheduled_start_time->timestamp,'parent' => $this->convertActivityAssociations($activity),'type' => Sthis->convertActivityType($activity->category),'details' => $this->generateActivityDescription(Sactivity),© HubspotLastModifiedOpe16991):© HubspotLastModifiedSyn1700DGojiminny v084143 ×4 л215•m_layout_id =2162,1661,66799,66217218219id = 33;=220221=223= 224id THEN '(own225=226= 227228229= 230hubspot';2312322:233V= 11512582;234© HubspotSingleSyncStrate1701© HubspotSyncStrategyBa:1702Sactivity->crm_provider_id = $cpActivity['id']:Sactivity->saveO:© HubspotWebhookBatchS1703v [ Pagination1704ch (ClientException $exception) {© HubspotPaginationServic1705A DaninatinnCanfin nhn/Log all ercons to SentryWorkspace associated with branch 'JY-20725-handle-HS-search-rate-limit' has been restored // Rollback // Configure... (today 16:17)W Windsurf Teams1688:29 (8 chars)UTF-8Co 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
45370
|
1626
|
14
|
2026-05-14T14:33:08.442631+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769188442_m2.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.2962101,"top":1.0,"width":0.03856383,"height":-0.019952059},"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":"#12066 on JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.33477393,"top":1.0,"width":0.122340426,"height":-0.019952059},"on_screen":true,"help_text":"Pull request #12066 exists for current branch JY-20725-handle-HS-search-rate-limit, but local branch is out of sync with remote","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.5731383,"top":1.0,"width":0.011303191,"height":-0.019952059},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.5884308,"top":1.0,"width":0.076130316,"height":-0.019952059},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7058342144550237105
|
-7195274138713862717
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
ActivityFilesLaterJiminny... ~@ jiminny-x-integrati& platform-inner-team© Channels# ai-chapter# alertsi backend# bugscontusion-cllnia# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the people of iimi..• Direct messages8. A...• A3 62P. Galya Dimitrova Mvasil VasilevA. Stefka Stoyanova%: Todor Stamatovf. Mario GeorgievP. Nikolay Ivanov2o James Graham "2. Stoyan Tanev. Steliyan Georgiev. Petko Kashinski*. Lukas Kovali...a: Apps® ToastS lira Gloud6 Huddle with Aneliya Angelova& R. Aneliya Angelova •• Messagest Add canvasur FilesAneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук,нали?пои останалите скМі тоябва оъчно ла се въвелат.Lukas Kovalik 2:47 PMтряова да се за всички, някьде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova @ 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725X Preview insackt[HubSpot] Optimise CRM rematctOpenReady for QA- MediumAA Aneliya AngelovaAs of today at 4:00 PM RetreshOpen in Jira+ SummariseLukas Kovalik 4:02 PMzean-iurwiniareelYou joined the huddle LIVE 4:06 PMAneliva Angelova is here toolAneliya Angelova 4:44 PM11512582Lukas Kovalik O 5:16 PMcurl --location "httns:ani.hubani.com/crm/v3/obiects/contacts/search--header 'Content-Type: application/json'\--header "Authorization: BearerC|Kvma?iMx7OINOM8kOFwrAowAcAkUAhIR24?A05D?xiVrIYMILuP6SA01Kwcmhr=n.v2 hytorDniMvDalYck-CMalovolNOM9kOFwrAUAcrkcaws-ThwRARIRAOF-ATFSAOFRAO-ROIEBAQUBEggBAQEBAYICFIґ7Au8O2Nwal9YW2CbCCxYvwngmSgNldTFSAFoAYABoAHAAeAA'\--data "{ "limit", 13'Message Aneliva Angelova+ AaIAl Notes: OffLeave~ (Q SearchDate ModifiedYesterdav at 13.36Yesterday at 13:36Yesterday at 13.30Yesterday at 13:34Yesterday at 13:34resterday at 15.5sYesterdav at 13:3kYesterday at 13:32Yesterday at 13.31Yesterday at 13:31Yesterday at 13:30resterday at 15.30Yesterdav at 13:29Yesterday at 13:29Yesterday at 13:28Yesterday at 13:28Yesterday at 13:27resterday at 13-40Yesterdav at 13:26Yesterday at 13:25Yesterday at 13:25Yesterday at 13:24Yesterday at 13:24Yesterday at 13.22Yesterdav at 13:21Yesterday at 13:20Yesterday at 13:19Yesterday at 13.18Yecterdav at 12:19Yesterday at 13-1/Yesterdav at 13:16Yesterday at 13:16Yesterday at 13:15Yecterdav at 12:1/Yesterday at 13:14Yesterday at 13.13Yecterdav at 13:10Yesterday at 13:12Yesterday at 13:11Yesterday at 13:11Yesterday at 13:10Yesterday at 13.10Yecterdav at 12:091Yesterday at 13:09Yesterdav at 13:0823K:MPEG-4 movie9KBMPEG-4 movie13 KB16 Kb17 KEMPEG-4 movieMPEG-4 movie29 KB6 KBMPE0"4 movie12 K:9 KBMPEG-4 movie7 KBMP2G-4 movie37 KBMPEG-4 movie10 KBI KDMPEG"4 movie8 KE9KBMPEG-4 movie8 KB72 KBMPEG-4 movie14 KBMPEG-4 movie13 KB9KBMPEG-4 movie18 KEMPEG-4 movie12 KBMPEG-4 movie10 KB16 K:MPEG-4 movie6 KBMPEG-4 movie12 KBMPEG-4 movie23 KBMPEG-4 movie8 KBMPEG-4 movie6 KBMPEG-4 movie16 K:11 KBMPEG-4 movie20 KBMPEG-4 movie21 KPMPEG-4 movie10 KB MPEG-4 movie7 KBMPEG-4 movie5 KB1MPEG-4 movie11 KBMPEG-4 movie26 KB111 KB102 KRMPEG-4 movieMDEG-A movie88 KB59 KBMPEG-4 movie08 KBIMPEG-A movie97 KB MPEG-4 movie66 KB44 KB02 KpMPEG-4 movieMPEG-4 movie78 KB50 KBMPEG-4 movie58 KГMPEG-A movid27 KBMPEG-4 movie7 KB12K8MPEG-4 movieFavouritesE jiminny© Recents* ApplicationsiCloudiCloud Drive228 Sync folderQ DXP4800PLUS-B5FA@ Network|• CRMI• Orange• Red• Yellow• Green• Purple•) All lags..lohlDownloadsNameLoom.pkgAlfred copv.alfredoreterencesB KeychronAssist-1.0.2 (1).dmgA Keychron Assist-1.0.2.dmgmazanoke-images-yWJo.zioPhotos-3-001.zip→mage U.loge1 Orioninstaller.dmaimage.jpg- image (2).1pc• ПО-22221726037035-004-001_ORGES.pdf• %D0%9F%D0%9E-22221726037035-004-001_archive.zipПO-22221726037035-004-001_archive (1).zipD report(2) xmlAltred copy2.altredoreterences05012026_0000000026574472_ SWIFT_OB70501260015890.pdf27022026_0000000026574472_SWIFT_OB72702260049200.pdf= 03042026 [CREDIT_CARD] SWIFT [CREDIT_CARD].001B reporti) xm=pdt.odipdf-1.pdfD pdf-2.pdf-pdf-5.pd1= ndf-1 ndipdf-3.pdfKoválik Family Tree.gedbitwarden export 20251031122528.isonKoválik Family Tree.zip*macOS Storage_Cleanup.mdal favicon icofirst_aid_notes_complete.docxrenortl2).esvconfig.ymlIteration run Search HS.postman_collection.jsonm licence hettertouchtoolMariusHosting Config.json1ooks-891a6503-bbb7-4b2b-9c3.csv•AlfredwPmazanoko.imnaoc.YWIfана Ковалик.jpg•искане даниел Ковалик..pa• Фактура Март Даниел Ковалик.jpс• Фактура Април Даниел Ковалик.jpg• Dhotac 2.001Q SearchKind00,4 MDinstdlle..dckage55.9 MBAlfred...ferences10,1 MBDisk Image10,1 MBDisk ImageIL MBLiP archive6,6 MBZIP archive2,5 MB PDF Document2,5 MBJreo lmage2.2 MBDisk Image2,2 MB PDF Document2 MBJPEG image1,9 MBJPEG imaqe192 KBPDF Document140 Kb148 KВ148 KB122 KB111 KB94 KBZIP archiveZIP archivelZIP archiveXML documentAlfred...ferencesPDF Document92 KBPDr DocumentPDF Document91 KB91 KB30 KB29 KBXML documentPDF Document28 KB28 KR28 KB27 KB14 KB11 KB6 KB6KB5KR4 KB3 KBPDF DocumentPDE DocumentDocumentJSONICSV DocumentZIP archiveMarkdo…..umentWindo...n imageword ..cumentCSV Document2 KBYAML document1 KBcSV Document928 byteshttlicence183 bytesZero butesJSONAlfred.. ferencesZero bytes1,9 MB1,8 MB17 MB1,7 MBFoldeColdorJPEG imageJPEG ImageJPEG imageJPEG imageColdo1 of 58 selected, 8.5 GB availab!i• Inu 14 Mаy 1/.33.01Date AddedIs Mdl ZUzo dl 19:4530 Jan 2026 at 12:3617 Mar 2026 at 20:2717 Mar 2026 at 20:26Z3 Aor 2020 al 13:0229 Jan 2026 at 15:2019 Dec 2025 at 10:1619 Dec 2025 at 12:238 Aor 2026 at 20:3519 Dec 2025 at 10:2919 Dec 2025 at 12:1819 Dec 2025 at 12:4026 Mar 2026 at 11:2410 May 2026 at 13:5326 Mar 2026 at 11:2426 Mar 2026 at 11:2426 Mar 2026 at 11:2310 May 2026 at 14:3730 Jan 2026 at 12:3713 Feb 2026 at 11:54Z3 Apr 2026 at 13.0823 Aor 2026 at 13:0810 May 2026 at 13:5410 May 2026 at 14:3710 May 2026 at 13:4910 May 2026 at 13:5010 May 2026 at 13:5110 Mav 2026 at 12:51110 May 2026 at 13:5019 Dec 2025 at 11:3431 Oct 2025 at 12:2525 Nov 2025 at 17:596 Mar 2026 at 11.2224 Anr 2026 at 16:5220 Oct 2025 at 11:0218 Mar 2026 at 15:29• Mav 2026 at 11:09129 Oct 2025 at 19:329 May 2026 at 10:0418 Mar 2026 at 11:5510 May 2026 at 13:5712 Jun 2025 at 19:0430 Jan 2026 at 12:3630 Jan 2026 at 12:3616 Oct 2025 aт 16:0123 Apr 2026 at 13:0223 Apr 2026 at 13:0223 Apr 2026 at 13:0222 Anr 2026 at 12:0223 Apr 2026 at 13:0229 Jan 2026 at 15:20...
|
45367
|
NULL
|
NULL
|
NULL
|
|
45369
|
1625
|
22
|
2026-05-14T14:33:08.460007+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769188460_m1.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.054166667,"top":0.027777778,"width":0.08055556,"height":0.035555556},"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":"#12066 on JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.13472222,"top":0.027777778,"width":0.25555557,"height":0.035555556},"on_screen":true,"help_text":"Pull request #12066 exists for current branch JY-20725-handle-HS-search-rate-limit, but local branch is out of sync with remote","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.6326389,"top":0.027777778,"width":0.023611112,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.6645833,"top":0.027777778,"width":0.15902779,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7058342144550237105
|
-7195274138713862717
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
PhpStormFileEditViewNavigateCodeLaravelRefactorRunToolsGitWindowHelp•FV faVsco.jsv* #12066 on JY-20725-handle-HS-search-rate-limit k vabl100% CHandleHubspotRateLimitTest8• Thu 14 May 17:33:08* :QProjectv:=custom.logAutomatedReportGenerated.phpTrackAutomatedReportGeneratedEvent.phpPlaybackController.php© FieldDefinitions.php© UserAutomatedReportsController.phpPlanhatService.phpAutomatedReportResult.phpSendReportJob.php=laravel.log© FieldValueConverter.php• DeleteCrmEntityTrait.phpDeleteAccountJob.php© ImportActivityTypes.phpT WriteCrmTrait.php© Service.php© DecorateActivity.phpSF [jiminny@localhost]> D CrmObjects© Salesforce/Service.php© LogActivityTrait.php© Pipedrive/Service.php© Close/Service.phpCopper/Service.php XA HS_local [jiminny@localho:W• DecorateActivity© PlainTextDecorateActivity.phpT ActivityPlaybookTrait.php© CrmHelperRepository.php© AccountController.php4 console [QAI PROD] X18© BaseDecorateActivity.php© PlainTextDecorateActivity.plT IntegrationAppTrait.php=.env.stagingE.env© DetachActivityObject.phpRematchActivityOnCrmObjectDetach.php4 console [PROD]> D Dummyv HelpersT ActivityPlaybookTrait.php521664© MatchActivityCrmData.php© Client.php© HubspotPaginationService.phpclass Service extends BaseService implementsprivatefunction buildCallPayload(Activity $activity): Activity© HandleHubspotRateLimit.phpA console (EU]811 472 M1 ×4© Arraylterator.phpT ConnectionStateTrait.php1674© CrmHelperRepository.php1675© FilterJoinedParticipants.php1676© OpportunitySyncableFieldsT 1677v D Hubspot1678• AccountSyncStrategy1679> OJ Actions |1680Sthis->copperClient->tasks()->update($activity->crm_provider_id, ['status' =>'Completed','custom_activity_type_id' => $newActivityType->value,'details' => $this-›generateActivityDescription(Sactivity),1):else{id = 33;• ContactSyncStrategy1681> ODTO1682if(Sthis->getCrmType(Sactivitx-2categacx2null2ntSmessage = sprintf( format: '[Copper] Invalid CRM Activity Type: %s', Sactivity->category->getName()) ; E223D Fields1683› Journal1684• Metadata1685v C OpportunitySyncStrategy1686> D Concerns1687© HubspotLastModifiedByf 1688© HubspotLastModifiedCre1689© HubspotLastModifiedCre1690HubspotLastModifiedOpe1691|© HubspotLastModifiedSyn16921693DGo jiminny084143 ×4 л215•m_layout_id =2162,1661,66799,66217218219=220221: 222= 224— 225=226Extract Surround / E :=2271t (scnis->getcrmiype(>activity->category)->value === nul) {228Smessage = sprintf( format: '[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName 229= 230231t232233 V234id THEN(ownthrow new CrmException(Smessage,code: 400);HIhubspat":throw new CrmException(Smessage,code: 400);// Just createan activity.= 11512582;© HubspotSingleSyncStrate$cpActivity = $this->copperClient-›activities()->create([© HubspotSyncStrategyBa:1694'user_id' => $this->profile->crm_provider_id,© HubspotWebhookBatchS1695'activity_date' => $activity->scheduled_start_time->timestamp,v [ Pagination1696'parent' => $this->convertActivityAssociations(Sactivity),© HubspotPaginationServic 1697'type' => $this->convertActivityType($activity->category),A DaninationCanfin nhn1698'details= $this->qenerateActivityDescription(Sactivity)Workspace associated with branch 'JY-20725-handle-HS-search-rate-limit' has been restored // Rollback // Configure... (today 16:17)W Windsurf Teams1685:18 (246 chars, 4 line breaks)UTF-8Ca 4 spaces...
|
45368
|
NULL
|
NULL
|
NULL
|
|
45367
|
1626
|
13
|
2026-05-14T14:32:59.007462+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769179007_m2.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
ActivityFilesLaterJiminny... ~@ jiminny-x-integrat ActivityFilesLaterJiminny... ~@ jiminny-x-integrati& platform-inner-team© Channels# ai-chapter# alertsi backend# bugscontusion-cllnia# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the people of iimi..• Direct messages8. A...• A3 62P. Galya Dimitrova Mvasil VasilevA. Stefka Stoyanova%: Todor Stamatovf. Mario GeorgievP. Nikolay Ivanov2o James Graham "2. Stoyan Tanev. Steliyan Georgiev. Petko Kashinski*. Lukas Kovali...a: Apps® ToastS lira Gloud6 Huddle with Aneliya Angelova& R. Aneliya Angelova •• Messagest Add canvasur FilesAneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук,нали?пои останалите скМі тоябва оъчно ла се въвелат.Lukas Kovalik 2:47 PMтряова да се за всички, някьде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova @ 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725X Preview insackt[HubSpot] Optimise CRM rematctOpenReady for QA- MediumAA Aneliya AngelovaAs of today at 4:00 PM RetreshOpen in Jira+ SummariseLukas Kovalik 4:02 PMzean-iurwiniareelYou joined the huddle LIVE 4:06 PMAneliva Angelova is here toolAneliya Angelova 4:44 PM11512582Lukas Kovalik O 5:16 PMcurl --location "httns:ani.hubani.com/crm/v3/obiects/contacts/search--header 'Content-Type: application/json'\--header "Authorization: BearerC|Kvma?iMx7OINOM8kOFwrAowAcAkUAhIR24?A05D?xiVrIYMILuP6SA01Kwcmhr=n.v2 hytorDniMvDalYck-CMalovolNOM9kOFwrAUAcrkcaws-ThwRARIRAOF-ATFSAOFRAO-ROIEBAQUBEggBAQEBAYICFIґ7Au8O2Nwal9YW2CbCCxYvwngmSgNldTFSAFoAYABoAHAAeAA'\--data "{ "limit", 13'Message Aneliva Angelova+ AaIAl Notes: OffLeave~ (Q SearchDate ModifiedYesterdav at 13.36Yesterday at 13:36Yesterday at 13.30Yesterday at 13:34Yesterday at 13:34resterday at 15.5sYesterdav at 13:3kYesterday at 13:32Yesterday at 13.31Yesterday at 13:31Yesterday at 13:30resterday at 15.30Yesterdav at 13:29Yesterday at 13:29Yesterday at 13:28Yesterday at 13:28Yesterday at 13:27resterday at 13-40Yesterdav at 13:26Yesterday at 13:25Yesterday at 13:25Yesterday at 13:24Yesterday at 13:24Yesterday at 13.22Yesterdav at 13:21Yesterday at 13:20Yesterday at 13:19Yesterday at 13.18Yecterdav at 12:19Yesterday at 13-1/Yesterdav at 13:16Yesterday at 13:16Yesterday at 13:15Yecterdav at 12:1/Yesterday at 13:14Yesterday at 13.13Yecterdav at 13:10Yesterday at 13:12Yesterday at 13:11Yesterday at 13:11Yesterday at 13:10Yesterday at 13.10Yecterdav at 12:091Yesterday at 13:09Yesterdav at 13:0823K:MPEG-4 movie9KBMPEG-4 movie13 KB16 Kb17 KEMPEG-4 movieMPEG-4 movie29 KB6 KBMPE0"4 movie12 K:9 KBMPEG-4 movie7 KBMP2G-4 movie37 KBMPEG-4 movie10 KBI KDMPEG"4 movie8 KE9KBMPEG-4 movie8 KB72 KBMPEG-4 movie14 KBMPEG-4 movie13 KB9KBMPEG-4 movie18 KEMPEG-4 movie12 KBMPEG-4 movie10 KB16 K:MPEG-4 movie6 KBMPEG-4 movie12 KBMPEG-4 movie23 KBMPEG-4 movie8 KBMPEG-4 movie6 KBMPEG-4 movie16 K:11 KBMPEG-4 movie20 KBMPEG-4 movie21 KPMPEG-4 movie10 KB MPEG-4 movie7 KBMPEG-4 movie5 KB1MPEG-4 movie11 KBMPEG-4 movie26 KB111 KB102 KRMPEG-4 movieMDEG-A movie88 KB59 KBMPEG-4 movie08 KBIMPEG-A movie97 KB MPEG-4 movie66 KB44 KB02 KpMPEG-4 movieMPEG-4 movie78 KB50 KBMPEG-4 movie58 KГMPEG-A movid27 KBMPEG-4 movie7 KB12K8MPEG-4 movieFavouritesE jiminny© Recents* ApplicationsiCloudiCloud Drive228 Sync folderQ DXP4800PLUS-B5FA@ Network|• CRMI• Orange• Red• Yellow• Green• Purple•) All lags..lohlDownloadsNameLoom.pkgAlfred copv.alfredoreterencesB KeychronAssist-1.0.2 (1).dmgA Keychron Assist-1.0.2.dmgmazanoke-images-yWJo.zioPhotos-3-001.zip→mage U.loge1 Orioninstaller.dmaimage.jpg- image (2).1pc• ПО-22221726037035-004-001_ORGES.pdf• %D0%9F%D0%9E-22221726037035-004-001_archive.zipПO-22221726037035-004-001_archive (1).zipD report(2) xmlAltred copy2.altredoreterences05012026_0000000026574472_ SWIFT_OB70501260015890.pdf27022026_0000000026574472_SWIFT_OB72702260049200.pdf= 03042026 [CREDIT_CARD] SWIFT [CREDIT_CARD].001B reporti) xm=pdt.odipdf-1.pdfD pdf-2.pdf-pdf-5.pd1= ndf-1 ndipdf-3.pdfKoválik Family Tree.gedbitwarden export 20251031122528.isonKoválik Family Tree.zip*macOS Storage_Cleanup.mdal favicon icofirst_aid_notes_complete.docxrenortl2).esvconfig.ymlIteration run Search HS.postman_collection.jsonm licence hettertouchtoolMariusHosting Config.json1ooks-891a6503-bbb7-4b2b-9c3.csv•AlfredwPmazanoko.imnaoc.YWIfана Ковалик.jpg•искане даниел Ковалик..pa• Фактура Март Даниел Ковалик.jpс• Фактура Април Даниел Ковалик.jpg• Dhotac 2.001Q SearchKind00,4 MDinstdlle..dckage55.9 MBAlfred...ferences10,1 MBDisk Image10,1 MBDisk ImageIL MBLiP archive6,6 MBZIP archive2,5 MB PDF Document2,5 MBJreo lmage2.2 MBDisk Image2,2 MB PDF Document2 MBJPEG image1,9 MBJPEG imaqe192 KBPDF Document140 Kb148 KВ148 KB122 KB111 KB94 KBZIP archiveZIP archivelZIP archiveXML documentAlfred...ferencesPDF Document92 KBPDr DocumentPDF Document91 KB91 KB30 KB29 KBXML documentPDF Document28 KB28 KR28 KB27 KB14 KB11 KB6 KB6KB5KR4 KB3 KBPDF DocumentPDE DocumentDocumentJSONICSV DocumentZIP archiveMarkdo…..umentWindo...n imageword ..cumentCSV Document2 KBYAML document1 KBcSV Document928 byteshttlicence183 bytesZero butesJSONAlfred.. ferencesZero bytes1,9 MB1,8 MB17 MB1,7 MBFoldeColdorJPEG imageJPEG ImageJPEG imageJPEG imageColdo1 of 58 selected, 8.5 GB availab!i• Inu 14 May 1/.32:00Date AddedIs Mdl ZUzo dl 19:4530 Jan 2026 at 12:3617 Mar 2026 at 20:2717 Mar 2026 at 20:26Z3 Aor 2020 al 13:0229 Jan 2026 at 15:2019 Dec 2025 at 10:1619 Dec 2025 at 12:238 Aor 2026 at 20:3519 Dec 2025 at 10:2919 Dec 2025 at 12:1819 Dec 2025 at 12:4026 Mar 2026 at 11:2410 May 2026 at 13:5326 Mar 2026 at 11:2426 Mar 2026 at 11:2426 Mar 2026 at 11:2310 May 2026 at 14:3730 Jan 2026 at 12:3713 Feb 2026 at 11:54Z3 Apr 2026 at 13.0823 Aor 2026 at 13:0810 May 2026 at 13:5410 May 2026 at 14:3710 May 2026 at 13:4910 May 2026 at 13:5010 May 2026 at 13:5110 Mav 2026 at 12:51110 May 2026 at 13:5019 Dec 2025 at 11:3431 Oct 2025 at 12:2525 Nov 2025 at 17:596 Mar 2026 at 11.2224 Anr 2026 at 16:5220 Oct 2025 at 11:0218 Mar 2026 at 15:29• Mav 2026 at 11:09129 Oct 2025 at 19:329 May 2026 at 10:0418 Mar 2026 at 11:5510 May 2026 at 13:5712 Jun 2025 at 19:0430 Jan 2026 at 12:3630 Jan 2026 at 12:3616 Oct 2025 aт 16:0123 Apr 2026 at 13:0223 Apr 2026 at 13:0223 Apr 2026 at 13:0222 Anr 2026 at 12:0223 Apr 2026 at 13:0229 Jan 2026 at 15:20...
|
NULL
|
2977166443459692715
|
NULL
|
click
|
ocr
|
NULL
|
ActivityFilesLaterJiminny... ~@ jiminny-x-integrat ActivityFilesLaterJiminny... ~@ jiminny-x-integrati& platform-inner-team© Channels# ai-chapter# alertsi backend# bugscontusion-cllnia# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the people of iimi..• Direct messages8. A...• A3 62P. Galya Dimitrova Mvasil VasilevA. Stefka Stoyanova%: Todor Stamatovf. Mario GeorgievP. Nikolay Ivanov2o James Graham "2. Stoyan Tanev. Steliyan Georgiev. Petko Kashinski*. Lukas Kovali...a: Apps® ToastS lira Gloud6 Huddle with Aneliya Angelova& R. Aneliya Angelova •• Messagest Add canvasur FilesAneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук,нали?пои останалите скМі тоябва оъчно ла се въвелат.Lukas Kovalik 2:47 PMтряова да се за всички, някьде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova @ 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725X Preview insackt[HubSpot] Optimise CRM rematctOpenReady for QA- MediumAA Aneliya AngelovaAs of today at 4:00 PM RetreshOpen in Jira+ SummariseLukas Kovalik 4:02 PMzean-iurwiniareelYou joined the huddle LIVE 4:06 PMAneliva Angelova is here toolAneliya Angelova 4:44 PM11512582Lukas Kovalik O 5:16 PMcurl --location "httns:ani.hubani.com/crm/v3/obiects/contacts/search--header 'Content-Type: application/json'\--header "Authorization: BearerC|Kvma?iMx7OINOM8kOFwrAowAcAkUAhIR24?A05D?xiVrIYMILuP6SA01Kwcmhr=n.v2 hytorDniMvDalYck-CMalovolNOM9kOFwrAUAcrkcaws-ThwRARIRAOF-ATFSAOFRAO-ROIEBAQUBEggBAQEBAYICFIґ7Au8O2Nwal9YW2CbCCxYvwngmSgNldTFSAFoAYABoAHAAeAA'\--data "{ "limit", 13'Message Aneliva Angelova+ AaIAl Notes: OffLeave~ (Q SearchDate ModifiedYesterdav at 13.36Yesterday at 13:36Yesterday at 13.30Yesterday at 13:34Yesterday at 13:34resterday at 15.5sYesterdav at 13:3kYesterday at 13:32Yesterday at 13.31Yesterday at 13:31Yesterday at 13:30resterday at 15.30Yesterdav at 13:29Yesterday at 13:29Yesterday at 13:28Yesterday at 13:28Yesterday at 13:27resterday at 13-40Yesterdav at 13:26Yesterday at 13:25Yesterday at 13:25Yesterday at 13:24Yesterday at 13:24Yesterday at 13.22Yesterdav at 13:21Yesterday at 13:20Yesterday at 13:19Yesterday at 13.18Yecterdav at 12:19Yesterday at 13-1/Yesterdav at 13:16Yesterday at 13:16Yesterday at 13:15Yecterdav at 12:1/Yesterday at 13:14Yesterday at 13.13Yecterdav at 13:10Yesterday at 13:12Yesterday at 13:11Yesterday at 13:11Yesterday at 13:10Yesterday at 13.10Yecterdav at 12:091Yesterday at 13:09Yesterdav at 13:0823K:MPEG-4 movie9KBMPEG-4 movie13 KB16 Kb17 KEMPEG-4 movieMPEG-4 movie29 KB6 KBMPE0"4 movie12 K:9 KBMPEG-4 movie7 KBMP2G-4 movie37 KBMPEG-4 movie10 KBI KDMPEG"4 movie8 KE9KBMPEG-4 movie8 KB72 KBMPEG-4 movie14 KBMPEG-4 movie13 KB9KBMPEG-4 movie18 KEMPEG-4 movie12 KBMPEG-4 movie10 KB16 K:MPEG-4 movie6 KBMPEG-4 movie12 KBMPEG-4 movie23 KBMPEG-4 movie8 KBMPEG-4 movie6 KBMPEG-4 movie16 K:11 KBMPEG-4 movie20 KBMPEG-4 movie21 KPMPEG-4 movie10 KB MPEG-4 movie7 KBMPEG-4 movie5 KB1MPEG-4 movie11 KBMPEG-4 movie26 KB111 KB102 KRMPEG-4 movieMDEG-A movie88 KB59 KBMPEG-4 movie08 KBIMPEG-A movie97 KB MPEG-4 movie66 KB44 KB02 KpMPEG-4 movieMPEG-4 movie78 KB50 KBMPEG-4 movie58 KГMPEG-A movid27 KBMPEG-4 movie7 KB12K8MPEG-4 movieFavouritesE jiminny© Recents* ApplicationsiCloudiCloud Drive228 Sync folderQ DXP4800PLUS-B5FA@ Network|• CRMI• Orange• Red• Yellow• Green• Purple•) All lags..lohlDownloadsNameLoom.pkgAlfred copv.alfredoreterencesB KeychronAssist-1.0.2 (1).dmgA Keychron Assist-1.0.2.dmgmazanoke-images-yWJo.zioPhotos-3-001.zip→mage U.loge1 Orioninstaller.dmaimage.jpg- image (2).1pc• ПО-22221726037035-004-001_ORGES.pdf• %D0%9F%D0%9E-22221726037035-004-001_archive.zipПO-22221726037035-004-001_archive (1).zipD report(2) xmlAltred copy2.altredoreterences05012026_0000000026574472_ SWIFT_OB70501260015890.pdf27022026_0000000026574472_SWIFT_OB72702260049200.pdf= 03042026 [CREDIT_CARD] SWIFT [CREDIT_CARD].001B reporti) xm=pdt.odipdf-1.pdfD pdf-2.pdf-pdf-5.pd1= ndf-1 ndipdf-3.pdfKoválik Family Tree.gedbitwarden export 20251031122528.isonKoválik Family Tree.zip*macOS Storage_Cleanup.mdal favicon icofirst_aid_notes_complete.docxrenortl2).esvconfig.ymlIteration run Search HS.postman_collection.jsonm licence hettertouchtoolMariusHosting Config.json1ooks-891a6503-bbb7-4b2b-9c3.csv•AlfredwPmazanoko.imnaoc.YWIfана Ковалик.jpg•искане даниел Ковалик..pa• Фактура Март Даниел Ковалик.jpс• Фактура Април Даниел Ковалик.jpg• Dhotac 2.001Q SearchKind00,4 MDinstdlle..dckage55.9 MBAlfred...ferences10,1 MBDisk Image10,1 MBDisk ImageIL MBLiP archive6,6 MBZIP archive2,5 MB PDF Document2,5 MBJreo lmage2.2 MBDisk Image2,2 MB PDF Document2 MBJPEG image1,9 MBJPEG imaqe192 KBPDF Document140 Kb148 KВ148 KB122 KB111 KB94 KBZIP archiveZIP archivelZIP archiveXML documentAlfred...ferencesPDF Document92 KBPDr DocumentPDF Document91 KB91 KB30 KB29 KBXML documentPDF Document28 KB28 KR28 KB27 KB14 KB11 KB6 KB6KB5KR4 KB3 KBPDF DocumentPDE DocumentDocumentJSONICSV DocumentZIP archiveMarkdo…..umentWindo...n imageword ..cumentCSV Document2 KBYAML document1 KBcSV Document928 byteshttlicence183 bytesZero butesJSONAlfred.. ferencesZero bytes1,9 MB1,8 MB17 MB1,7 MBFoldeColdorJPEG imageJPEG ImageJPEG imageJPEG imageColdo1 of 58 selected, 8.5 GB availab!i• Inu 14 May 1/.32:00Date AddedIs Mdl ZUzo dl 19:4530 Jan 2026 at 12:3617 Mar 2026 at 20:2717 Mar 2026 at 20:26Z3 Aor 2020 al 13:0229 Jan 2026 at 15:2019 Dec 2025 at 10:1619 Dec 2025 at 12:238 Aor 2026 at 20:3519 Dec 2025 at 10:2919 Dec 2025 at 12:1819 Dec 2025 at 12:4026 Mar 2026 at 11:2410 May 2026 at 13:5326 Mar 2026 at 11:2426 Mar 2026 at 11:2426 Mar 2026 at 11:2310 May 2026 at 14:3730 Jan 2026 at 12:3713 Feb 2026 at 11:54Z3 Apr 2026 at 13.0823 Aor 2026 at 13:0810 May 2026 at 13:5410 May 2026 at 14:3710 May 2026 at 13:4910 May 2026 at 13:5010 May 2026 at 13:5110 Mav 2026 at 12:51110 May 2026 at 13:5019 Dec 2025 at 11:3431 Oct 2025 at 12:2525 Nov 2025 at 17:596 Mar 2026 at 11.2224 Anr 2026 at 16:5220 Oct 2025 at 11:0218 Mar 2026 at 15:29• Mav 2026 at 11:09129 Oct 2025 at 19:329 May 2026 at 10:0418 Mar 2026 at 11:5510 May 2026 at 13:5712 Jun 2025 at 19:0430 Jan 2026 at 12:3630 Jan 2026 at 12:3616 Oct 2025 aт 16:0123 Apr 2026 at 13:0223 Apr 2026 at 13:0223 Apr 2026 at 13:0222 Anr 2026 at 12:0223 Apr 2026 at 13:0229 Jan 2026 at 15:20...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
45365
|
1626
|
12
|
2026-05-14T14:32:55.476143+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769175476_m2.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
11
72
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Copper;
use Carbon\Carbon;
use Exception;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Support\Facades\Cache;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\CopperInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Crm\LayoutEntity;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Repositories\UserRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Copper\Api\Client;
use Jiminny\Services\Crm\Copper\Api\ClientFactory;
use Jiminny\Services\Crm\Copper\Exception\RequestFailedException;
use Jiminny\Services\Crm\Helpers\FilterJoinedParticipants;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\Copper\Traits\SearchesCrmEntities;
use Jiminny\Utils\CurrencyFormatter;
use Jiminny\Utils\StringUtil;
class Service extends BaseService implements
CopperInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
RemoteEntityManipulationInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use SearchesCrmEntities;
private const int NOTE_BODY_MAX_LENGTH = 3000000;
private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day
private const array STANDARD_OPPORTUNITY_FIELDS = [
'monetary_value' => [
'label' => 'Value',
'available_on' => Field::OBJECT_OPPORTUNITY,
'type' => Field::TYPE_CURRENCY,
],
'pipeline_stage_id' => [
'label' => 'Stage',
'type' => Field::TYPE_PICKLIST,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
'close_date' => [
'label' => 'Close date',
'type' => Field::TYPE_DATE,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
'win_probability' => [
'label' => 'Win probability',
'type' => Field::TYPE_NUMBER,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
];
private const string UNSUPPORTED_OBJECT_TYPE = 'unsupported';
private const string OPPORTUNITY_STATUS_OPEN = 'Open';
private const string OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE = 'Opportunity import failed';
private const string RESOURCE_UPDATE_FAILED_ERROR_MESSAGE = 'Failed to update resource';
private FieldValueConverter $fieldValueConverter;
private ClientFactory $clientFactory;
private ?Client $copperClient = null;
public function __construct(
ClientFactory $clientFactory,
FieldValueConverter $fieldValueConverter,
private readonly UserRepository $userRepository,
private readonly ProspectPhotoPathService $prospectPhotoPathService,
private readonly CrmEntityRepository $crmEntityRepository
) {
parent::__construct();
$this->clientFactory = $clientFactory;
$this->fieldValueConverter = $fieldValueConverter;
}
public function getDisplayName(): string
{
return 'Copper';
}
/**
* Get the CRM entity repository (used by SearchesCrmEntities trait)
*/
protected function getCrmEntityRepository(): CrmEntityRepository
{
return $this->crmEntityRepository;
}
public function getMinimumApiVersion(): string
{
return Client::MIN_API_VERSION;
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
$owner = $user->team->owner;
return $owner->getSocialAccount(SocialAccount::PROVIDER_COPPER);
}
public function setUser(User $user): void
{
$this->configureSentryScope($user);
$this->team = $user->getTeam();
$this->teamService->setTeam($user->getTeam());
$this->setConfiguration($user->getTeam()->getCrmConfiguration());
// Reset state.
$this->profile = $user->getProfile();
if (! $this->profile instanceof Profile) {
// Try to fetch their profile, maybe it was not yet imported?
$this->profile = $this->getProfile($user);
}
}
public function setConfiguration(Configuration $configuration): void
{
$this->config = $configuration;
$this->copperClient = $this->clientFactory->create($configuration);
if ($this->team === null) {
$this->team = $configuration->getTeam();
}
}
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);
}
private function mapObjectType(string $objectType): string
{
$objectType = strtolower($objectType);
switch ($objectType) {
case Field::OBJECT_TASK:
case Field::OBJECT_OPPORTUNITY:
case Field::OBJECT_LEAD:
$mappedType = $objectType;
break;
case Field::OBJECT_ACCOUNT:
$mappedType = 'company';
break;
case Field::OBJECT_CONTACT:
$mappedType = 'person';
break;
default:
$mappedType = self::UNSUPPORTED_OBJECT_TYPE;
break;
}
return $mappedType;
}
/**
* @param string $crmObject The name of the CRM object. i.e. Opportunity or Contact
*/
protected function getFields(string $crmObject): array
{
$mappedObjectType = $this->mapObjectType($crmObject);
if (! $this->isSupportedObjectType($mappedObjectType)) {
return [];
}
$customFields = $this->copperClient->fields()->all();
$filteredFields = array_filter(
$customFields,
static fn ($field) => in_array($mappedObjectType, $field['available_on'], true)
);
return array_map(
fn (array $property) => [
'name' => $property['id'],
'label' => $property['name'],
'type' => $this->convertFieldType($property['data_type']),
],
$filteredFields
);
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
// Setup the activity field as the default Type.
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'type',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldFilters = FieldDefinitions::taskFollowupFieldsFilter();
foreach ($fieldFilters as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
public function syncFields(): void
{
$this->syncStandardFields();
$this->syncCustomFields();
}
public function syncField(Field $field): void
{
if ($field->getCrmProviderId() === 'type') {
/**
* This field is a special case, it is not a custom field and is not returned by the Copper API.
*
* The field is created manually during layout setup.
*
* @see getDefaultFields()
*
* There is a separate endpoint to get the activity types.
* @see importPicklistValues()
*/
return;
}
if ($field->getCrmProviderId() === 'pipeline_stage_id') {
// Not a custom type
return;
}
$crmField = $this->copperClient->fields()->find($field->getCrmProviderId());
$field->label = $crmField['name'];
$field->type = $this->convertFieldType($crmField['data_type']);
$field->save();
}
/**
* @param string $fieldType How the data should be input
*/
private function convertFieldType(string $fieldType): string
{
$fieldType = strtolower($fieldType);
switch ($fieldType) {
case 'dropdown':
$convertedType = Field::TYPE_PICKLIST;
break;
case 'string':
$convertedType = Field::TYPE_TEXT;
break;
case 'float':
case 'percentage':
$convertedType = Field::TYPE_NUMBER;
break;
case 'text':
$convertedType = Field::TYPE_TEXTAREA;
break;
case 'checkbox':
$convertedType = Field::TYPE_BOOLEAN;
break;
case Field::TYPE_DATE:
case Field::TYPE_CURRENCY:
case Field::TYPE_URL:
$convertedType = $fieldType;
break;
default:
$convertedType = Field::TYPE_UNSUPPORTED;
break;
}
return $convertedType;
}
/**
* @inheritdoc
*/
public function importPicklistValues(Field $field): array
{
$fieldValues = [];
if ($field->object_type === 'opportunity' && $field->crm_provider_id === 'pipeline_stage_id') {
return $this->importFieldValuesForDealInsights($field);
}
$values = [];
if ($field->object_type === Field::OBJECT_TASK && $field->crm_provider_id === 'type') {
$activityTypes = $this->copperClient->activityTypes()->all();
/**
* We ignore "system" activity types, disabled activity types and the "Note" activity type.
*/
$activityTypes = array_filter(
$activityTypes['user'],
fn (array $activityType) => ! $activityType['is_disabled'] && $activityType['id'] !== 0
);
// Import all activity values.
$i = 0;
foreach ($activityTypes as $activityType) {
$values[] = [
'value' => $activityType['id'],
'label' => mb_strimwidth($activityType['name'], 0, Field::LABEL_MAX_LENGTH),
'sequence' => $i++,
];
}
} else {
// We just check for the field in the custom definitions.
$crmField = $this->copperClient->fields()->find($field->crm_provider_id);
// Import all values.
foreach ($crmField['options'] as $option) {
$values[] = [
'value' => $option['id'],
'label' => mb_strimwidth($option['name'], 0, 191),
'sequence' => $option['rank'],
];
}
}
// Take the existing set of field values.
$fieldsToPurge = $field->values()->get()->pluck('value')->toArray();
foreach ($values as $value) {
// For all current values, upsert the field.
$value['value'] = substr($value['value'] ?? '', 0, 255);
$fieldValues[] = $field->values()->updateOrCreate([
'value' => $value['value'],
], $value);
// Remove this value from the ones we are going to purge.
$key = array_search($value['value'], $fieldsToPurge, false);
if ($key !== false) {
unset($fieldsToPurge[$key]);
}
}
// Delete the old values that are no longer used.
$field->values()->whereIn('value', $fieldsToPurge)->delete();
return $fieldValues;
}
/**
*
* @return FieldValue[]
*/
private function importFieldValuesForDealInsights(Field $field): array
{
$fieldValues = [];
$pipelines = $this->copperClient->pipelines()->all();
foreach ($pipelines as $pipeline) {
foreach ($pipeline['stages'] as $i => $dealStage) {
$fieldValues[] = $field->values()->updateOrCreate(
['value' => $dealStage['id']],
[
'label' => $dealStage['name'],
'sequence' => $i,
]
);
}
}
return $fieldValues;
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
if ($types === null) {
$types = [Stage::TYPE_LEAD, Stage::TYPE_OPPORTUNITY];
}
$missingStage = null;
foreach ($types as $type) {
if ($type === Stage::TYPE_LEAD) {
$statuses = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leadStatuses()->all()
);
if (count($statuses) > 0) {
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => BusinessProcess::TYPE_LEAD,
], [
'team_id' => $this->team->id,
'name' => BusinessProcess::TYPE_LEAD,
'type' => BusinessProcess::TYPE_LEAD,
'is_selectable' => true,
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => BusinessProcess::TYPE_LEAD,
], [
'team_id' => $this->team->id,
'name' => BusinessProcess::TYPE_LEAD,
'is_selectable' => true,
'business_process_id' => $businessProcess->id ?? null,
]);
$leadStatuses = [];
foreach ($statuses as $status) {
// Upsert all statuses for the team.
$status = $this->config->stages()->updateOrCreate([
'crm_provider_id' => $status['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($status['name'], 0, 50),
'label' => mb_strimwidth($status['name'], 0, 191),
'type' => Stage::TYPE_LEAD,
'sequence' => $status['order'],
'is_selectable' => true,
]);
if ($missingStageName && $missingStageName === $status['id']) {
$missingStage = $status;
}
$leadStatuses[] = $status['id'];
}
$businessProcess->stages()->sync($leadStatuses);
}
} else {
// We create a business process to contain the pipeline, and later store all stages against it.
foreach ($this->copperClient->pipelines()->all() as $pipeline) {
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $pipeline['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($pipeline['name'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => true,
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $pipeline['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($pipeline['name'], 0, 150),
'is_selectable' => true,
'business_process_id' => $businessProcess->id ?? null,
]);
$stages = [];
foreach ($pipeline['stages'] as $i => $dealStage) {
// Upsert all stages for the team.
$stage = $this->config->stages()->updateOrCreate([
'crm_provider_id' => $dealStage['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($dealStage['name'], 0, 50),
'label' => mb_strimwidth($dealStage['name'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $i,
'is_selectable' => true,
'probability' => $dealStage['win_probability'],
]);
if ($missingStageName && $missingStageName === $dealStage['id']) {
$missingStage = $stage;
}
$stages[] = $stage['id'];
}
$businessProcess->stages()->sync($stages);
}
}
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int
{
$syncCount = 0;
$cpLeads = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->paginate([
'minimum_modified_date' => $since->timestamp,
'sort_by' => 'date_modified',
])
);
foreach ($cpLeads as $cpLead) {
// Only sync if previously imported.
if ($this->hasLead($cpLead['id']) === false) {
$this->importLead($cpLead);
$syncCount++;
}
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncLead(string $crmId): ?Lead
{
$cpLead = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->find($crmId)
);
if (\count($cpLead) === 0) {
return null;
}
return $this->importLead($cpLead);
}
/**
* @inheritdoc
*/
private function importLead($crmData): ?Lead
{
$countryCode = null;
if (! empty($crmData['address']) && isset($crmData['address']['country'])) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$mobilePhone = $parsedNumber = null;
if (! empty($crmData['phone_numbers'])) {
foreach ($crmData['phone_numbers'] as $phoneNumber) {
if ($phoneNumber['category'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);
} else {
$parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);
}
}
}
$name = $crmData['name'];
if (empty($crmData['company_name'])) {
$company = 'Unknown';
} else {
$company = mb_strimwidth($crmData['company_name'], 0, 191);
}
$domain = null;
if (empty($crmData['websites']) === false) {
$domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);
$domain = StringUtil::resolveDomain($domain);
}
$email = null;
if (empty($crmData['email']) === false) {
$email = mb_strimwidth($crmData['email']['email'], 0, 80);
}
$stage = $this->config
->stages()
->where('crm_provider_id', (string) $crmData['status_id'])
->where('type', Stage::TYPE_LEAD)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_LEAD], $crmData['status_id']);
}
if (! $stage instanceof Stage) {
return null;
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($name, 0, 191),
'company' => $company,
'domain' => $domain,
'title' => $crmData['title'] ? mb_strimwidth($crmData['title'], 0, 128) : null,
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'mobile_phone' => $mobilePhone,
'stage_id' => $stage->id,
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Lead::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'country_code' => $countryCode,
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->leads()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
/**
* @inheritdoc
*/
public function syncAccounts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
$cpAccounts = $this->copperClient->accounts()->paginate([
'minimum_modified_date' => $since->timestamp,
'sort_by' => 'date_modified',
]);
foreach ($cpAccounts as $cpAccount) {
// Only sync if previously imported.
if ($this->hasAccount($cpAccount['id'])) {
$this->importAccount($cpAccount);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncAccount(string $crmId): ?Account
{
$cpAccount = $this->copperClient->accounts()->find($crmId);
if (empty($cpAccount)) {
return null;
}
return $this->importAccount($cpAccount);
}
/**
* @inheritdoc
*/
private function importAccount($crmData): Account
{
$countryCode = null;
if (empty($crmData['address']) === false && $crmData['address']['country']) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$name = $crmData['name'];
$parsedNumber = null;
foreach ($crmData['phone_numbers'] as $phoneNumber) {
$parsedNumber = parsePhoneNumber($countryCode, $phoneNumber['number']);
}
$domain = null;
if (empty($crmData['websites']) === false) {
$domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);
$domain = StringUtil::resolveDomain($domain);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($name, 0, 191),
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Account::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'country_code' => $countryCode,
'domain' => $domain,
'phone' => $parsedNumber['phone'] ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->accounts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
public function syncOpportunities(array $parameters, ?string $strategy = null): int
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->copperClient,
]);
$strategies = $strategyResolver->getStrategies($this->config, $strategy);
$syncCount = 0;
try {
foreach ($strategies as $syncStrategy) {
foreach ($syncStrategy->fetchOpportunities($parameters) as $opportunityData) {
$this->importOpportunity($opportunityData);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
$this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => $exception->getMessage(),
]);
}
return $syncCount;
}
public function syncOpportunity(string $crmId): ?Opportunity
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->copperClient,
]);
$strategy = $strategyResolver->resolve(
$this->config,
OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY
);
$parameters['crm_id'] = $crmId;
$cpOpportunity = $strategy->fetchOpportunities($parameters);
return $this->importOpportunity($cpOpportunity);
}
private function importOpportunity($crmData): ?Opportunity
{
$companyId = (string) $crmData['company_id'];
if (empty($companyId)) {
$this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => 'No company id',
]);
return null;
}
$account = $this->config->accounts()->where('crm_provider_id', $companyId)->first();
if ($account === null) {
$account = $this->syncAccount($companyId);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', (string) $crmData['pipeline_id'])
->first();
if ($businessProcess === null) {
// It is possible for some deals to not be in a pipeline.
$this->logger->warning(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => 'Missing pipeline',
]);
return null;
}
$stage = $businessProcess
->stages()
->where('crm_provider_id', (string) $crmData['pipeline_stage_id'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
$this->logger->info('Stage not found, importing', [
'pipeline_id' => $crmData['pipeline_id'],
'stage_id' => $crmData['pipeline_stage_id'],
]);
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData['pipeline_stage_id']);
}
$recordType = $businessProcess->recordTypes()->first();
$closeDate = null;
$isClosed = $crmData['status'] !== self::OPPORTUNITY_STATUS_OPEN;
if ($crmData['close_date']) {
$closeDate = Carbon::parse($crmData['close_date'])->format('Y-m-d');
}
$data = [
'team_id' => $this->team->getId(),
'account_id' => $account->id,
'user_id' => $profile->user_id ?? null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($crmData['name'], 0, 128),
'value' => $crmData['monetary_value'],
'currency_code' => CurrencyFormatter::formatCode($crmData['monetary_unit']),
'close_date' => $closeDate,
'is_closed' => $isClosed,
'is_won' => $crmData['status'] === 'Won',
'stage_id' => $stage->id,
'record_type_id' => $recordType->id ?? null,
'remotely_created_at' => $crmData['date_created'],
];
/** @var Opportunity $opportunity */
$opportunity = $this->config
->opportunities()
->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data)
;
// import external fields into crm_field_data if present
$dealInsightsFields = $this->getOpportunitySyncableFields();
$this->importOpportunityCrmFieldData($crmData, $dealInsightsFields, $opportunity->id);
return $opportunity;
}
/**
* @param array<string, mixed> $opportunityData
* @param string[] $dealInsightsFields
*/
public function importOpportunityCrmFieldData(
array $opportunityData,
array $dealInsightsFields,
int $opportunityId
): void {
foreach ($dealInsightsFields as $fieldName) {
$field = $this->config->fields()->with('entities')
->where('crm_provider_id', $fieldName)
->where('object_type', Field::OBJECT_OPPORTUNITY)
->first();
if (! $field instanceof Field) {
$this->logger->warning('Field not found', [
'field' => $fieldName,
'opportunity_id' => $opportunityId,
]);
continue;
}
$entity = $field->getEntities()->first();
if (! $entity instanceof LayoutEntity) {
continue;
}
$fieldValue = $this->extractFieldValue($opportunityData, $fieldName);
$normalizedValue = $this->normalizeValue($field->getType(), (string) $fieldValue, true);
$field->data()
->updateOrCreate([
'crm_layout_entity_id' => $entity->id,
'crm_field_id' => $field->id,
'object_type' => 'opportunity',
'object_id' => $opportunityId,
], ['value' => $normalizedValue])
;
}
}
/**
* @inheritdoc
*/
public function syncContacts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
$cpContacts = $this->copperClient->contacts()->paginate([
'minimum_interaction_date' => $since->timestamp,
'sort_by' => 'date_modified',
]);
foreach ($cpContacts as $cpContact) {
// Only sync if previously imported.
if ($this->hasContact($cpContact['id'])) {
$this->importContact($cpContact);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
throw $exception;
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncContact(string $crmId): ?Contact
{
$cpContact = $this->copperClient->contacts()->find($crmId);
if (empty($cpContact)) {
return null;
}
return $this->importContact($cpContact);
}
/**
* @inheritdoc
*/
private function importContact($crmData): Contact
{
$account = null;
if ($crmData['company_id']) {
$account = $this->team
->crm
->accounts()
->where('crm_provider_id', (string) $crmData['company_id'])
->first();
if ($account === null) {
$account = $this->syncAccount($crmData['company_id']);
}
}
$countryCode = null;
if (empty($crmData['address']) === false && $crmData['address']['country']) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$mobilePhone = $parsedNumber = null;
foreach ($crmData['phone_numbers'] as $phoneNumber) {
if ($phoneNumber['category'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);
} else {
$parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);
}
}
$email = null;
if (empty($crmData['emails']) === false) {
$email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'account_id' => $account->id ?? null,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => $crmData['name'],
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'mobile_phone' => $mobilePhone ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'title' => $crmData['title'],
'country_code' => $countryCode,
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Contact::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
private function buildContactPhone(?string $countryCode, ?string $number): ?array
{
if ($number) {
// Trim to our width and attempt to parse it.
$number = mb_strimwidth($number, 0, 25);
$parsedNumber = parsePhoneNumber($countryCode, $number);
} else {
$parsedNumber = [];
}
return $parsedNumber;
}
private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string
{
return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
$organization = $this->copperClient->organisation()->all();
if ($this->config->crm_provider_id !== $organization['id']) {
$this->config->update(['crm_provider_id' => $organization['id']]);
}
}
private function syncCustomFields(): void
{
foreach ($this->getFieldTypes() as $fieldType) {
$currentFields = $this->getFields($fieldType);
foreach ($currentFields as $field) {
/** @var Field $field */
$field = $this->config->fields()->updateOrCreate([
'crm_provider_id' => $field['name'],
'object_type' => $fieldType,
], [
'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),
'type' => $field['type'],
]);
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
}
$this->config->save();
}
protected function getFieldTypes(): array
{
return [
parent::OBJECT_TASK,
parent::OBJECT_LEAD,
parent::OBJECT_ACCOUNT,
parent::OBJECT_CONTACT,
parent::OBJECT_OPPORTUNITY,
];
}
/**
* @inheritdoc
*/
public function syncProfiles(?User $userToSearch = null): ?Profile
{
$profiles = $this->copperClient->users()->all();
foreach ($profiles as $profile) {
$user = $this->userRepository->findByTeamAndEmailAddress($this->team, $profile['email'], onlyActive: true);
// Only import profiles for users we have locally.
if ($user) {
$profile = $user->crmProfile()->updateOrCreate([
'crm_configuration_id' => $this->config->id,
'crm_provider_id' => $profile['id'],
]);
if ($userToSearch && $userToSearch->id === $user->id) {
return $profile;
}
}
}
return null;
}
/**
* @inheritdoc
*/
public function syncProfileFields(): void
{
$fieldTypes = [
'task',
'lead',
'account',
'contact',
'opportunity',
];
foreach ($fieldTypes as $fieldType) {
try {
$currentFields = $this->getFields(ucfirst($fieldType));
$newFields = array_column($currentFields, 'name');
$changedFields = array_merge(
array_diff($this->profile->getFieldsAsArray($fieldType), $newFields),
array_diff($newFields, $this->profile->getFieldsAsArray($fieldType))
);
if (\count($changedFields) > 0) {
$fields = implode(',', $newFields);
$this->logger->debug(
ucfirst($fieldType)
. ' fields changed from '
. $this->profile->{$fieldType . '_fields'}
. ' to: '
. $fields
);
$this->profile->{$fieldType . '_fields'} = $fields;
}
} catch (\Exception $exception) {
$this->logger->error('No access to ' . $fieldType . ' object, skipping...');
continue;
}
}
$this->profile->save();
}
/**
* @inheritdoc
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
$scopeValues = array_map(fn ($scope) => is_string($scope) ? $scope : $scope->value, $scopes);
$cacheKey = sprintf('copper-search-%d-%s-%s-%d-%d', $this->team->id, $name, implode('-', $scopeValues), $count, $offset);
return Cache::remember($cacheKey, 300, function () use ($name, $scopes, $count, $offset) {
// Try local search first
$localResults = $this->searchLocally($name, $scopes, $count, $offset);
// If no local results, fall back to remote API search
if (empty($localResults)) {
return $this->searchRemotely($name, $scopes, $count, $offset);
}
return $localResults;
});
}
/**
* @inheritdoc
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
$contact = null;
$account = null;
if ($crmAccountId) {
$account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();
if ($account === null) {
$account = $this->syncAccount($crmAccountId);
}
}
if ($crmContactId) {
$contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();
if ($contact === null) {
$contact = $this->syncContact($crmContactId);
}
}
if ($contact || $account) {
if ($contact && $account === null) {
$account = $contact->account;
}
if ($account === null) {
return [];
}
$params = [
'company_ids' => [$account->crm_provider_id],
'status_ids' => [0], // The integer values are 0, 1, 2, 3, for "Open", "Won", "Lost", and "Abandoned".
'sort_by' => 'date_modified',
'sort_direction' => 'desc',
];
switch ($this->config->opportunity_assignment_rule) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['sort_by'] = 'date_modified';
$params['sort_direction'] = 'desc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['sort_by'] = 'date_created';
$params['sort_direction'] = 'desc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['sort_by'] = 'date_created';
$params['sort_direction'] = 'asc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['sort_by'] = 'date_modified';
$params['sort_direction'] = 'desc';
$params['status_ids'] = [0, 1, 2, 3];
}
$cpOpportunities = $this->copperClient->opportunities()->search($params);
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
foreach ($cpOpportunities as $cpOpportunity) {
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', (string) $cpOpportunity['pipeline_id'])
->first();
if ($businessProcess === null) {
// Import it.
$businessProcess = $this->importStages(
[Stage::TYPE_OPPORTUNITY],
$cpOpportunity['pipeline_stage_id']
);
}
$stage = $businessProcess
->stages()
->where('crm_provider_id', (string) $cpOpportunity['pipeline_stage_id'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $cpOpportunity['pipeline_stage_id']);
}
$recordType = $businessProcess->recordTypes()->first();
$record = [
'crmId' => $cpOpportunity['id'],
'name' => $cpOpportunity['name'],
'value' => currency_format($cpOpportunity['monetary_value'], $cpOpportunity['monetary_unit']),
'won' => $cpOpportunity['status'] === 'Won',
'stage' => [
'id' => $stage->id_string,
'name' => $stage->name,
],
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
if ($ownerId && isset($cpOpportunity['assignee_id']) && $cpOpportunity['assignee_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
}
if (! empty($ownerData)) {
return $ownerData;
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array
{
$data = $cpTasks = [];
switch ($objectType) {
case 'lead':
$cpTasks = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->relatedTasks($objectId)
);
break;
case 'account':
$cpTasks = $this->copperClient->accounts()->relatedTasks($objectId);
break;
case 'contact':
if ($opportunityId) {
$cpTasks = $this->copperClient->opportunities()->relatedTasks($opportunityId);
} elseif ($objectType === 'contact') {
$cpTasks = $this->copperClient->contacts()->relatedTasks($objectId);
}
break;
}
foreach ($cpTasks as $cpTask) {
// We only get the ID itself returned, so pull out the full object.
try {
$cpTask = $this->copperClient->tasks()->find($cpTask['id']);
} catch (Exception $exception) {
$this->logger->error('[Copper] Error fetching task', [
'resource_id' => $cpTask['id'],
'error' => $exception->getMessage(),
]);
continue;
}
// Only allow open tasks.
if ($cpTask['status'] === 'Open') {
$data[] = [
'crmId' => $cpTask['id'],
'subject' => $cpTask['name'],
'due' => $cpTask['due_date']
? Carbon::createFromTimestamp($cpTask['due_date'])->format('Y-m-d\TH:i:sO')
: null,
'type' => null,
];
}
}
return $data;
}
/**
* Try to find email address in CRM service
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$cpObjectType = 'contact';
$cpObjects = $this->copperClient->contacts()->search([
'emails' => $email,
'sort_by' => 'date_modified',
'sort_direction' => 'desc',
]);
if (empty($cpObjects)) {
$cpObjectType = 'lead';
$cpObjects = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->search([
'emails' => ...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.2962101,"top":1.0,"width":0.03856383,"height":-0.019952059},"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":"#12066 on JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.33477393,"top":1.0,"width":0.122340426,"height":-0.019952059},"on_screen":true,"help_text":"Pull request #12066 exists for current branch JY-20725-handle-HS-search-rate-limit, but local branch is out of sync with remote","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.5731383,"top":1.0,"width":0.011303191,"height":-0.019952059},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.5884308,"top":1.0,"width":0.076130316,"height":-0.019952059},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.66456115,"top":1.0,"width":0.011303191,"height":-0.019952059},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.67586434,"top":1.0,"width":0.011303191,"height":-0.019952059},"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.6871675,"top":1.0,"width":0.011303191,"height":-0.019952059},"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.7150931,"top":1.0,"width":0.011303191,"height":-0.019952059},"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.72639626,"top":1.0,"width":0.011303191,"height":-0.019952059},"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.73769945,"top":1.0,"width":0.011303191,"height":-0.019952059},"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":"11","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"72","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"4","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\nnamespace Jiminny\\Services\\Crm\\Copper;\n\nuse Carbon\\Carbon;\nuse Exception;\nuse GuzzleHttp\\Exception\\ClientException;\nuse Illuminate\\Support\\Facades\\Cache;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\CopperInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Crm\\LayoutEntity;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Copper\\Api\\Client;\nuse Jiminny\\Services\\Crm\\Copper\\Api\\ClientFactory;\nuse Jiminny\\Services\\Crm\\Copper\\Exception\\RequestFailedException;\nuse Jiminny\\Services\\Crm\\Helpers\\FilterJoinedParticipants;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Services\\Crm\\Copper\\Traits\\SearchesCrmEntities;\nuse Jiminny\\Utils\\CurrencyFormatter;\nuse Jiminny\\Utils\\StringUtil;\n\nclass Service extends BaseService implements\n CopperInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n RemoteEntityManipulationInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n VerifyTaskExistsInterface\n{\n use SearchesCrmEntities;\n private const int NOTE_BODY_MAX_LENGTH = 3000000;\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n private const array STANDARD_OPPORTUNITY_FIELDS = [\n 'monetary_value' => [\n 'label' => 'Value',\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n 'type' => Field::TYPE_CURRENCY,\n ],\n 'pipeline_stage_id' => [\n 'label' => 'Stage',\n 'type' => Field::TYPE_PICKLIST,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n 'close_date' => [\n 'label' => 'Close date',\n 'type' => Field::TYPE_DATE,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n 'win_probability' => [\n 'label' => 'Win probability',\n 'type' => Field::TYPE_NUMBER,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n ];\n private const string UNSUPPORTED_OBJECT_TYPE = 'unsupported';\n private const string OPPORTUNITY_STATUS_OPEN = 'Open';\n private const string OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE = 'Opportunity import failed';\n private const string RESOURCE_UPDATE_FAILED_ERROR_MESSAGE = 'Failed to update resource';\n\n private FieldValueConverter $fieldValueConverter;\n private ClientFactory $clientFactory;\n private ?Client $copperClient = null;\n\n public function __construct(\n ClientFactory $clientFactory,\n FieldValueConverter $fieldValueConverter,\n private readonly UserRepository $userRepository,\n private readonly ProspectPhotoPathService $prospectPhotoPathService,\n private readonly CrmEntityRepository $crmEntityRepository\n ) {\n parent::__construct();\n\n $this->clientFactory = $clientFactory;\n $this->fieldValueConverter = $fieldValueConverter;\n }\n\n public function getDisplayName(): string\n {\n return 'Copper';\n }\n\n /**\n * Get the CRM entity repository (used by SearchesCrmEntities trait)\n */\n protected function getCrmEntityRepository(): CrmEntityRepository\n {\n return $this->crmEntityRepository;\n }\n\n public function getMinimumApiVersion(): string\n {\n return Client::MIN_API_VERSION;\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n $owner = $user->team->owner;\n\n return $owner->getSocialAccount(SocialAccount::PROVIDER_COPPER);\n }\n\n public function setUser(User $user): void\n {\n $this->configureSentryScope($user);\n\n $this->team = $user->getTeam();\n $this->teamService->setTeam($user->getTeam());\n $this->setConfiguration($user->getTeam()->getCrmConfiguration());\n\n // Reset state.\n $this->profile = $user->getProfile();\n\n if (! $this->profile instanceof Profile) {\n // Try to fetch their profile, maybe it was not yet imported?\n $this->profile = $this->getProfile($user);\n }\n }\n\n public function setConfiguration(Configuration $configuration): void\n {\n $this->config = $configuration;\n $this->copperClient = $this->clientFactory->create($configuration);\n\n if ($this->team === null) {\n $this->team = $configuration->getTeam();\n }\n }\n\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);\n }\n\n private function mapObjectType(string $objectType): string\n {\n $objectType = strtolower($objectType);\n\n switch ($objectType) {\n case Field::OBJECT_TASK:\n case Field::OBJECT_OPPORTUNITY:\n case Field::OBJECT_LEAD:\n $mappedType = $objectType;\n\n break;\n case Field::OBJECT_ACCOUNT:\n $mappedType = 'company';\n\n break;\n case Field::OBJECT_CONTACT:\n $mappedType = 'person';\n\n break;\n default:\n $mappedType = self::UNSUPPORTED_OBJECT_TYPE;\n\n break;\n }\n\n return $mappedType;\n }\n\n /**\n * @param string $crmObject The name of the CRM object. i.e. Opportunity or Contact\n */\n protected function getFields(string $crmObject): array\n {\n $mappedObjectType = $this->mapObjectType($crmObject);\n\n if (! $this->isSupportedObjectType($mappedObjectType)) {\n return [];\n }\n\n $customFields = $this->copperClient->fields()->all();\n\n $filteredFields = array_filter(\n $customFields,\n static fn ($field) => in_array($mappedObjectType, $field['available_on'], true)\n );\n\n return array_map(\n fn (array $property) => [\n 'name' => $property['id'],\n 'label' => $property['name'],\n 'type' => $this->convertFieldType($property['data_type']),\n ],\n $filteredFields\n );\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n // Setup the activity field as the default Type.\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'type',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n $fieldFilters = FieldDefinitions::taskFollowupFieldsFilter();\n\n foreach ($fieldFilters as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n public function syncFields(): void\n {\n $this->syncStandardFields();\n $this->syncCustomFields();\n }\n\n public function syncField(Field $field): void\n {\n if ($field->getCrmProviderId() === 'type') {\n /**\n * This field is a special case, it is not a custom field and is not returned by the Copper API.\n *\n * The field is created manually during layout setup.\n *\n * @see getDefaultFields()\n *\n * There is a separate endpoint to get the activity types.\n * @see importPicklistValues()\n */\n return;\n }\n\n if ($field->getCrmProviderId() === 'pipeline_stage_id') {\n // Not a custom type\n return;\n }\n\n $crmField = $this->copperClient->fields()->find($field->getCrmProviderId());\n $field->label = $crmField['name'];\n $field->type = $this->convertFieldType($crmField['data_type']);\n\n $field->save();\n }\n\n /**\n * @param string $fieldType How the data should be input\n */\n private function convertFieldType(string $fieldType): string\n {\n $fieldType = strtolower($fieldType);\n\n switch ($fieldType) {\n case 'dropdown':\n $convertedType = Field::TYPE_PICKLIST;\n\n break;\n case 'string':\n $convertedType = Field::TYPE_TEXT;\n\n break;\n case 'float':\n case 'percentage':\n $convertedType = Field::TYPE_NUMBER;\n\n break;\n case 'text':\n $convertedType = Field::TYPE_TEXTAREA;\n\n break;\n case 'checkbox':\n $convertedType = Field::TYPE_BOOLEAN;\n\n break;\n case Field::TYPE_DATE:\n case Field::TYPE_CURRENCY:\n case Field::TYPE_URL:\n $convertedType = $fieldType;\n\n break;\n default:\n $convertedType = Field::TYPE_UNSUPPORTED;\n\n break;\n }\n\n return $convertedType;\n }\n\n /**\n * @inheritdoc\n */\n public function importPicklistValues(Field $field): array\n {\n $fieldValues = [];\n\n if ($field->object_type === 'opportunity' && $field->crm_provider_id === 'pipeline_stage_id') {\n return $this->importFieldValuesForDealInsights($field);\n }\n\n $values = [];\n\n if ($field->object_type === Field::OBJECT_TASK && $field->crm_provider_id === 'type') {\n $activityTypes = $this->copperClient->activityTypes()->all();\n\n /**\n * We ignore \"system\" activity types, disabled activity types and the \"Note\" activity type.\n */\n $activityTypes = array_filter(\n $activityTypes['user'],\n fn (array $activityType) => ! $activityType['is_disabled'] && $activityType['id'] !== 0\n );\n\n // Import all activity values.\n $i = 0;\n foreach ($activityTypes as $activityType) {\n $values[] = [\n 'value' => $activityType['id'],\n 'label' => mb_strimwidth($activityType['name'], 0, Field::LABEL_MAX_LENGTH),\n 'sequence' => $i++,\n ];\n }\n } else {\n // We just check for the field in the custom definitions.\n $crmField = $this->copperClient->fields()->find($field->crm_provider_id);\n\n // Import all values.\n foreach ($crmField['options'] as $option) {\n $values[] = [\n 'value' => $option['id'],\n 'label' => mb_strimwidth($option['name'], 0, 191),\n 'sequence' => $option['rank'],\n ];\n }\n }\n\n // Take the existing set of field values.\n $fieldsToPurge = $field->values()->get()->pluck('value')->toArray();\n\n foreach ($values as $value) {\n // For all current values, upsert the field.\n $value['value'] = substr($value['value'] ?? '', 0, 255);\n $fieldValues[] = $field->values()->updateOrCreate([\n 'value' => $value['value'],\n ], $value);\n\n // Remove this value from the ones we are going to purge.\n $key = array_search($value['value'], $fieldsToPurge, false);\n if ($key !== false) {\n unset($fieldsToPurge[$key]);\n }\n }\n\n // Delete the old values that are no longer used.\n $field->values()->whereIn('value', $fieldsToPurge)->delete();\n\n return $fieldValues;\n }\n\n /**\n *\n * @return FieldValue[]\n */\n private function importFieldValuesForDealInsights(Field $field): array\n {\n $fieldValues = [];\n $pipelines = $this->copperClient->pipelines()->all();\n\n foreach ($pipelines as $pipeline) {\n foreach ($pipeline['stages'] as $i => $dealStage) {\n $fieldValues[] = $field->values()->updateOrCreate(\n ['value' => $dealStage['id']],\n [\n 'label' => $dealStage['name'],\n 'sequence' => $i,\n ]\n );\n }\n }\n\n return $fieldValues;\n }\n\n /**\n * @inheritdoc\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n if ($types === null) {\n $types = [Stage::TYPE_LEAD, Stage::TYPE_OPPORTUNITY];\n }\n $missingStage = null;\n\n foreach ($types as $type) {\n if ($type === Stage::TYPE_LEAD) {\n $statuses = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leadStatuses()->all()\n );\n\n if (count($statuses) > 0) {\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => BusinessProcess::TYPE_LEAD,\n ], [\n 'team_id' => $this->team->id,\n 'name' => BusinessProcess::TYPE_LEAD,\n 'type' => BusinessProcess::TYPE_LEAD,\n 'is_selectable' => true,\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => BusinessProcess::TYPE_LEAD,\n ], [\n 'team_id' => $this->team->id,\n 'name' => BusinessProcess::TYPE_LEAD,\n 'is_selectable' => true,\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n $leadStatuses = [];\n foreach ($statuses as $status) {\n // Upsert all statuses for the team.\n $status = $this->config->stages()->updateOrCreate([\n 'crm_provider_id' => $status['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($status['name'], 0, 50),\n 'label' => mb_strimwidth($status['name'], 0, 191),\n 'type' => Stage::TYPE_LEAD,\n 'sequence' => $status['order'],\n 'is_selectable' => true,\n ]);\n\n if ($missingStageName && $missingStageName === $status['id']) {\n $missingStage = $status;\n }\n\n $leadStatuses[] = $status['id'];\n }\n\n $businessProcess->stages()->sync($leadStatuses);\n }\n } else {\n // We create a business process to contain the pipeline, and later store all stages against it.\n foreach ($this->copperClient->pipelines()->all() as $pipeline) {\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => $pipeline['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($pipeline['name'], 0, 150),\n 'type' => BusinessProcess::TYPE_OPPORTUNITY,\n 'is_selectable' => true,\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => $pipeline['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($pipeline['name'], 0, 150),\n 'is_selectable' => true,\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n $stages = [];\n\n foreach ($pipeline['stages'] as $i => $dealStage) {\n // Upsert all stages for the team.\n $stage = $this->config->stages()->updateOrCreate([\n 'crm_provider_id' => $dealStage['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($dealStage['name'], 0, 50),\n 'label' => mb_strimwidth($dealStage['name'], 0, 191),\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'sequence' => $i,\n 'is_selectable' => true,\n 'probability' => $dealStage['win_probability'],\n ]);\n\n if ($missingStageName && $missingStageName === $dealStage['id']) {\n $missingStage = $stage;\n }\n\n $stages[] = $stage['id'];\n }\n\n $businessProcess->stages()->sync($stages);\n }\n }\n }\n\n return $missingStage;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int\n {\n $syncCount = 0;\n\n $cpLeads = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->paginate([\n 'minimum_modified_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ])\n );\n\n foreach ($cpLeads as $cpLead) {\n // Only sync if previously imported.\n if ($this->hasLead($cpLead['id']) === false) {\n $this->importLead($cpLead);\n $syncCount++;\n }\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLead(string $crmId): ?Lead\n {\n $cpLead = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->find($crmId)\n );\n\n if (\\count($cpLead) === 0) {\n return null;\n }\n\n return $this->importLead($cpLead);\n }\n\n /**\n * @inheritdoc\n */\n private function importLead($crmData): ?Lead\n {\n $countryCode = null;\n if (! empty($crmData['address']) && isset($crmData['address']['country'])) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $mobilePhone = $parsedNumber = null;\n if (! empty($crmData['phone_numbers'])) {\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n if ($phoneNumber['category'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);\n } else {\n $parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);\n }\n }\n }\n\n $name = $crmData['name'];\n\n if (empty($crmData['company_name'])) {\n $company = 'Unknown';\n } else {\n $company = mb_strimwidth($crmData['company_name'], 0, 191);\n }\n\n $domain = null;\n if (empty($crmData['websites']) === false) {\n $domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);\n $domain = StringUtil::resolveDomain($domain);\n }\n\n $email = null;\n if (empty($crmData['email']) === false) {\n $email = mb_strimwidth($crmData['email']['email'], 0, 80);\n }\n\n $stage = $this->config\n ->stages()\n ->where('crm_provider_id', (string) $crmData['status_id'])\n ->where('type', Stage::TYPE_LEAD)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_LEAD], $crmData['status_id']);\n }\n\n if (! $stage instanceof Stage) {\n return null;\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($name, 0, 191),\n 'company' => $company,\n 'domain' => $domain,\n 'title' => $crmData['title'] ? mb_strimwidth($crmData['title'], 0, 128) : null,\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'mobile_phone' => $mobilePhone,\n 'stage_id' => $stage->id,\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Lead::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'country_code' => $countryCode,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->leads()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n /**\n * @inheritdoc\n */\n public function syncAccounts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n $cpAccounts = $this->copperClient->accounts()->paginate([\n 'minimum_modified_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ]);\n\n foreach ($cpAccounts as $cpAccount) {\n // Only sync if previously imported.\n if ($this->hasAccount($cpAccount['id'])) {\n $this->importAccount($cpAccount);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncAccount(string $crmId): ?Account\n {\n $cpAccount = $this->copperClient->accounts()->find($crmId);\n\n if (empty($cpAccount)) {\n return null;\n }\n\n return $this->importAccount($cpAccount);\n }\n\n /**\n * @inheritdoc\n */\n private function importAccount($crmData): Account\n {\n $countryCode = null;\n if (empty($crmData['address']) === false && $crmData['address']['country']) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $name = $crmData['name'];\n\n $parsedNumber = null;\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n $parsedNumber = parsePhoneNumber($countryCode, $phoneNumber['number']);\n }\n\n $domain = null;\n if (empty($crmData['websites']) === false) {\n $domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);\n $domain = StringUtil::resolveDomain($domain);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($name, 0, 191),\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Account::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'country_code' => $countryCode,\n 'domain' => $domain,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->accounts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n public function syncOpportunities(array $parameters, ?string $strategy = null): int\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->copperClient,\n ]);\n $strategies = $strategyResolver->getStrategies($this->config, $strategy);\n\n $syncCount = 0;\n\n try {\n foreach ($strategies as $syncStrategy) {\n foreach ($syncStrategy->fetchOpportunities($parameters) as $opportunityData) {\n $this->importOpportunity($opportunityData);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n $this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => $exception->getMessage(),\n ]);\n }\n\n return $syncCount;\n }\n\n public function syncOpportunity(string $crmId): ?Opportunity\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->copperClient,\n ]);\n $strategy = $strategyResolver->resolve(\n $this->config,\n OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY\n );\n\n $parameters['crm_id'] = $crmId;\n\n $cpOpportunity = $strategy->fetchOpportunities($parameters);\n\n return $this->importOpportunity($cpOpportunity);\n }\n\n private function importOpportunity($crmData): ?Opportunity\n {\n $companyId = (string) $crmData['company_id'];\n\n if (empty($companyId)) {\n $this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => 'No company id',\n ]);\n\n return null;\n }\n\n $account = $this->config->accounts()->where('crm_provider_id', $companyId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($companyId);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', (string) $crmData['pipeline_id'])\n ->first();\n\n if ($businessProcess === null) {\n // It is possible for some deals to not be in a pipeline.\n $this->logger->warning(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => 'Missing pipeline',\n ]);\n\n return null;\n }\n\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', (string) $crmData['pipeline_stage_id'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n $this->logger->info('Stage not found, importing', [\n 'pipeline_id' => $crmData['pipeline_id'],\n 'stage_id' => $crmData['pipeline_stage_id'],\n ]);\n\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData['pipeline_stage_id']);\n }\n\n $recordType = $businessProcess->recordTypes()->first();\n $closeDate = null;\n $isClosed = $crmData['status'] !== self::OPPORTUNITY_STATUS_OPEN;\n\n if ($crmData['close_date']) {\n $closeDate = Carbon::parse($crmData['close_date'])->format('Y-m-d');\n }\n\n $data = [\n 'team_id' => $this->team->getId(),\n 'account_id' => $account->id,\n 'user_id' => $profile->user_id ?? null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($crmData['name'], 0, 128),\n 'value' => $crmData['monetary_value'],\n 'currency_code' => CurrencyFormatter::formatCode($crmData['monetary_unit']),\n 'close_date' => $closeDate,\n 'is_closed' => $isClosed,\n 'is_won' => $crmData['status'] === 'Won',\n 'stage_id' => $stage->id,\n 'record_type_id' => $recordType->id ?? null,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n /** @var Opportunity $opportunity */\n $opportunity = $this->config\n ->opportunities()\n ->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data)\n ;\n\n // import external fields into crm_field_data if present\n $dealInsightsFields = $this->getOpportunitySyncableFields();\n $this->importOpportunityCrmFieldData($crmData, $dealInsightsFields, $opportunity->id);\n\n return $opportunity;\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n * @param string[] $dealInsightsFields\n */\n public function importOpportunityCrmFieldData(\n array $opportunityData,\n array $dealInsightsFields,\n int $opportunityId\n ): void {\n foreach ($dealInsightsFields as $fieldName) {\n $field = $this->config->fields()->with('entities')\n ->where('crm_provider_id', $fieldName)\n ->where('object_type', Field::OBJECT_OPPORTUNITY)\n ->first();\n\n if (! $field instanceof Field) {\n $this->logger->warning('Field not found', [\n 'field' => $fieldName,\n 'opportunity_id' => $opportunityId,\n ]);\n\n continue;\n }\n\n $entity = $field->getEntities()->first();\n\n if (! $entity instanceof LayoutEntity) {\n continue;\n }\n\n $fieldValue = $this->extractFieldValue($opportunityData, $fieldName);\n $normalizedValue = $this->normalizeValue($field->getType(), (string) $fieldValue, true);\n\n $field->data()\n ->updateOrCreate([\n 'crm_layout_entity_id' => $entity->id,\n 'crm_field_id' => $field->id,\n 'object_type' => 'opportunity',\n 'object_id' => $opportunityId,\n ], ['value' => $normalizedValue])\n ;\n }\n }\n\n /**\n * @inheritdoc\n */\n public function syncContacts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n $cpContacts = $this->copperClient->contacts()->paginate([\n 'minimum_interaction_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ]);\n\n foreach ($cpContacts as $cpContact) {\n // Only sync if previously imported.\n if ($this->hasContact($cpContact['id'])) {\n $this->importContact($cpContact);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n throw $exception;\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncContact(string $crmId): ?Contact\n {\n $cpContact = $this->copperClient->contacts()->find($crmId);\n\n if (empty($cpContact)) {\n return null;\n }\n\n return $this->importContact($cpContact);\n }\n\n /**\n * @inheritdoc\n */\n private function importContact($crmData): Contact\n {\n $account = null;\n if ($crmData['company_id']) {\n $account = $this->team\n ->crm\n ->accounts()\n ->where('crm_provider_id', (string) $crmData['company_id'])\n ->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmData['company_id']);\n }\n }\n\n $countryCode = null;\n if (empty($crmData['address']) === false && $crmData['address']['country']) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $mobilePhone = $parsedNumber = null;\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n if ($phoneNumber['category'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);\n } else {\n $parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);\n }\n }\n\n $email = null;\n if (empty($crmData['emails']) === false) {\n $email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'account_id' => $account->id ?? null,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => $crmData['name'],\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'mobile_phone' => $mobilePhone ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'title' => $crmData['title'],\n 'country_code' => $countryCode,\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Contact::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n private function buildContactPhone(?string $countryCode, ?string $number): ?array\n {\n if ($number) {\n // Trim to our width and attempt to parse it.\n $number = mb_strimwidth($number, 0, 25);\n $parsedNumber = parsePhoneNumber($countryCode, $number);\n } else {\n $parsedNumber = [];\n }\n\n return $parsedNumber;\n }\n\n private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string\n {\n return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;\n }\n\n /**\n * @inheritdoc\n */\n public function syncOrganization(): void\n {\n $organization = $this->copperClient->organisation()->all();\n\n if ($this->config->crm_provider_id !== $organization['id']) {\n $this->config->update(['crm_provider_id' => $organization['id']]);\n }\n }\n\n private function syncCustomFields(): void\n {\n foreach ($this->getFieldTypes() as $fieldType) {\n $currentFields = $this->getFields($fieldType);\n\n foreach ($currentFields as $field) {\n /** @var Field $field */\n $field = $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => $field['name'],\n 'object_type' => $fieldType,\n ], [\n 'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),\n 'type' => $field['type'],\n ]);\n\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n }\n\n $this->config->save();\n }\n\n protected function getFieldTypes(): array\n {\n return [\n parent::OBJECT_TASK,\n parent::OBJECT_LEAD,\n parent::OBJECT_ACCOUNT,\n parent::OBJECT_CONTACT,\n parent::OBJECT_OPPORTUNITY,\n ];\n }\n\n /**\n * @inheritdoc\n */\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n $profiles = $this->copperClient->users()->all();\n\n foreach ($profiles as $profile) {\n $user = $this->userRepository->findByTeamAndEmailAddress($this->team, $profile['email'], onlyActive: true);\n\n // Only import profiles for users we have locally.\n if ($user) {\n $profile = $user->crmProfile()->updateOrCreate([\n 'crm_configuration_id' => $this->config->id,\n 'crm_provider_id' => $profile['id'],\n ]);\n\n if ($userToSearch && $userToSearch->id === $user->id) {\n return $profile;\n }\n }\n }\n\n return null;\n }\n\n /**\n * @inheritdoc\n */\n public function syncProfileFields(): void\n {\n $fieldTypes = [\n 'task',\n 'lead',\n 'account',\n 'contact',\n 'opportunity',\n ];\n\n foreach ($fieldTypes as $fieldType) {\n try {\n $currentFields = $this->getFields(ucfirst($fieldType));\n\n $newFields = array_column($currentFields, 'name');\n $changedFields = array_merge(\n array_diff($this->profile->getFieldsAsArray($fieldType), $newFields),\n array_diff($newFields, $this->profile->getFieldsAsArray($fieldType))\n );\n\n if (\\count($changedFields) > 0) {\n $fields = implode(',', $newFields);\n $this->logger->debug(\n ucfirst($fieldType)\n . ' fields changed from '\n . $this->profile->{$fieldType . '_fields'}\n . ' to: '\n . $fields\n );\n\n $this->profile->{$fieldType . '_fields'} = $fields;\n }\n } catch (\\Exception $exception) {\n $this->logger->error('No access to ' . $fieldType . ' object, skipping...');\n\n continue;\n }\n }\n\n $this->profile->save();\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n $scopeValues = array_map(fn ($scope) => is_string($scope) ? $scope : $scope->value, $scopes);\n $cacheKey = sprintf('copper-search-%d-%s-%s-%d-%d', $this->team->id, $name, implode('-', $scopeValues), $count, $offset);\n\n return Cache::remember($cacheKey, 300, function () use ($name, $scopes, $count, $offset) {\n // Try local search first\n $localResults = $this->searchLocally($name, $scopes, $count, $offset);\n\n // If no local results, fall back to remote API search\n if (empty($localResults)) {\n return $this->searchRemotely($name, $scopes, $count, $offset);\n }\n\n return $localResults;\n });\n }\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n $contact = null;\n $account = null;\n\n if ($crmAccountId) {\n $account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmAccountId);\n }\n }\n\n if ($crmContactId) {\n $contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();\n\n if ($contact === null) {\n $contact = $this->syncContact($crmContactId);\n }\n }\n\n if ($contact || $account) {\n if ($contact && $account === null) {\n $account = $contact->account;\n }\n\n if ($account === null) {\n return [];\n }\n\n $params = [\n 'company_ids' => [$account->crm_provider_id],\n 'status_ids' => [0], // The integer values are 0, 1, 2, 3, for \"Open\", \"Won\", \"Lost\", and \"Abandoned\".\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ];\n\n switch ($this->config->opportunity_assignment_rule) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['sort_by'] = 'date_modified';\n $params['sort_direction'] = 'desc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['sort_by'] = 'date_created';\n $params['sort_direction'] = 'desc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['sort_by'] = 'date_created';\n $params['sort_direction'] = 'asc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['sort_by'] = 'date_modified';\n $params['sort_direction'] = 'desc';\n $params['status_ids'] = [0, 1, 2, 3];\n }\n\n $cpOpportunities = $this->copperClient->opportunities()->search($params);\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n foreach ($cpOpportunities as $cpOpportunity) {\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', (string) $cpOpportunity['pipeline_id'])\n ->first();\n\n if ($businessProcess === null) {\n // Import it.\n $businessProcess = $this->importStages(\n [Stage::TYPE_OPPORTUNITY],\n $cpOpportunity['pipeline_stage_id']\n );\n }\n\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', (string) $cpOpportunity['pipeline_stage_id'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $cpOpportunity['pipeline_stage_id']);\n }\n\n $recordType = $businessProcess->recordTypes()->first();\n\n $record = [\n 'crmId' => $cpOpportunity['id'],\n 'name' => $cpOpportunity['name'],\n 'value' => currency_format($cpOpportunity['monetary_value'], $cpOpportunity['monetary_unit']),\n 'won' => $cpOpportunity['status'] === 'Won',\n 'stage' => [\n 'id' => $stage->id_string,\n 'name' => $stage->name,\n ],\n 'recordType' => [\n 'id' => $recordType->id_string,\n 'name' => $recordType->name,\n ],\n ];\n\n if ($ownerId && isset($cpOpportunity['assignee_id']) && $cpOpportunity['assignee_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = $cpTasks = [];\n\n switch ($objectType) {\n case 'lead':\n $cpTasks = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->relatedTasks($objectId)\n );\n\n break;\n\n case 'account':\n $cpTasks = $this->copperClient->accounts()->relatedTasks($objectId);\n\n break;\n case 'contact':\n if ($opportunityId) {\n $cpTasks = $this->copperClient->opportunities()->relatedTasks($opportunityId);\n } elseif ($objectType === 'contact') {\n $cpTasks = $this->copperClient->contacts()->relatedTasks($objectId);\n }\n\n break;\n }\n\n foreach ($cpTasks as $cpTask) {\n // We only get the ID itself returned, so pull out the full object.\n try {\n $cpTask = $this->copperClient->tasks()->find($cpTask['id']);\n } catch (Exception $exception) {\n $this->logger->error('[Copper] Error fetching task', [\n 'resource_id' => $cpTask['id'],\n 'error' => $exception->getMessage(),\n ]);\n\n continue;\n }\n\n // Only allow open tasks.\n if ($cpTask['status'] === 'Open') {\n $data[] = [\n 'crmId' => $cpTask['id'],\n 'subject' => $cpTask['name'],\n 'due' => $cpTask['due_date']\n ? Carbon::createFromTimestamp($cpTask['due_date'])->format('Y-m-d\\TH:i:sO')\n : null,\n 'type' => null,\n ];\n }\n }\n\n return $data;\n }\n\n /**\n * Try to find email address in CRM service\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $cpObjectType = 'contact';\n\n $cpObjects = $this->copperClient->contacts()->search([\n 'emails' => $email,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (empty($cpObjects)) {\n $cpObjectType = 'lead';\n $cpObjects = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'emails' => $email,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (empty($cpObjects)) {\n return null;\n }\n\n // Search returns an array of results, but we only want the first\n $cpObject = reset($cpObjects);\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n // Check if the user is internal.\n $teamMember = $this->team->users()->where('phone', $phone)->exists();\n\n // Skip the attendee if internal.\n if ($teamMember === false) {\n $cpObjectType = 'contact';\n $cpObject = $this->copperClient->contacts()->search([\n 'phone_number' => $phone,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (\\count($cpObject) === 0) {\n $cpObjectType = 'lead';\n $cpObject = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'phone_number' => $phone,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (empty($cpObject)) {\n return null;\n }\n\n $cpObject = reset($cpObject);\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n return null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $result = \\Cache::remember($this->team->id . $name, 60, function () use ($name, $userId) {\n $cpObjectType = 'contact';\n $cpObject = $this->copperClient->contacts()->search([\n 'name' => $name,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (\\count($cpObject) === 0) {\n $cpObjectType = 'lead';\n $cpObject = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'name' => $name,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (! empty($cpObject)) {\n $cpObject = reset($cpObject);\n }\n\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : false;\n });\n\n return is_array($result) ? $result : null;\n }\n\n private function convertCrmData(array $object, string $objectType, ?int $userId = null): array\n {\n $lead = null;\n $contact = null;\n $opportunity = null;\n $account = null;\n $stage = null;\n $countryCode = null;\n\n if ($objectType === 'lead') {\n $lead = $this->importLead($object);\n\n // Lead might not be imported if the Stage is null for example.\n if ($lead) {\n $countryCode = $lead->country_code;\n $stage = $lead->stage;\n }\n } else {\n $contact = $this->importContact($object);\n $account = $contact->account;\n\n if ($contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account) {\n $countryCode = $account->country_code;\n }\n\n try {\n $cpOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId,\n );\n\n if (! empty($cpOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($cpOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (\\Exception $e) {\n // Nothing to see here.\n }\n }\n\n return [\n $lead,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n public function saveActivity(Activity $activity): Activity\n {\n switch ($activity->type) {\n case Activity::TYPE_CONFERENCE:\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n $activity = $this->buildCallPayload($activity);\n\n break;\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $activity = $this->buildTextMessagePayload($activity);\n\n break;\n }\n\n return $activity;\n }\n\n private function convertActivityAssociations(Activity $activity): array\n {\n if ($activity->lead) {\n $type = 'lead';\n $id = $activity->lead->crm_provider_id;\n } elseif ($activity->contact) {\n $type = 'person';\n $id = $activity->contact->crm_provider_id;\n } elseif ($activity->opportunity) {\n $type = 'opportunity';\n $id = $activity->opportunity->crm_provider_id;\n } else {\n $type = 'company';\n $id = $activity->account->crm_provider_id;\n }\n\n return [\n 'type' => $type,\n 'id' => $id,\n ];\n }\n\n private function convertActivityType(PlaybookCategory $activityType): array\n {\n return [\n 'category' => 'user',\n 'id' => $this->getCrmType($activityType)->value,\n ];\n }\n\n /**\n * @throws CrmException\n */\n private function buildCallPayload(Activity $activity): Activity\n {\n try {\n if ($activity->crm_provider_id) {\n // The activity should be logged under the existing Task (not Activity).\n $newActivityType = $this->getCrmType($activity->category);\n if ($newActivityType === null) {\n $message = sprintf('[Copper] invalid CRM Custom Activity Type: %s', $activity->category);\n\n throw new CrmException($message, 400);\n }\n $this->copperClient->tasks()->update($activity->crm_provider_id, [\n 'status' => 'Completed',\n 'custom_activity_type_id' => $newActivityType->value,\n 'details' => $this->generateActivityDescription($activity),\n ]);\n } else {\n if ($this->getCrmType($activity->category) === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n if ($this->getCrmType($activity->category)->value === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n // Just create an activity.\n $cpActivity = $this->copperClient->activities()->create([\n 'user_id' => $this->profile->crm_provider_id,\n 'activity_date' => $activity->scheduled_start_time->timestamp,\n 'parent' => $this->convertActivityAssociations($activity),\n 'type' => $this->convertActivityType($activity->category),\n 'details' => $this->generateActivityDescription($activity),\n ]);\n\n $activity->crm_provider_id = $cpActivity['id'];\n $activity->save();\n }\n } catch (ClientException $exception) {\n //Log all errors to Sentry\n \\Sentry::captureException($exception);\n\n $response = $exception->getResponse();\n\n $responseBody = $response->getBody();\n $message = $responseBody;\n $errorCode = $response->getStatusCode();\n\n $jsonResponse = json_decode($responseBody, true);\n if (isset($jsonResponse[0]['message'])) {\n $message = $jsonResponse[0]['message'];\n }\n\n throw new CrmException($message, $errorCode);\n }\n\n return $activity;\n }\n\n private function buildTextMessagePayload(Activity $activity): Activity\n {\n if ($this->getCrmType($activity->category) === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n if ($this->getCrmType($activity->category)->value === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n $cpActivity = $this->copperClient->activities()->create([\n 'user_id' => $this->profile->crm_provider_id,\n 'activity_date' => $activity->created_at->timestamp,\n 'parent' => $this->convertActivityAssociations($activity),\n 'type' => $this->convertActivityType($activity->category),\n 'details' => $this->generateActivityDescription($activity),\n ]);\n\n $activity->crm_provider_id = $cpActivity['id'];\n $activity->save();\n\n return $activity;\n }\n\n private function generateActivityDescription(Activity $activity): string\n {\n $description = '';\n\n switch ($activity->type) {\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n case Activity::TYPE_CONFERENCE:\n\n $description = 'Jiminny Call Summary' . PHP_EOL . PHP_EOL;\n $description .= 'Call Duration: ' . $activity->duration_for_humans . PHP_EOL . PHP_EOL;\n\n // Tell them which number was dialed.\n if ($activity->to) {\n $description .= 'Dialed: ' . $activity->to->phone_number . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->hasReasonCodeBotKicked()) {\n $description .= 'Notetaker removed from this meeting' . PHP_EOL . PHP_EOL;\n // When we fix the state to be Activity::RECORDING_RECORDED as it should be this can change.\n } elseif ($activity->hasReasonCodeNotCompliant()) {\n $description .= 'Notetaker did not join due to recording consent not being provided by attendees' . PHP_EOL . PHP_EOL;\n } elseif ($activity->canReviewActivity()) {\n $playbackUrl = $activity->user->team->partner->getPlaybackUrl($activity);\n $description .= 'Review Activity:' . PHP_EOL . $playbackUrl . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->getCrmType() === Activity::TYPE_CONFERENCE) {\n $description .= 'Attendees:'\n . PHP_EOL\n . (new FilterJoinedParticipants())->toString($activity);\n }\n\n if (\\count($activity->notes) > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Notes: ' . PHP_EOL;\n\n foreach ($activity->notes as $note) {\n $nTime = (int) ceil($note->time);\n $time = ($nTime > 3600) ? gmdate('H:i:s', $nTime) : gmdate('i:s', $nTime);\n $description .= $time . ' ' . $note->note . PHP_EOL;\n }\n }\n\n // Get all private messages.\n $messages = $activity->messages()\n ->where('is_private', 1)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Coaching Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n // Get all public messages.\n $messages = $activity->messages()\n ->where('is_private', 0)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Customer Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n if ($activity->summary) {\n $description .= PHP_EOL . PHP_EOL . 'Summary: ' . PHP_EOL . $activity->summary;\n }\n\n break;\n\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $description = $activity->description;\n\n break;\n }\n\n return $description;\n }\n\n public function saveFollowupActivity(Activity $activity, array $fields): ?string\n {\n // This is the user provided activity subject field.\n if (empty($fields['type'])) {\n return null;\n }\n\n $reminder = null;\n if (empty($fields['reminder_date']) === false) {\n $formatReminder = Carbon::createFromFormat('Y-m-d\\TH:i:s\\Z', $fields['reminder_date']);\n $reminder = $formatReminder->getTimestamp();\n }\n\n $due = null;\n if (empty($fields['due_date']) === false) {\n $formatDue = Carbon::createFromFormat('Y-m-d\\TH:i:s\\Z', $fields['due_date']);\n $due = $formatDue->getTimestamp();\n }\n\n $data = [\n 'custom_activity_type_id' => $fields['type'],\n 'status' => 'Open',\n 'assignee_id' => $this->profile->crm_provider_id,\n 'due_date' => $due,\n 'details' => $fields['details'] ?? '',\n 'reminder_date' => $reminder,\n 'name' => $fields['name'] ?? 'Follow-up',\n 'related_resource' => $this->convertActivityAssociations($activity),\n 'custom_fields' => $this->fetchCustomFieldData($activity, Field::OBJECT_TASK),\n ];\n\n // We don't actually create a corresponding activity object on our side yet.\n return $this->copperClient->tasks()->create($data)['id'];\n }\n\n /**\n * Store transcripts as note.\n *\n * @throws \\Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, static::NOTE_BODY_MAX_LENGTH);\n\n $data = [\n 'user_id' => $this->profile->crm_provider_id,\n 'type' => [\n 'category' => 'user',\n 'id' => 0, // This creates a note.\n ],\n 'activity_date' => time(),\n 'details' => $transcripts,\n 'parent' => $this->convertActivityAssociations($activity),\n ];\n\n $cpActivity = $this->copperClient->activities()->create($data);\n\n // Store CRM Activity ID in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $cpActivity['id'];\n $transcription->save();\n }\n\n /**\n * @inheritdoc\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n if ($crmObject instanceof Lead) {\n $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->update($crmObject->crm_provider_id, [\n 'status_id' => $stage->crm_provider_id,\n ])\n );\n } else {\n $this->copperClient->opportunities()->update($crmObject->crm_provider_id, [\n 'pipeline_stage_id' => $stage->crm_provider_id,\n ]);\n }\n }\n\n public function prepareValueForUpdate(array $params): array\n {\n return [$params['fieldName'] => $params['fieldValue']];\n }\n\n /*\n * @inheritdoc\n */\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $preparedData = $data;\n\n if ($objectType === Field::OBJECT_OPPORTUNITY) {\n $preparedData = $this->prepareOpportunityFieldsForUpdate($data);\n }\n\n try {\n $this->copperClient\n ->createResourceFromObjectType($objectType)\n ->update($objectId, $preparedData)\n ;\n } catch (Exception $e) {\n $this->logger->error(self::RESOURCE_UPDATE_FAILED_ERROR_MESSAGE, [\n 'resource_id' => $objectId,\n 'data' => $preparedData,\n 'error' => $e->getMessage(),\n ]);\n\n throw new CrmException(self::RESOURCE_UPDATE_FAILED_ERROR_MESSAGE, $e->getCode(), $e);\n }\n }\n\n /**\n * @param array<string,string> $fieldData\n *\n * @throws CrmException\n *\n * @return array<string,array<int,array<string,bool|float|int|string|null>>|bool|float|int|string|null>\n */\n private function prepareOpportunityFieldsForUpdate(array $fieldData): array\n {\n $preparedData = [];\n $customFields = [];\n\n foreach ($fieldData as $fieldName => $fieldValue) {\n $field = $this->config\n ->fields()\n ->where('crm_provider_id', $fieldName)\n ->first();\n\n if (! $field instanceof Field) {\n throw new CrmException('Field not found');\n }\n\n $convertedValue = $this->fieldValueConverter->convertToCrm($field->getType(), $fieldValue);\n\n if ($this->isStandardField($fieldName)) {\n $preparedData[$fieldName] = $convertedValue;\n\n continue;\n }\n\n $customFields[] = [\n 'custom_field_definition_id' => $fieldName,\n 'value' => $convertedValue,\n ];\n }\n\n if (! empty($customFields)) {\n $preparedData['custom_fields'] = $customFields;\n }\n\n return $preparedData;\n }\n\n /*\n * @inheritdoc\n */\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n return $this->copperClient->createResourceFromObjectType($objectType)->find($objectId);\n }\n\n private function fetchCustomFieldData(Activity $activity, string $objectType): array\n {\n $payload = [];\n\n $fieldData = FieldData::where([\n 'object_id' => $activity->id,\n ])->whereHas('field', function ($query) use ($objectType) {\n $query->where('object_type', $objectType);\n })->get();\n\n foreach ($fieldData as $data) {\n // Add the field and value to the payload.\n $payload += [\n 'custom_field_definition_id' => $data->field->crm_provider_id,\n 'value' => $data->value,\n ];\n }\n\n return $payload;\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $baseUrl = 'https://app.prosperworks.com/companies/' . $this->config->crm_provider_id . '/app#/';\n switch ($objectType) {\n case 'lead':\n $url = $baseUrl . 'leads/' . $providerId;\n\n break;\n\n case 'account':\n $url = $baseUrl . 'organization/' . $providerId;\n\n break;\n\n case 'contact':\n $url = $baseUrl . 'contact/' . $providerId;\n\n break;\n\n case 'opportunity':\n $url = $baseUrl . 'deal/' . $providerId;\n\n break;\n\n default:\n case 'task':\n case 'activity':\n // Sadly we can't deeplink to these in Copper UI.\n $url = null;\n }\n\n return $url;\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! ($this->config->store_transcript)) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n return $this->transcriptionService\n ->findTranscriptionByActivity($activity)\n ->map(static function (array $transcriptionSegment): string {\n return $transcriptionSegment['formattedStartsAt'] . ' | ' . $transcriptionSegment['transcript'];\n })\n ->implode(PHP_EOL);\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n *\n * @return int|string|bool|float|null\n */\n private function extractFieldValue(array $opportunityData, string $fieldName)\n {\n $fieldValue = $this->isStandardField($fieldName)\n ? $opportunityData[$fieldName]\n : $this->resolveCustomFieldFromOpportunityData($opportunityData, $fieldName);\n\n if (is_array($fieldValue)) {\n $fieldValue = implode(', ', $fieldValue);\n }\n\n return $fieldValue;\n }\n\n private function isStandardField(string $fieldName): bool\n {\n return array_key_exists($fieldName, self::STANDARD_OPPORTUNITY_FIELDS);\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n *\n * @return string|int|float|bool|null|array<string, mixed>\n */\n private function resolveCustomFieldFromOpportunityData(array $opportunityData, string $fieldName)\n {\n $fieldData = array_filter(\n $opportunityData['custom_fields'],\n static fn ($field) => (string) $field['custom_field_definition_id'] === $fieldName\n );\n\n return array_pop($fieldData)['value'] ?? '';\n }\n\n private function isSupportedObjectType(string $objectType): bool\n {\n return $objectType !== self::UNSUPPORTED_OBJECT_TYPE;\n }\n\n private function syncStandardFields(): void\n {\n foreach (self::STANDARD_OPPORTUNITY_FIELDS as $fieldId => $fieldData) {\n $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => mb_strimwidth($fieldId, 0, 128),\n 'object_type' => Field::OBJECT_OPPORTUNITY,\n ], [\n 'label' => mb_strimwidth($fieldData['label'], 0, Field::LABEL_MAX_LENGTH),\n 'type' => $fieldData['type'],\n ]);\n }\n\n $this->importStages([Stage::TYPE_OPPORTUNITY]);\n }\n\n private function requestWithExceptionHandling(\\Closure $apiRequest): iterable\n {\n try {\n return $apiRequest();\n } catch (\\Exception $exception) {\n if ($exception->getCode() === 403) {\n // Object might not be supported\n return [];\n }\n\n \\Sentry::captureException($exception);\n\n return [];\n }\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n if ($this->copperClient === null) {\n return false;\n }\n\n $task = $this->copperClient->tasks()->find($crmProviderId);\n\n return ! empty($task);\n } catch (HttpNotFoundException) {\n // Task not found in CRM - this is expected and permanent\n $this->logger->info('[Copper] Task not found during verification', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n } catch (RequestFailedException $e) {\n // Handle 404 responses from Copper API\n if ($e->getCode() === 404) {\n $this->logger->info('[Copper] Task not found during verification (404)', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n\n // Re-throw other Copper exceptions for retry\n throw $e;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\n });\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Crm\\Copper;\n\nuse Carbon\\Carbon;\nuse Exception;\nuse GuzzleHttp\\Exception\\ClientException;\nuse Illuminate\\Support\\Facades\\Cache;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\CopperInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Crm\\LayoutEntity;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Copper\\Api\\Client;\nuse Jiminny\\Services\\Crm\\Copper\\Api\\ClientFactory;\nuse Jiminny\\Services\\Crm\\Copper\\Exception\\RequestFailedException;\nuse Jiminny\\Services\\Crm\\Helpers\\FilterJoinedParticipants;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Services\\Crm\\Copper\\Traits\\SearchesCrmEntities;\nuse Jiminny\\Utils\\CurrencyFormatter;\nuse Jiminny\\Utils\\StringUtil;\n\nclass Service extends BaseService implements\n CopperInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n RemoteEntityManipulationInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n VerifyTaskExistsInterface\n{\n use SearchesCrmEntities;\n private const int NOTE_BODY_MAX_LENGTH = 3000000;\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n private const array STANDARD_OPPORTUNITY_FIELDS = [\n 'monetary_value' => [\n 'label' => 'Value',\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n 'type' => Field::TYPE_CURRENCY,\n ],\n 'pipeline_stage_id' => [\n 'label' => 'Stage',\n 'type' => Field::TYPE_PICKLIST,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n 'close_date' => [\n 'label' => 'Close date',\n 'type' => Field::TYPE_DATE,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n 'win_probability' => [\n 'label' => 'Win probability',\n 'type' => Field::TYPE_NUMBER,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n ];\n private const string UNSUPPORTED_OBJECT_TYPE = 'unsupported';\n private const string OPPORTUNITY_STATUS_OPEN = 'Open';\n private const string OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE = 'Opportunity import failed';\n private const string RESOURCE_UPDATE_FAILED_ERROR_MESSAGE = 'Failed to update resource';\n\n private FieldValueConverter $fieldValueConverter;\n private ClientFactory $clientFactory;\n private ?Client $copperClient = null;\n\n public function __construct(\n ClientFactory $clientFactory,\n FieldValueConverter $fieldValueConverter,\n private readonly UserRepository $userRepository,\n private readonly ProspectPhotoPathService $prospectPhotoPathService,\n private readonly CrmEntityRepository $crmEntityRepository\n ) {\n parent::__construct();\n\n $this->clientFactory = $clientFactory;\n $this->fieldValueConverter = $fieldValueConverter;\n }\n\n public function getDisplayName(): string\n {\n return 'Copper';\n }\n\n /**\n * Get the CRM entity repository (used by SearchesCrmEntities trait)\n */\n protected function getCrmEntityRepository(): CrmEntityRepository\n {\n return $this->crmEntityRepository;\n }\n\n public function getMinimumApiVersion(): string\n {\n return Client::MIN_API_VERSION;\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n $owner = $user->team->owner;\n\n return $owner->getSocialAccount(SocialAccount::PROVIDER_COPPER);\n }\n\n public function setUser(User $user): void\n {\n $this->configureSentryScope($user);\n\n $this->team = $user->getTeam();\n $this->teamService->setTeam($user->getTeam());\n $this->setConfiguration($user->getTeam()->getCrmConfiguration());\n\n // Reset state.\n $this->profile = $user->getProfile();\n\n if (! $this->profile instanceof Profile) {\n // Try to fetch their profile, maybe it was not yet imported?\n $this->profile = $this->getProfile($user);\n }\n }\n\n public function setConfiguration(Configuration $configuration): void\n {\n $this->config = $configuration;\n $this->copperClient = $this->clientFactory->create($configuration);\n\n if ($this->team === null) {\n $this->team = $configuration->getTeam();\n }\n }\n\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);\n }\n\n private function mapObjectType(string $objectType): string\n {\n $objectType = strtolower($objectType);\n\n switch ($objectType) {\n case Field::OBJECT_TASK:\n case Field::OBJECT_OPPORTUNITY:\n case Field::OBJECT_LEAD:\n $mappedType = $objectType;\n\n break;\n case Field::OBJECT_ACCOUNT:\n $mappedType = 'company';\n\n break;\n case Field::OBJECT_CONTACT:\n $mappedType = 'person';\n\n break;\n default:\n $mappedType = self::UNSUPPORTED_OBJECT_TYPE;\n\n break;\n }\n\n return $mappedType;\n }\n\n /**\n * @param string $crmObject The name of the CRM object. i.e. Opportunity or Contact\n */\n protected function getFields(string $crmObject): array\n {\n $mappedObjectType = $this->mapObjectType($crmObject);\n\n if (! $this->isSupportedObjectType($mappedObjectType)) {\n return [];\n }\n\n $customFields = $this->copperClient->fields()->all();\n\n $filteredFields = array_filter(\n $customFields,\n static fn ($field) => in_array($mappedObjectType, $field['available_on'], true)\n );\n\n return array_map(\n fn (array $property) => [\n 'name' => $property['id'],\n 'label' => $property['name'],\n 'type' => $this->convertFieldType($property['data_type']),\n ],\n $filteredFields\n );\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n // Setup the activity field as the default Type.\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'type',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n $fieldFilters = FieldDefinitions::taskFollowupFieldsFilter();\n\n foreach ($fieldFilters as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n public function syncFields(): void\n {\n $this->syncStandardFields();\n $this->syncCustomFields();\n }\n\n public function syncField(Field $field): void\n {\n if ($field->getCrmProviderId() === 'type') {\n /**\n * This field is a special case, it is not a custom field and is not returned by the Copper API.\n *\n * The field is created manually during layout setup.\n *\n * @see getDefaultFields()\n *\n * There is a separate endpoint to get the activity types.\n * @see importPicklistValues()\n */\n return;\n }\n\n if ($field->getCrmProviderId() === 'pipeline_stage_id') {\n // Not a custom type\n return;\n }\n\n $crmField = $this->copperClient->fields()->find($field->getCrmProviderId());\n $field->label = $crmField['name'];\n $field->type = $this->convertFieldType($crmField['data_type']);\n\n $field->save();\n }\n\n /**\n * @param string $fieldType How the data should be input\n */\n private function convertFieldType(string $fieldType): string\n {\n $fieldType = strtolower($fieldType);\n\n switch ($fieldType) {\n case 'dropdown':\n $convertedType = Field::TYPE_PICKLIST;\n\n break;\n case 'string':\n $convertedType = Field::TYPE_TEXT;\n\n break;\n case 'float':\n case 'percentage':\n $convertedType = Field::TYPE_NUMBER;\n\n break;\n case 'text':\n $convertedType = Field::TYPE_TEXTAREA;\n\n break;\n case 'checkbox':\n $convertedType = Field::TYPE_BOOLEAN;\n\n break;\n case Field::TYPE_DATE:\n case Field::TYPE_CURRENCY:\n case Field::TYPE_URL:\n $convertedType = $fieldType;\n\n break;\n default:\n $convertedType = Field::TYPE_UNSUPPORTED;\n\n break;\n }\n\n return $convertedType;\n }\n\n /**\n * @inheritdoc\n */\n public function importPicklistValues(Field $field): array\n {\n $fieldValues = [];\n\n if ($field->object_type === 'opportunity' && $field->crm_provider_id === 'pipeline_stage_id') {\n return $this->importFieldValuesForDealInsights($field);\n }\n\n $values = [];\n\n if ($field->object_type === Field::OBJECT_TASK && $field->crm_provider_id === 'type') {\n $activityTypes = $this->copperClient->activityTypes()->all();\n\n /**\n * We ignore \"system\" activity types, disabled activity types and the \"Note\" activity type.\n */\n $activityTypes = array_filter(\n $activityTypes['user'],\n fn (array $activityType) => ! $activityType['is_disabled'] && $activityType['id'] !== 0\n );\n\n // Import all activity values.\n $i = 0;\n foreach ($activityTypes as $activityType) {\n $values[] = [\n 'value' => $activityType['id'],\n 'label' => mb_strimwidth($activityType['name'], 0, Field::LABEL_MAX_LENGTH),\n 'sequence' => $i++,\n ];\n }\n } else {\n // We just check for the field in the custom definitions.\n $crmField = $this->copperClient->fields()->find($field->crm_provider_id);\n\n // Import all values.\n foreach ($crmField['options'] as $option) {\n $values[] = [\n 'value' => $option['id'],\n 'label' => mb_strimwidth($option['name'], 0, 191),\n 'sequence' => $option['rank'],\n ];\n }\n }\n\n // Take the existing set of field values.\n $fieldsToPurge = $field->values()->get()->pluck('value')->toArray();\n\n foreach ($values as $value) {\n // For all current values, upsert the field.\n $value['value'] = substr($value['value'] ?? '', 0, 255);\n $fieldValues[] = $field->values()->updateOrCreate([\n 'value' => $value['value'],\n ], $value);\n\n // Remove this value from the ones we are going to purge.\n $key = array_search($value['value'], $fieldsToPurge, false);\n if ($key !== false) {\n unset($fieldsToPurge[$key]);\n }\n }\n\n // Delete the old values that are no longer used.\n $field->values()->whereIn('value', $fieldsToPurge)->delete();\n\n return $fieldValues;\n }\n\n /**\n *\n * @return FieldValue[]\n */\n private function importFieldValuesForDealInsights(Field $field): array\n {\n $fieldValues = [];\n $pipelines = $this->copperClient->pipelines()->all();\n\n foreach ($pipelines as $pipeline) {\n foreach ($pipeline['stages'] as $i => $dealStage) {\n $fieldValues[] = $field->values()->updateOrCreate(\n ['value' => $dealStage['id']],\n [\n 'label' => $dealStage['name'],\n 'sequence' => $i,\n ]\n );\n }\n }\n\n return $fieldValues;\n }\n\n /**\n * @inheritdoc\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n if ($types === null) {\n $types = [Stage::TYPE_LEAD, Stage::TYPE_OPPORTUNITY];\n }\n $missingStage = null;\n\n foreach ($types as $type) {\n if ($type === Stage::TYPE_LEAD) {\n $statuses = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leadStatuses()->all()\n );\n\n if (count($statuses) > 0) {\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => BusinessProcess::TYPE_LEAD,\n ], [\n 'team_id' => $this->team->id,\n 'name' => BusinessProcess::TYPE_LEAD,\n 'type' => BusinessProcess::TYPE_LEAD,\n 'is_selectable' => true,\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => BusinessProcess::TYPE_LEAD,\n ], [\n 'team_id' => $this->team->id,\n 'name' => BusinessProcess::TYPE_LEAD,\n 'is_selectable' => true,\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n $leadStatuses = [];\n foreach ($statuses as $status) {\n // Upsert all statuses for the team.\n $status = $this->config->stages()->updateOrCreate([\n 'crm_provider_id' => $status['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($status['name'], 0, 50),\n 'label' => mb_strimwidth($status['name'], 0, 191),\n 'type' => Stage::TYPE_LEAD,\n 'sequence' => $status['order'],\n 'is_selectable' => true,\n ]);\n\n if ($missingStageName && $missingStageName === $status['id']) {\n $missingStage = $status;\n }\n\n $leadStatuses[] = $status['id'];\n }\n\n $businessProcess->stages()->sync($leadStatuses);\n }\n } else {\n // We create a business process to contain the pipeline, and later store all stages against it.\n foreach ($this->copperClient->pipelines()->all() as $pipeline) {\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => $pipeline['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($pipeline['name'], 0, 150),\n 'type' => BusinessProcess::TYPE_OPPORTUNITY,\n 'is_selectable' => true,\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => $pipeline['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($pipeline['name'], 0, 150),\n 'is_selectable' => true,\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n $stages = [];\n\n foreach ($pipeline['stages'] as $i => $dealStage) {\n // Upsert all stages for the team.\n $stage = $this->config->stages()->updateOrCreate([\n 'crm_provider_id' => $dealStage['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($dealStage['name'], 0, 50),\n 'label' => mb_strimwidth($dealStage['name'], 0, 191),\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'sequence' => $i,\n 'is_selectable' => true,\n 'probability' => $dealStage['win_probability'],\n ]);\n\n if ($missingStageName && $missingStageName === $dealStage['id']) {\n $missingStage = $stage;\n }\n\n $stages[] = $stage['id'];\n }\n\n $businessProcess->stages()->sync($stages);\n }\n }\n }\n\n return $missingStage;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int\n {\n $syncCount = 0;\n\n $cpLeads = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->paginate([\n 'minimum_modified_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ])\n );\n\n foreach ($cpLeads as $cpLead) {\n // Only sync if previously imported.\n if ($this->hasLead($cpLead['id']) === false) {\n $this->importLead($cpLead);\n $syncCount++;\n }\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLead(string $crmId): ?Lead\n {\n $cpLead = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->find($crmId)\n );\n\n if (\\count($cpLead) === 0) {\n return null;\n }\n\n return $this->importLead($cpLead);\n }\n\n /**\n * @inheritdoc\n */\n private function importLead($crmData): ?Lead\n {\n $countryCode = null;\n if (! empty($crmData['address']) && isset($crmData['address']['country'])) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $mobilePhone = $parsedNumber = null;\n if (! empty($crmData['phone_numbers'])) {\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n if ($phoneNumber['category'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);\n } else {\n $parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);\n }\n }\n }\n\n $name = $crmData['name'];\n\n if (empty($crmData['company_name'])) {\n $company = 'Unknown';\n } else {\n $company = mb_strimwidth($crmData['company_name'], 0, 191);\n }\n\n $domain = null;\n if (empty($crmData['websites']) === false) {\n $domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);\n $domain = StringUtil::resolveDomain($domain);\n }\n\n $email = null;\n if (empty($crmData['email']) === false) {\n $email = mb_strimwidth($crmData['email']['email'], 0, 80);\n }\n\n $stage = $this->config\n ->stages()\n ->where('crm_provider_id', (string) $crmData['status_id'])\n ->where('type', Stage::TYPE_LEAD)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_LEAD], $crmData['status_id']);\n }\n\n if (! $stage instanceof Stage) {\n return null;\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($name, 0, 191),\n 'company' => $company,\n 'domain' => $domain,\n 'title' => $crmData['title'] ? mb_strimwidth($crmData['title'], 0, 128) : null,\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'mobile_phone' => $mobilePhone,\n 'stage_id' => $stage->id,\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Lead::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'country_code' => $countryCode,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->leads()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n /**\n * @inheritdoc\n */\n public function syncAccounts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n $cpAccounts = $this->copperClient->accounts()->paginate([\n 'minimum_modified_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ]);\n\n foreach ($cpAccounts as $cpAccount) {\n // Only sync if previously imported.\n if ($this->hasAccount($cpAccount['id'])) {\n $this->importAccount($cpAccount);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncAccount(string $crmId): ?Account\n {\n $cpAccount = $this->copperClient->accounts()->find($crmId);\n\n if (empty($cpAccount)) {\n return null;\n }\n\n return $this->importAccount($cpAccount);\n }\n\n /**\n * @inheritdoc\n */\n private function importAccount($crmData): Account\n {\n $countryCode = null;\n if (empty($crmData['address']) === false && $crmData['address']['country']) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $name = $crmData['name'];\n\n $parsedNumber = null;\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n $parsedNumber = parsePhoneNumber($countryCode, $phoneNumber['number']);\n }\n\n $domain = null;\n if (empty($crmData['websites']) === false) {\n $domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);\n $domain = StringUtil::resolveDomain($domain);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($name, 0, 191),\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Account::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'country_code' => $countryCode,\n 'domain' => $domain,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->accounts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n public function syncOpportunities(array $parameters, ?string $strategy = null): int\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->copperClient,\n ]);\n $strategies = $strategyResolver->getStrategies($this->config, $strategy);\n\n $syncCount = 0;\n\n try {\n foreach ($strategies as $syncStrategy) {\n foreach ($syncStrategy->fetchOpportunities($parameters) as $opportunityData) {\n $this->importOpportunity($opportunityData);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n $this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => $exception->getMessage(),\n ]);\n }\n\n return $syncCount;\n }\n\n public function syncOpportunity(string $crmId): ?Opportunity\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->copperClient,\n ]);\n $strategy = $strategyResolver->resolve(\n $this->config,\n OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY\n );\n\n $parameters['crm_id'] = $crmId;\n\n $cpOpportunity = $strategy->fetchOpportunities($parameters);\n\n return $this->importOpportunity($cpOpportunity);\n }\n\n private function importOpportunity($crmData): ?Opportunity\n {\n $companyId = (string) $crmData['company_id'];\n\n if (empty($companyId)) {\n $this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => 'No company id',\n ]);\n\n return null;\n }\n\n $account = $this->config->accounts()->where('crm_provider_id', $companyId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($companyId);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', (string) $crmData['pipeline_id'])\n ->first();\n\n if ($businessProcess === null) {\n // It is possible for some deals to not be in a pipeline.\n $this->logger->warning(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => 'Missing pipeline',\n ]);\n\n return null;\n }\n\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', (string) $crmData['pipeline_stage_id'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n $this->logger->info('Stage not found, importing', [\n 'pipeline_id' => $crmData['pipeline_id'],\n 'stage_id' => $crmData['pipeline_stage_id'],\n ]);\n\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData['pipeline_stage_id']);\n }\n\n $recordType = $businessProcess->recordTypes()->first();\n $closeDate = null;\n $isClosed = $crmData['status'] !== self::OPPORTUNITY_STATUS_OPEN;\n\n if ($crmData['close_date']) {\n $closeDate = Carbon::parse($crmData['close_date'])->format('Y-m-d');\n }\n\n $data = [\n 'team_id' => $this->team->getId(),\n 'account_id' => $account->id,\n 'user_id' => $profile->user_id ?? null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($crmData['name'], 0, 128),\n 'value' => $crmData['monetary_value'],\n 'currency_code' => CurrencyFormatter::formatCode($crmData['monetary_unit']),\n 'close_date' => $closeDate,\n 'is_closed' => $isClosed,\n 'is_won' => $crmData['status'] === 'Won',\n 'stage_id' => $stage->id,\n 'record_type_id' => $recordType->id ?? null,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n /** @var Opportunity $opportunity */\n $opportunity = $this->config\n ->opportunities()\n ->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data)\n ;\n\n // import external fields into crm_field_data if present\n $dealInsightsFields = $this->getOpportunitySyncableFields();\n $this->importOpportunityCrmFieldData($crmData, $dealInsightsFields, $opportunity->id);\n\n return $opportunity;\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n * @param string[] $dealInsightsFields\n */\n public function importOpportunityCrmFieldData(\n array $opportunityData,\n array $dealInsightsFields,\n int $opportunityId\n ): void {\n foreach ($dealInsightsFields as $fieldName) {\n $field = $this->config->fields()->with('entities')\n ->where('crm_provider_id', $fieldName)\n ->where('object_type', Field::OBJECT_OPPORTUNITY)\n ->first();\n\n if (! $field instanceof Field) {\n $this->logger->warning('Field not found', [\n 'field' => $fieldName,\n 'opportunity_id' => $opportunityId,\n ]);\n\n continue;\n }\n\n $entity = $field->getEntities()->first();\n\n if (! $entity instanceof LayoutEntity) {\n continue;\n }\n\n $fieldValue = $this->extractFieldValue($opportunityData, $fieldName);\n $normalizedValue = $this->normalizeValue($field->getType(), (string) $fieldValue, true);\n\n $field->data()\n ->updateOrCreate([\n 'crm_layout_entity_id' => $entity->id,\n 'crm_field_id' => $field->id,\n 'object_type' => 'opportunity',\n 'object_id' => $opportunityId,\n ], ['value' => $normalizedValue])\n ;\n }\n }\n\n /**\n * @inheritdoc\n */\n public function syncContacts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n $cpContacts = $this->copperClient->contacts()->paginate([\n 'minimum_interaction_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ]);\n\n foreach ($cpContacts as $cpContact) {\n // Only sync if previously imported.\n if ($this->hasContact($cpContact['id'])) {\n $this->importContact($cpContact);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n throw $exception;\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncContact(string $crmId): ?Contact\n {\n $cpContact = $this->copperClient->contacts()->find($crmId);\n\n if (empty($cpContact)) {\n return null;\n }\n\n return $this->importContact($cpContact);\n }\n\n /**\n * @inheritdoc\n */\n private function importContact($crmData): Contact\n {\n $account = null;\n if ($crmData['company_id']) {\n $account = $this->team\n ->crm\n ->accounts()\n ->where('crm_provider_id', (string) $crmData['company_id'])\n ->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmData['company_id']);\n }\n }\n\n $countryCode = null;\n if (empty($crmData['address']) === false && $crmData['address']['country']) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $mobilePhone = $parsedNumber = null;\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n if ($phoneNumber['category'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);\n } else {\n $parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);\n }\n }\n\n $email = null;\n if (empty($crmData['emails']) === false) {\n $email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'account_id' => $account->id ?? null,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => $crmData['name'],\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'mobile_phone' => $mobilePhone ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'title' => $crmData['title'],\n 'country_code' => $countryCode,\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Contact::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n private function buildContactPhone(?string $countryCode, ?string $number): ?array\n {\n if ($number) {\n // Trim to our width and attempt to parse it.\n $number = mb_strimwidth($number, 0, 25);\n $parsedNumber = parsePhoneNumber($countryCode, $number);\n } else {\n $parsedNumber = [];\n }\n\n return $parsedNumber;\n }\n\n private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string\n {\n return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;\n }\n\n /**\n * @inheritdoc\n */\n public function syncOrganization(): void\n {\n $organization = $this->copperClient->organisation()->all();\n\n if ($this->config->crm_provider_id !== $organization['id']) {\n $this->config->update(['crm_provider_id' => $organization['id']]);\n }\n }\n\n private function syncCustomFields(): void\n {\n foreach ($this->getFieldTypes() as $fieldType) {\n $currentFields = $this->getFields($fieldType);\n\n foreach ($currentFields as $field) {\n /** @var Field $field */\n $field = $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => $field['name'],\n 'object_type' => $fieldType,\n ], [\n 'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),\n 'type' => $field['type'],\n ]);\n\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n }\n\n $this->config->save();\n }\n\n protected function getFieldTypes(): array\n {\n return [\n parent::OBJECT_TASK,\n parent::OBJECT_LEAD,\n parent::OBJECT_ACCOUNT,\n parent::OBJECT_CONTACT,\n parent::OBJECT_OPPORTUNITY,\n ];\n }\n\n /**\n * @inheritdoc\n */\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n $profiles = $this->copperClient->users()->all();\n\n foreach ($profiles as $profile) {\n $user = $this->userRepository->findByTeamAndEmailAddress($this->team, $profile['email'], onlyActive: true);\n\n // Only import profiles for users we have locally.\n if ($user) {\n $profile = $user->crmProfile()->updateOrCreate([\n 'crm_configuration_id' => $this->config->id,\n 'crm_provider_id' => $profile['id'],\n ]);\n\n if ($userToSearch && $userToSearch->id === $user->id) {\n return $profile;\n }\n }\n }\n\n return null;\n }\n\n /**\n * @inheritdoc\n */\n public function syncProfileFields(): void\n {\n $fieldTypes = [\n 'task',\n 'lead',\n 'account',\n 'contact',\n 'opportunity',\n ];\n\n foreach ($fieldTypes as $fieldType) {\n try {\n $currentFields = $this->getFields(ucfirst($fieldType));\n\n $newFields = array_column($currentFields, 'name');\n $changedFields = array_merge(\n array_diff($this->profile->getFieldsAsArray($fieldType), $newFields),\n array_diff($newFields, $this->profile->getFieldsAsArray($fieldType))\n );\n\n if (\\count($changedFields) > 0) {\n $fields = implode(',', $newFields);\n $this->logger->debug(\n ucfirst($fieldType)\n . ' fields changed from '\n . $this->profile->{$fieldType . '_fields'}\n . ' to: '\n . $fields\n );\n\n $this->profile->{$fieldType . '_fields'} = $fields;\n }\n } catch (\\Exception $exception) {\n $this->logger->error('No access to ' . $fieldType . ' object, skipping...');\n\n continue;\n }\n }\n\n $this->profile->save();\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n $scopeValues = array_map(fn ($scope) => is_string($scope) ? $scope : $scope->value, $scopes);\n $cacheKey = sprintf('copper-search-%d-%s-%s-%d-%d', $this->team->id, $name, implode('-', $scopeValues), $count, $offset);\n\n return Cache::remember($cacheKey, 300, function () use ($name, $scopes, $count, $offset) {\n // Try local search first\n $localResults = $this->searchLocally($name, $scopes, $count, $offset);\n\n // If no local results, fall back to remote API search\n if (empty($localResults)) {\n return $this->searchRemotely($name, $scopes, $count, $offset);\n }\n\n return $localResults;\n });\n }\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n $contact = null;\n $account = null;\n\n if ($crmAccountId) {\n $account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmAccountId);\n }\n }\n\n if ($crmContactId) {\n $contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();\n\n if ($contact === null) {\n $contact = $this->syncContact($crmContactId);\n }\n }\n\n if ($contact || $account) {\n if ($contact && $account === null) {\n $account = $contact->account;\n }\n\n if ($account === null) {\n return [];\n }\n\n $params = [\n 'company_ids' => [$account->crm_provider_id],\n 'status_ids' => [0], // The integer values are 0, 1, 2, 3, for \"Open\", \"Won\", \"Lost\", and \"Abandoned\".\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ];\n\n switch ($this->config->opportunity_assignment_rule) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['sort_by'] = 'date_modified';\n $params['sort_direction'] = 'desc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['sort_by'] = 'date_created';\n $params['sort_direction'] = 'desc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['sort_by'] = 'date_created';\n $params['sort_direction'] = 'asc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['sort_by'] = 'date_modified';\n $params['sort_direction'] = 'desc';\n $params['status_ids'] = [0, 1, 2, 3];\n }\n\n $cpOpportunities = $this->copperClient->opportunities()->search($params);\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n foreach ($cpOpportunities as $cpOpportunity) {\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', (string) $cpOpportunity['pipeline_id'])\n ->first();\n\n if ($businessProcess === null) {\n // Import it.\n $businessProcess = $this->importStages(\n [Stage::TYPE_OPPORTUNITY],\n $cpOpportunity['pipeline_stage_id']\n );\n }\n\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', (string) $cpOpportunity['pipeline_stage_id'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $cpOpportunity['pipeline_stage_id']);\n }\n\n $recordType = $businessProcess->recordTypes()->first();\n\n $record = [\n 'crmId' => $cpOpportunity['id'],\n 'name' => $cpOpportunity['name'],\n 'value' => currency_format($cpOpportunity['monetary_value'], $cpOpportunity['monetary_unit']),\n 'won' => $cpOpportunity['status'] === 'Won',\n 'stage' => [\n 'id' => $stage->id_string,\n 'name' => $stage->name,\n ],\n 'recordType' => [\n 'id' => $recordType->id_string,\n 'name' => $recordType->name,\n ],\n ];\n\n if ($ownerId && isset($cpOpportunity['assignee_id']) && $cpOpportunity['assignee_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = $cpTasks = [];\n\n switch ($objectType) {\n case 'lead':\n $cpTasks = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->relatedTasks($objectId)\n );\n\n break;\n\n case 'account':\n $cpTasks = $this->copperClient->accounts()->relatedTasks($objectId);\n\n break;\n case 'contact':\n if ($opportunityId) {\n $cpTasks = $this->copperClient->opportunities()->relatedTasks($opportunityId);\n } elseif ($objectType === 'contact') {\n $cpTasks = $this->copperClient->contacts()->relatedTasks($objectId);\n }\n\n break;\n }\n\n foreach ($cpTasks as $cpTask) {\n // We only get the ID itself returned, so pull out the full object.\n try {\n $cpTask = $this->copperClient->tasks()->find($cpTask['id']);\n } catch (Exception $exception) {\n $this->logger->error('[Copper] Error fetching task', [\n 'resource_id' => $cpTask['id'],\n 'error' => $exception->getMessage(),\n ]);\n\n continue;\n }\n\n // Only allow open tasks.\n if ($cpTask['status'] === 'Open') {\n $data[] = [\n 'crmId' => $cpTask['id'],\n 'subject' => $cpTask['name'],\n 'due' => $cpTask['due_date']\n ? Carbon::createFromTimestamp($cpTask['due_date'])->format('Y-m-d\\TH:i:sO')\n : null,\n 'type' => null,\n ];\n }\n }\n\n return $data;\n }\n\n /**\n * Try to find email address in CRM service\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $cpObjectType = 'contact';\n\n $cpObjects = $this->copperClient->contacts()->search([\n 'emails' => $email,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (empty($cpObjects)) {\n $cpObjectType = 'lead';\n $cpObjects = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'emails' => $email,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (empty($cpObjects)) {\n return null;\n }\n\n // Search returns an array of results, but we only want the first\n $cpObject = reset($cpObjects);\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n // Check if the user is internal.\n $teamMember = $this->team->users()->where('phone', $phone)->exists();\n\n // Skip the attendee if internal.\n if ($teamMember === false) {\n $cpObjectType = 'contact';\n $cpObject = $this->copperClient->contacts()->search([\n 'phone_number' => $phone,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (\\count($cpObject) === 0) {\n $cpObjectType = 'lead';\n $cpObject = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'phone_number' => $phone,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (empty($cpObject)) {\n return null;\n }\n\n $cpObject = reset($cpObject);\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n return null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $result = \\Cache::remember($this->team->id . $name, 60, function () use ($name, $userId) {\n $cpObjectType = 'contact';\n $cpObject = $this->copperClient->contacts()->search([\n 'name' => $name,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (\\count($cpObject) === 0) {\n $cpObjectType = 'lead';\n $cpObject = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'name' => $name,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (! empty($cpObject)) {\n $cpObject = reset($cpObject);\n }\n\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : false;\n });\n\n return is_array($result) ? $result : null;\n }\n\n private function convertCrmData(array $object, string $objectType, ?int $userId = null): array\n {\n $lead = null;\n $contact = null;\n $opportunity = null;\n $account = null;\n $stage = null;\n $countryCode = null;\n\n if ($objectType === 'lead') {\n $lead = $this->importLead($object);\n\n // Lead might not be imported if the Stage is null for example.\n if ($lead) {\n $countryCode = $lead->country_code;\n $stage = $lead->stage;\n }\n } else {\n $contact = $this->importContact($object);\n $account = $contact->account;\n\n if ($contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account) {\n $countryCode = $account->country_code;\n }\n\n try {\n $cpOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId,\n );\n\n if (! empty($cpOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($cpOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (\\Exception $e) {\n // Nothing to see here.\n }\n }\n\n return [\n $lead,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n public function saveActivity(Activity $activity): Activity\n {\n switch ($activity->type) {\n case Activity::TYPE_CONFERENCE:\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n $activity = $this->buildCallPayload($activity);\n\n break;\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $activity = $this->buildTextMessagePayload($activity);\n\n break;\n }\n\n return $activity;\n }\n\n private function convertActivityAssociations(Activity $activity): array\n {\n if ($activity->lead) {\n $type = 'lead';\n $id = $activity->lead->crm_provider_id;\n } elseif ($activity->contact) {\n $type = 'person';\n $id = $activity->contact->crm_provider_id;\n } elseif ($activity->opportunity) {\n $type = 'opportunity';\n $id = $activity->opportunity->crm_provider_id;\n } else {\n $type = 'company';\n $id = $activity->account->crm_provider_id;\n }\n\n return [\n 'type' => $type,\n 'id' => $id,\n ];\n }\n\n private function convertActivityType(PlaybookCategory $activityType): array\n {\n return [\n 'category' => 'user',\n 'id' => $this->getCrmType($activityType)->value,\n ];\n }\n\n /**\n * @throws CrmException\n */\n private function buildCallPayload(Activity $activity): Activity\n {\n try {\n if ($activity->crm_provider_id) {\n // The activity should be logged under the existing Task (not Activity).\n $newActivityType = $this->getCrmType($activity->category);\n if ($newActivityType === null) {\n $message = sprintf('[Copper] invalid CRM Custom Activity Type: %s', $activity->category);\n\n throw new CrmException($message, 400);\n }\n $this->copperClient->tasks()->update($activity->crm_provider_id, [\n 'status' => 'Completed',\n 'custom_activity_type_id' => $newActivityType->value,\n 'details' => $this->generateActivityDescription($activity),\n ]);\n } else {\n if ($this->getCrmType($activity->category) === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n if ($this->getCrmType($activity->category)->value === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n // Just create an activity.\n $cpActivity = $this->copperClient->activities()->create([\n 'user_id' => $this->profile->crm_provider_id,\n 'activity_date' => $activity->scheduled_start_time->timestamp,\n 'parent' => $this->convertActivityAssociations($activity),\n 'type' => $this->convertActivityType($activity->category),\n 'details' => $this->generateActivityDescription($activity),\n ]);\n\n $activity->crm_provider_id = $cpActivity['id'];\n $activity->save();\n }\n } catch (ClientException $exception) {\n //Log all errors to Sentry\n \\Sentry::captureException($exception);\n\n $response = $exception->getResponse();\n\n $responseBody = $response->getBody();\n $message = $responseBody;\n $errorCode = $response->getStatusCode();\n\n $jsonResponse = json_decode($responseBody, true);\n if (isset($jsonResponse[0]['message'])) {\n $message = $jsonResponse[0]['message'];\n }\n\n throw new CrmException($message, $errorCode);\n }\n\n return $activity;\n }\n\n private function buildTextMessagePayload(Activity $activity): Activity\n {\n if ($this->getCrmType($activity->category) === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n if ($this->getCrmType($activity->category)->value === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n $cpActivity = $this->copperClient->activities()->create([\n 'user_id' => $this->profile->crm_provider_id,\n 'activity_date' => $activity->created_at->timestamp,\n 'parent' => $this->convertActivityAssociations($activity),\n 'type' => $this->convertActivityType($activity->category),\n 'details' => $this->generateActivityDescription($activity),\n ]);\n\n $activity->crm_provider_id = $cpActivity['id'];\n $activity->save();\n\n return $activity;\n }\n\n private function generateActivityDescription(Activity $activity): string\n {\n $description = '';\n\n switch ($activity->type) {\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n case Activity::TYPE_CONFERENCE:\n\n $description = 'Jiminny Call Summary' . PHP_EOL . PHP_EOL;\n $description .= 'Call Duration: ' . $activity->duration_for_humans . PHP_EOL . PHP_EOL;\n\n // Tell them which number was dialed.\n if ($activity->to) {\n $description .= 'Dialed: ' . $activity->to->phone_number . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->hasReasonCodeBotKicked()) {\n $description .= 'Notetaker removed from this meeting' . PHP_EOL . PHP_EOL;\n // When we fix the state to be Activity::RECORDING_RECORDED as it should be this can change.\n } elseif ($activity->hasReasonCodeNotCompliant()) {\n $description .= 'Notetaker did not join due to recording consent not being provided by attendees' . PHP_EOL . PHP_EOL;\n } elseif ($activity->canReviewActivity()) {\n $playbackUrl = $activity->user->team->partner->getPlaybackUrl($activity);\n $description .= 'Review Activity:' . PHP_EOL . $playbackUrl . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->getCrmType() === Activity::TYPE_CONFERENCE) {\n $description .= 'Attendees:'\n . PHP_EOL\n . (new FilterJoinedParticipants())->toString($activity);\n }\n\n if (\\count($activity->notes) > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Notes: ' . PHP_EOL;\n\n foreach ($activity->notes as $note) {\n $nTime = (int) ceil($note->time);\n $time = ($nTime > 3600) ? gmdate('H:i:s', $nTime) : gmdate('i:s', $nTime);\n $description .= $time . ' ' . $note->note . PHP_EOL;\n }\n }\n\n // Get all private messages.\n $messages = $activity->messages()\n ->where('is_private', 1)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Coaching Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n // Get all public messages.\n $messages = $activity->messages()\n ->where('is_private', 0)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Customer Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n if ($activity->summary) {\n $description .= PHP_EOL . PHP_EOL . 'Summary: ' . PHP_EOL . $activity->summary;\n }\n\n break;\n\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $description = $activity->description;\n\n break;\n }\n\n return $description;\n }\n\n public function saveFollowupActivity(Activity $activity, array $fields): ?string\n {\n // This is the user provided activity subject field.\n if (empty($fields['type'])) {\n return null;\n }\n\n $reminder = null;\n if (empty($fields['reminder_date']) === false) {\n $formatReminder = Carbon::createFromFormat('Y-m-d\\TH:i:s\\Z', $fields['reminder_date']);\n $reminder = $formatReminder->getTimestamp();\n }\n\n $due = null;\n if (empty($fields['due_date']) === false) {\n $formatDue = Carbon::createFromFormat('Y-m-d\\TH:i:s\\Z', $fields['due_date']);\n $due = $formatDue->getTimestamp();\n }\n\n $data = [\n 'custom_activity_type_id' => $fields['type'],\n 'status' => 'Open',\n 'assignee_id' => $this->profile->crm_provider_id,\n 'due_date' => $due,\n 'details' => $fields['details'] ?? '',\n 'reminder_date' => $reminder,\n 'name' => $fields['name'] ?? 'Follow-up',\n 'related_resource' => $this->convertActivityAssociations($activity),\n 'custom_fields' => $this->fetchCustomFieldData($activity, Field::OBJECT_TASK),\n ];\n\n // We don't actually create a corresponding activity object on our side yet.\n return $this->copperClient->tasks()->create($data)['id'];\n }\n\n /**\n * Store transcripts as note.\n *\n * @throws \\Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, static::NOTE_BODY_MAX_LENGTH);\n\n $data = [\n 'user_id' => $this->profile->crm_provider_id,\n 'type' => [\n 'category' => 'user',\n 'id' => 0, // This creates a note.\n ],\n 'activity_date' => time(),\n 'details' => $transcripts,\n 'parent' => $this->convertActivityAssociations($activity),\n ];\n\n $cpActivity = $this->copperClient->activities()->create($data);\n\n // Store CRM Activity ID in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $cpActivity['id'];\n $transcription->save();\n }\n\n /**\n * @inheritdoc\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n if ($crmObject instanceof Lead) {\n $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->update($crmObject->crm_provider_id, [\n 'status_id' => $stage->crm_provider_id,\n ])\n );\n } else {\n $this->copperClient->opportunities()->update($crmObject->crm_provider_id, [\n 'pipeline_stage_id' => $stage->crm_provider_id,\n ]);\n }\n }\n\n public function prepareValueForUpdate(array $params): array\n {\n return [$params['fieldName'] => $params['fieldValue']];\n }\n\n /*\n * @inheritdoc\n */\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $preparedData = $data;\n\n if ($objectType === Field::OBJECT_OPPORTUNITY) {\n $preparedData = $this->prepareOpportunityFieldsForUpdate($data);\n }\n\n try {\n $this->copperClient\n ->createResourceFromObjectType($objectType)\n ->update($objectId, $preparedData)\n ;\n } catch (Exception $e) {\n $this->logger->error(self::RESOURCE_UPDATE_FAILED_ERROR_MESSAGE, [\n 'resource_id' => $objectId,\n 'data' => $preparedData,\n 'error' => $e->getMessage(),\n ]);\n\n throw new CrmException(self::RESOURCE_UPDATE_FAILED_ERROR_MESSAGE, $e->getCode(), $e);\n }\n }\n\n /**\n * @param array<string,string> $fieldData\n *\n * @throws CrmException\n *\n * @return array<string,array<int,array<string,bool|float|int|string|null>>|bool|float|int|string|null>\n */\n private function prepareOpportunityFieldsForUpdate(array $fieldData): array\n {\n $preparedData = [];\n $customFields = [];\n\n foreach ($fieldData as $fieldName => $fieldValue) {\n $field = $this->config\n ->fields()\n ->where('crm_provider_id', $fieldName)\n ->first();\n\n if (! $field instanceof Field) {\n throw new CrmException('Field not found');\n }\n\n $convertedValue = $this->fieldValueConverter->convertToCrm($field->getType(), $fieldValue);\n\n if ($this->isStandardField($fieldName)) {\n $preparedData[$fieldName] = $convertedValue;\n\n continue;\n }\n\n $customFields[] = [\n 'custom_field_definition_id' => $fieldName,\n 'value' => $convertedValue,\n ];\n }\n\n if (! empty($customFields)) {\n $preparedData['custom_fields'] = $customFields;\n }\n\n return $preparedData;\n }\n\n /*\n * @inheritdoc\n */\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n return $this->copperClient->createResourceFromObjectType($objectType)->find($objectId);\n }\n\n private function fetchCustomFieldData(Activity $activity, string $objectType): array\n {\n $payload = [];\n\n $fieldData = FieldData::where([\n 'object_id' => $activity->id,\n ])->whereHas('field', function ($query) use ($objectType) {\n $query->where('object_type', $objectType);\n })->get();\n\n foreach ($fieldData as $data) {\n // Add the field and value to the payload.\n $payload += [\n 'custom_field_definition_id' => $data->field->crm_provider_id,\n 'value' => $data->value,\n ];\n }\n\n return $payload;\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $baseUrl = 'https://app.prosperworks.com/companies/' . $this->config->crm_provider_id . '/app#/';\n switch ($objectType) {\n case 'lead':\n $url = $baseUrl . 'leads/' . $providerId;\n\n break;\n\n case 'account':\n $url = $baseUrl . 'organization/' . $providerId;\n\n break;\n\n case 'contact':\n $url = $baseUrl . 'contact/' . $providerId;\n\n break;\n\n case 'opportunity':\n $url = $baseUrl . 'deal/' . $providerId;\n\n break;\n\n default:\n case 'task':\n case 'activity':\n // Sadly we can't deeplink to these in Copper UI.\n $url = null;\n }\n\n return $url;\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! ($this->config->store_transcript)) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n return $this->transcriptionService\n ->findTranscriptionByActivity($activity)\n ->map(static function (array $transcriptionSegment): string {\n return $transcriptionSegment['formattedStartsAt'] . ' | ' . $transcriptionSegment['transcript'];\n })\n ->implode(PHP_EOL);\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n *\n * @return int|string|bool|float|null\n */\n private function extractFieldValue(array $opportunityData, string $fieldName)\n {\n $fieldValue = $this->isStandardField($fieldName)\n ? $opportunityData[$fieldName]\n : $this->resolveCustomFieldFromOpportunityData($opportunityData, $fieldName);\n\n if (is_array($fieldValue)) {\n $fieldValue = implode(', ', $fieldValue);\n }\n\n return $fieldValue;\n }\n\n private function isStandardField(string $fieldName): bool\n {\n return array_key_exists($fieldName, self::STANDARD_OPPORTUNITY_FIELDS);\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n *\n * @return string|int|float|bool|null|array<string, mixed>\n */\n private function resolveCustomFieldFromOpportunityData(array $opportunityData, string $fieldName)\n {\n $fieldData = array_filter(\n $opportunityData['custom_fields'],\n static fn ($field) => (string) $field['custom_field_definition_id'] === $fieldName\n );\n\n return array_pop($fieldData)['value'] ?? '';\n }\n\n private function isSupportedObjectType(string $objectType): bool\n {\n return $objectType !== self::UNSUPPORTED_OBJECT_TYPE;\n }\n\n private function syncStandardFields(): void\n {\n foreach (self::STANDARD_OPPORTUNITY_FIELDS as $fieldId => $fieldData) {\n $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => mb_strimwidth($fieldId, 0, 128),\n 'object_type' => Field::OBJECT_OPPORTUNITY,\n ], [\n 'label' => mb_strimwidth($fieldData['label'], 0, Field::LABEL_MAX_LENGTH),\n 'type' => $fieldData['type'],\n ]);\n }\n\n $this->importStages([Stage::TYPE_OPPORTUNITY]);\n }\n\n private function requestWithExceptionHandling(\\Closure $apiRequest): iterable\n {\n try {\n return $apiRequest();\n } catch (\\Exception $exception) {\n if ($exception->getCode() === 403) {\n // Object might not be supported\n return [];\n }\n\n \\Sentry::captureException($exception);\n\n return [];\n }\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n if ($this->copperClient === null) {\n return false;\n }\n\n $task = $this->copperClient->tasks()->find($crmProviderId);\n\n return ! empty($task);\n } catch (HttpNotFoundException) {\n // Task not found in CRM - this is expected and permanent\n $this->logger->info('[Copper] Task not found during verification', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n } catch (RequestFailedException $e) {\n // Handle 404 responses from Copper API\n if ($e->getCode() === 404) {\n $this->logger->info('[Copper] Task not found during verification (404)', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n\n // Re-throw other Copper exceptions for retry\n throw $e;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\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":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"on_screen":false,"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":false,"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":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Tx: Auto","depth":4,"on_screen":false,"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":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"on_screen":false,"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":"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":"8","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"4","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":"SELECT\n# DISTINCT\nopp.id as opp_id, opp.uuid, opp.name,\n# COUNT(dr.id) AS deal_risk_count,\n\n# dr.id,\n# cfd.value,\nusr.name AS owner_name,\nopp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,\nusr.uuid as owner_uuid,\nusr.photo_path as owner_photo,\nusr.id AS owner_id,\njt.name as owner_job,\nopp.stage_id, opp.stage_updated_at,\nacc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,\nrt.business_process_id AS pipeline_id\nFROM opportunities opp\nLEFT JOIN record_types rt ON opp.record_type_id = rt.id\nLEFT JOIN users usr ON opp.user_id = usr.id\nLEFT JOIN accounts acc ON opp.account_id = acc.id\nLEFT JOIN job_titles jt ON usr.job_title_id = jt.id\n\n# LEFT JOIN group_deal_risk_types gdrt ON gdrt.group_id = usr.group_id\n# LEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id AND dr.group_deal_risk_type_id = gdrt.id\n\nLEFT JOIN crm_field_data cfd ON (cfd.object_id = opp.id and cfd.crm_field_id = 66814)\n\nWHERE opp.user_id IS NOT NULL\nAND opp.deleted_at IS NULL\nAND opp.is_closed = 1\nAND opp.is_won = 0\nAND opp.close_date >= '2024-01-01 00:00:00'\nAND opp.close_date <= '2024-12-31 23:59:59'\nAND usr.team_id = 1\n\n# and opp.id = 4823179\n\nGROUP BY opp.id, cfd.value\nORDER BY\n# cfd.value\n CAST(cfd.value AS UNSIGNED)\n# owner_name\n# (SELECT COUNT(dr.id)\n# FROM deal_risks dr\n# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n# WHERE dr.opportunity_id = opp.id\n# AND dr.is_active = 1\n# AND gdrt.is_enabled = 1)\nDESC\nLIMIT 25\n# OFFSET 0\n;\n\nselect * from crm_fields where crm_configuration_id = 1 and object_type = 'opportunity';\nselect * from crm_layout_entities where crm_layout_id = 1493;\n\nSELECT * FROM opportunities WHERE id = 4584045;\nSELECT * FROM crm_field_data WHERE object_id = 4584045;\n\nSELECT * FROM opportunities where team_id = 1 and crm_provider_id = '0061K00000lfb9IQAQ'\n\nSELECT\n opp.id as opportunity_id,\n opp.name,\n COUNT(dr.id) as risk_count\nFROM opportunities opp\nLEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id\nWHERE opp.id IN (\n 6069574,8900938,9507638,9524799,9660490,9662824,9705675,9749758,4158460,4391812,6450439,4448422,5118945,5590675,4584045,7228149,9002408,9165534,9446720,9641778,9665149,9703344,9709280,5747948,4158491,6182565,6263970,5798120,5111315,4536978,6062352,6548383,6072095,6548225,4480986,5011422,6548381,8760540,8917554,9509986,9514392,9569009,9569011,9578490,9713604,5784397,7276612,7288405,8994421,9118219,9608148,9818911,4510535,6479693,5958049,6271674,6550448,4158331,4158483,6126571,6171615,6540943,4897466,5190896,5796182,5932762,8572433,8723698,8892697,9711001,9789264,4549188,6100831,6170064,6260799,6263653,6449936,6530871,6538978,7777651,8059269,8319918,8787049,8901150,9263153,9453207,9514738,9696700,9791062,5752018,6421452,7439134,7878923,9354763,9369285,9514396,9582506,9889949,9890216,4094311,4158495,4158496,6098128,5585661,3872564,6442149,5891604,6164746,6199593,6583474,6519684,9018490,9809006,4496897,5041324,5829430,6198319,6253504,6555763,7242914,7931055,8024125,8797814,8058559,8673347,8892695,8994420,9616219,9714970,9722004,9809439,9818918,6523177,8134147,9002915,9711422,9892713,9901719,9954210,9978435,5800810,6243518,6416114,6222251,6411974,6512456,5791953,6545606,9914780,5805540,6238986,6463838,6547680,9767049,9809437,9810885,9890855,6673493,9902036,4335521,6379871,6503799,6546077,8018765,9907556,9958433,9905855,9916179,9946741,9957877,5563344,6271838,6450815,7641128,7762567,7780592,8684810,8685786,8685787,8685788\n)\nGROUP BY opp.id;\n\nSELECT COUNT(dr.id)\n FROM deal_risks dr\n JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n WHERE dr.opportunity_id = 5563344\n# AND gdrt.group_id = usr.group_id\n\n\n\nEXPLAIN SELECT\n opp.id as opp_id, opp.uuid, opp.name,\n\ncfd.value,\ncfv.sequence,\ncfv.value,\n# MAX(cfd.value) AS max_cfd_value,\nusr.name AS owner_name,\nopp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,\nusr.uuid as owner_uuid,\nusr.photo_path as owner_photo,\nusr.id AS owner_id,\njt.name as owner_job,\nopp.stage_id, opp.stage_updated_at,\nacc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,\nrt.business_process_id AS pipeline_id\nFROM opportunities opp\n\nLEFT JOIN record_types rt ON opp.record_type_id = rt.id\nLEFT JOIN users usr ON opp.user_id = usr.id\nLEFT JOIN accounts acc ON opp.account_id = acc.id\nLEFT JOIN job_titles jt ON usr.job_title_id = jt.id\n\nLEFT JOIN crm_field_data cfd ON cfd.id = (SELECT sub_cfd.id\n FROM crm_field_data sub_cfd\n WHERE sub_cfd.object_id = opp.id\n AND sub_cfd.crm_field_id = 66810\n ORDER BY sub_cfd.updated_at DESC\n LIMIT 1)\n\nLEFT JOIN crm_field_values cfv ON cfv.crm_field_id = 66810 AND cfv.value = cfd.value\n\nWHERE opp.user_id IS NOT NULL\nAND opp.deleted_at IS NULL\nAND opp.is_closed = 0\n# AND opp.is_closed = 1\n# AND opp.is_won = 0\nAND opp.close_date >= '2024-01-01 00:00:00'\nAND opp.close_date <= '2024-12-31 23:59:59'\nAND usr.team_id = 1\n\n# and opp.id = 4823179\n\n# GROUP BY opp.id\nORDER BY\n cfv.sequence DESC,\n# opp.name\n# owner_name\n cfd.value\n# CAST(cfd.value AS UNSIGNED)\n# CAST(MAX(cfd.value) AS UNSIGNED)\n# (SELECT COUNT(dr.id)\n# FROM deal_risks dr\n# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n# WHERE dr.opportunity_id = opp.id\n# AND dr.is_active = 1 AND gdrt.is_enabled = 1)\nDESC\n# LIMIT 75, 25\n;\n\n\n\nSELECT * FROM crm_field_values WHERE crm_field_id = 66810;\n\nSELECT f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value, fd.updated_at, fd.id, fd.created_at\nFROM crm_fields f\nINNER JOIN crm_field_data fd ON fd.crm_field_id = f.id\n WHERE (f.crm_configuration_id = 1)\n AND (f.object_type = 'opportunity')\n# AND (fd.object_id IN (4158331,4158483,4158495,4158496,6069574,6263970,6171615,6540943,6545606,5829430,6198319,6263653,6548381,7242914,8797814,7228149,7439134,7878923,8134147,9002915,9118219,9165534,9354763,9369285,9446720))\n AND (fd.object_id IN (4158460))\n AND (f.crm_provider_id IN ('ForecastCategoryName'))\n ORDER BY fd.object_id ASC, fd.updated_at DESC;\n\nselect * from crm_layouts where crm_configuration_id = 1;\nselect cf.* from crm_fields cf\njoin crm_layout_entities cle on cf.id = cle.crm_field_id\nwhere crm_layout_id = 1493;\n\nSELECT * FROM opportunities WHERE id = 4158460;\nSELECT * FROM crm_field_data WHERE object_id = 4158460;\n\nselect * from users where team_id = 1;\nSELECT * FROM users WHERE id = 7160;\nselect * from role_user where user_id = 3248;\n\nselect * from crm_field_values where crm_field_id = 66824;\n\nSELECT * FROM users WHERE id = 23470;\nselect * from crm_configurations;\n\n# ******************************************\nselect * from teams where id = 1038; # 23521, 966\nselect * from users where team_id = 1038;\nselect * from crm_configurations where id = 966;\nSELECT * FROM activities WHERE uuid_to_bin('e8dc7c34-31f6-4430-bd81-2d9d8f00dd07') = uuid; # 54965762\nSELECT * FROM activities WHERE uuid_to_bin('4b5727c0-69d1-428f-b8d9-b649055166e2') = uuid; # 54965764\nSELECT * FROM participants WHERE activity_id = 54965764;\n\nSELECT id, uuid, title, recording_state FROM activities WHERE uuid_to_bin('355f105d-5606-4379-b0c5-d91daf59f4ce') = uuid; # 54964075\nSELECT * FROM participants WHERE activity_id = 54964075;\nselect f.id, slug, title, tf.team_id from team_features tf JOIN features f on tf.feature_id = f.id\n where tf.team_id = 1038;\n\n\n# ****************************************** PD *************************\nselect * from teams where id = 1029;\nSELECT * FROM crm_configurations WHERE id = 957;\nSELECT * FROM activities WHERE uuid_to_bin('581a33cb-4343-44bd-ac0c-4a5cee71c5ec') = uuid; # 54963423\nSELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433\n\nSELECT * FROM activities WHERE uuid_to_bin('8b6bb2f7-e7a7-4aec-8806-fbfea7093ccd') = uuid; # 54963421\n\n# ****************************************** Close *************************\nselect * from teams where id = 1031;\nSELECT * FROM crm_configurations WHERE id = 959;\nSELECT * FROM activities WHERE uuid_to_bin('59c517e0-96c9-4dad-bfeb-b7bef72f8725') = uuid; # 54963517\n\n\nSELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433\n\nSELECT * FROM activities WHERE uuid_to_bin('d68311e3-ac34-49bd-bf04-88323a7e5352') = uuid; # 54966009\n\n# ****************************************** SF *************************\nSELECT * FROM activities WHERE uuid_to_bin('2bd4cfa3-4eb5-4c77-84a7-9ed46a21c988') = uuid;\n\nselect * from roles;\nselect * from permissions;\nselect * from permission_role where permission_id = 136;\n\nselect * from migrations order by id desc;\n\nselect * from teams where id IN (1, 1037);\nselect * from crm_layouts where crm_configuration_id = 1;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1493;\nSELECT * FROM crm_fields WHERE id IN (1652,1661,66799,66814,66821,66836,66843,66846,66864,84752,182306,323580,380378);\n\nselect * from features;\nselect * from team_features where feature_id = 33;\nselect * from opportunities;\n\nselect * from teams;\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 = 1052 and sa.provider = 'hubspot';\n\nSELECT * FROM accounts where id = 11512582;\nselect * from activities where account_id = 11512582;","depth":4,"on_screen":true,"value":"SELECT\n# DISTINCT\nopp.id as opp_id, opp.uuid, opp.name,\n# COUNT(dr.id) AS deal_risk_count,\n\n# dr.id,\n# cfd.value,\nusr.name AS owner_name,\nopp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,\nusr.uuid as owner_uuid,\nusr.photo_path as owner_photo,\nusr.id AS owner_id,\njt.name as owner_job,\nopp.stage_id, opp.stage_updated_at,\nacc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,\nrt.business_process_id AS pipeline_id\nFROM opportunities opp\nLEFT JOIN record_types rt ON opp.record_type_id = rt.id\nLEFT JOIN users usr ON opp.user_id = usr.id\nLEFT JOIN accounts acc ON opp.account_id = acc.id\nLEFT JOIN job_titles jt ON usr.job_title_id = jt.id\n\n# LEFT JOIN group_deal_risk_types gdrt ON gdrt.group_id = usr.group_id\n# LEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id AND dr.group_deal_risk_type_id = gdrt.id\n\nLEFT JOIN crm_field_data cfd ON (cfd.object_id = opp.id and cfd.crm_field_id = 66814)\n\nWHERE opp.user_id IS NOT NULL\nAND opp.deleted_at IS NULL\nAND opp.is_closed = 1\nAND opp.is_won = 0\nAND opp.close_date >= '2024-01-01 00:00:00'\nAND opp.close_date <= '2024-12-31 23:59:59'\nAND usr.team_id = 1\n\n# and opp.id = 4823179\n\nGROUP BY opp.id, cfd.value\nORDER BY\n# cfd.value\n CAST(cfd.value AS UNSIGNED)\n# owner_name\n# (SELECT COUNT(dr.id)\n# FROM deal_risks dr\n# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n# WHERE dr.opportunity_id = opp.id\n# AND dr.is_active = 1\n# AND gdrt.is_enabled = 1)\nDESC\nLIMIT 25\n# OFFSET 0\n;\n\nselect * from crm_fields where crm_configuration_id = 1 and object_type = 'opportunity';\nselect * from crm_layout_entities where crm_layout_id = 1493;\n\nSELECT * FROM opportunities WHERE id = 4584045;\nSELECT * FROM crm_field_data WHERE object_id = 4584045;\n\nSELECT * FROM opportunities where team_id = 1 and crm_provider_id = '0061K00000lfb9IQAQ'\n\nSELECT\n opp.id as opportunity_id,\n opp.name,\n COUNT(dr.id) as risk_count\nFROM opportunities opp\nLEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id\nWHERE opp.id IN (\n 6069574,8900938,9507638,9524799,9660490,9662824,9705675,9749758,4158460,4391812,6450439,4448422,5118945,5590675,4584045,7228149,9002408,9165534,9446720,9641778,9665149,9703344,9709280,5747948,4158491,6182565,6263970,5798120,5111315,4536978,6062352,6548383,6072095,6548225,4480986,5011422,6548381,8760540,8917554,9509986,9514392,9569009,9569011,9578490,9713604,5784397,7276612,7288405,8994421,9118219,9608148,9818911,4510535,6479693,5958049,6271674,6550448,4158331,4158483,6126571,6171615,6540943,4897466,5190896,5796182,5932762,8572433,8723698,8892697,9711001,9789264,4549188,6100831,6170064,6260799,6263653,6449936,6530871,6538978,7777651,8059269,8319918,8787049,8901150,9263153,9453207,9514738,9696700,9791062,5752018,6421452,7439134,7878923,9354763,9369285,9514396,9582506,9889949,9890216,4094311,4158495,4158496,6098128,5585661,3872564,6442149,5891604,6164746,6199593,6583474,6519684,9018490,9809006,4496897,5041324,5829430,6198319,6253504,6555763,7242914,7931055,8024125,8797814,8058559,8673347,8892695,8994420,9616219,9714970,9722004,9809439,9818918,6523177,8134147,9002915,9711422,9892713,9901719,9954210,9978435,5800810,6243518,6416114,6222251,6411974,6512456,5791953,6545606,9914780,5805540,6238986,6463838,6547680,9767049,9809437,9810885,9890855,6673493,9902036,4335521,6379871,6503799,6546077,8018765,9907556,9958433,9905855,9916179,9946741,9957877,5563344,6271838,6450815,7641128,7762567,7780592,8684810,8685786,8685787,8685788\n)\nGROUP BY opp.id;\n\nSELECT COUNT(dr.id)\n FROM deal_risks dr\n JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n WHERE dr.opportunity_id = 5563344\n# AND gdrt.group_id = usr.group_id\n\n\n\nEXPLAIN SELECT\n opp.id as opp_id, opp.uuid, opp.name,\n\ncfd.value,\ncfv.sequence,\ncfv.value,\n# MAX(cfd.value) AS max_cfd_value,\nusr.name AS owner_name,\nopp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,\nusr.uuid as owner_uuid,\nusr.photo_path as owner_photo,\nusr.id AS owner_id,\njt.name as owner_job,\nopp.stage_id, opp.stage_updated_at,\nacc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,\nrt.business_process_id AS pipeline_id\nFROM opportunities opp\n\nLEFT JOIN record_types rt ON opp.record_type_id = rt.id\nLEFT JOIN users usr ON opp.user_id = usr.id\nLEFT JOIN accounts acc ON opp.account_id = acc.id\nLEFT JOIN job_titles jt ON usr.job_title_id = jt.id\n\nLEFT JOIN crm_field_data cfd ON cfd.id = (SELECT sub_cfd.id\n FROM crm_field_data sub_cfd\n WHERE sub_cfd.object_id = opp.id\n AND sub_cfd.crm_field_id = 66810\n ORDER BY sub_cfd.updated_at DESC\n LIMIT 1)\n\nLEFT JOIN crm_field_values cfv ON cfv.crm_field_id = 66810 AND cfv.value = cfd.value\n\nWHERE opp.user_id IS NOT NULL\nAND opp.deleted_at IS NULL\nAND opp.is_closed = 0\n# AND opp.is_closed = 1\n# AND opp.is_won = 0\nAND opp.close_date >= '2024-01-01 00:00:00'\nAND opp.close_date <= '2024-12-31 23:59:59'\nAND usr.team_id = 1\n\n# and opp.id = 4823179\n\n# GROUP BY opp.id\nORDER BY\n cfv.sequence DESC,\n# opp.name\n# owner_name\n cfd.value\n# CAST(cfd.value AS UNSIGNED)\n# CAST(MAX(cfd.value) AS UNSIGNED)\n# (SELECT COUNT(dr.id)\n# FROM deal_risks dr\n# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n# WHERE dr.opportunity_id = opp.id\n# AND dr.is_active = 1 AND gdrt.is_enabled = 1)\nDESC\n# LIMIT 75, 25\n;\n\n\n\nSELECT * FROM crm_field_values WHERE crm_field_id = 66810;\n\nSELECT f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value, fd.updated_at, fd.id, fd.created_at\nFROM crm_fields f\nINNER JOIN crm_field_data fd ON fd.crm_field_id = f.id\n WHERE (f.crm_configuration_id = 1)\n AND (f.object_type = 'opportunity')\n# AND (fd.object_id IN (4158331,4158483,4158495,4158496,6069574,6263970,6171615,6540943,6545606,5829430,6198319,6263653,6548381,7242914,8797814,7228149,7439134,7878923,8134147,9002915,9118219,9165534,9354763,9369285,9446720))\n AND (fd.object_id IN (4158460))\n AND (f.crm_provider_id IN ('ForecastCategoryName'))\n ORDER BY fd.object_id ASC, fd.updated_at DESC;\n\nselect * from crm_layouts where crm_configuration_id = 1;\nselect cf.* from crm_fields cf\njoin crm_layout_entities cle on cf.id = cle.crm_field_id\nwhere crm_layout_id = 1493;\n\nSELECT * FROM opportunities WHERE id = 4158460;\nSELECT * FROM crm_field_data WHERE object_id = 4158460;\n\nselect * from users where team_id = 1;\nSELECT * FROM users WHERE id = 7160;\nselect * from role_user where user_id = 3248;\n\nselect * from crm_field_values where crm_field_id = 66824;\n\nSELECT * FROM users WHERE id = 23470;\nselect * from crm_configurations;\n\n# ******************************************\nselect * from teams where id = 1038; # 23521, 966\nselect * from users where team_id = 1038;\nselect * from crm_configurations where id = 966;\nSELECT * FROM activities WHERE uuid_to_bin('e8dc7c34-31f6-4430-bd81-2d9d8f00dd07') = uuid; # 54965762\nSELECT * FROM activities WHERE uuid_to_bin('4b5727c0-69d1-428f-b8d9-b649055166e2') = uuid; # 54965764\nSELECT * FROM participants WHERE activity_id = 54965764;\n\nSELECT id, uuid, title, recording_state FROM activities WHERE uuid_to_bin('355f105d-5606-4379-b0c5-d91daf59f4ce') = uuid; # 54964075\nSELECT * FROM participants WHERE activity_id = 54964075;\nselect f.id, slug, title, tf.team_id from team_features tf JOIN features f on tf.feature_id = f.id\n where tf.team_id = 1038;\n\n\n# ****************************************** PD *************************\nselect * from teams where id = 1029;\nSELECT * FROM crm_configurations WHERE id = 957;\nSELECT * FROM activities WHERE uuid_to_bin('581a33cb-4343-44bd-ac0c-4a5cee71c5ec') = uuid; # 54963423\nSELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433\n\nSELECT * FROM activities WHERE uuid_to_bin('8b6bb2f7-e7a7-4aec-8806-fbfea7093ccd') = uuid; # 54963421\n\n# ****************************************** Close *************************\nselect * from teams where id = 1031;\nSELECT * FROM crm_configurations WHERE id = 959;\nSELECT * FROM activities WHERE uuid_to_bin('59c517e0-96c9-4dad-bfeb-b7bef72f8725') = uuid; # 54963517\n\n\nSELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433\n\nSELECT * FROM activities WHERE uuid_to_bin('d68311e3-ac34-49bd-bf04-88323a7e5352') = uuid; # 54966009\n\n# ****************************************** SF *************************\nSELECT * FROM activities WHERE uuid_to_bin('2bd4cfa3-4eb5-4c77-84a7-9ed46a21c988') = uuid;\n\nselect * from roles;\nselect * from permissions;\nselect * from permission_role where permission_id = 136;\n\nselect * from migrations order by id desc;\n\nselect * from teams where id IN (1, 1037);\nselect * from crm_layouts where crm_configuration_id = 1;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1493;\nSELECT * FROM crm_fields WHERE id IN (1652,1661,66799,66814,66821,66836,66843,66846,66864,84752,182306,323580,380378);\n\nselect * from features;\nselect * from team_features where feature_id = 33;\nselect * from opportunities;\n\nselect * from teams;\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 = 1052 and sa.provider = 'hubspot';\n\nSELECT * FROM accounts where id = 11512582;\nselect * from activities where account_id = 11512582;","role_description":"text entry area","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.28224733,"top":1.0,"width":0.024268618,"height":-0.04788506},"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}]...
|
8957564869086018857
|
-7959665055215941403
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
11
72
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Copper;
use Carbon\Carbon;
use Exception;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Support\Facades\Cache;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\CopperInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Crm\LayoutEntity;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Repositories\UserRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Copper\Api\Client;
use Jiminny\Services\Crm\Copper\Api\ClientFactory;
use Jiminny\Services\Crm\Copper\Exception\RequestFailedException;
use Jiminny\Services\Crm\Helpers\FilterJoinedParticipants;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\Copper\Traits\SearchesCrmEntities;
use Jiminny\Utils\CurrencyFormatter;
use Jiminny\Utils\StringUtil;
class Service extends BaseService implements
CopperInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
RemoteEntityManipulationInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use SearchesCrmEntities;
private const int NOTE_BODY_MAX_LENGTH = 3000000;
private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day
private const array STANDARD_OPPORTUNITY_FIELDS = [
'monetary_value' => [
'label' => 'Value',
'available_on' => Field::OBJECT_OPPORTUNITY,
'type' => Field::TYPE_CURRENCY,
],
'pipeline_stage_id' => [
'label' => 'Stage',
'type' => Field::TYPE_PICKLIST,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
'close_date' => [
'label' => 'Close date',
'type' => Field::TYPE_DATE,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
'win_probability' => [
'label' => 'Win probability',
'type' => Field::TYPE_NUMBER,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
];
private const string UNSUPPORTED_OBJECT_TYPE = 'unsupported';
private const string OPPORTUNITY_STATUS_OPEN = 'Open';
private const string OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE = 'Opportunity import failed';
private const string RESOURCE_UPDATE_FAILED_ERROR_MESSAGE = 'Failed to update resource';
private FieldValueConverter $fieldValueConverter;
private ClientFactory $clientFactory;
private ?Client $copperClient = null;
public function __construct(
ClientFactory $clientFactory,
FieldValueConverter $fieldValueConverter,
private readonly UserRepository $userRepository,
private readonly ProspectPhotoPathService $prospectPhotoPathService,
private readonly CrmEntityRepository $crmEntityRepository
) {
parent::__construct();
$this->clientFactory = $clientFactory;
$this->fieldValueConverter = $fieldValueConverter;
}
public function getDisplayName(): string
{
return 'Copper';
}
/**
* Get the CRM entity repository (used by SearchesCrmEntities trait)
*/
protected function getCrmEntityRepository(): CrmEntityRepository
{
return $this->crmEntityRepository;
}
public function getMinimumApiVersion(): string
{
return Client::MIN_API_VERSION;
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
$owner = $user->team->owner;
return $owner->getSocialAccount(SocialAccount::PROVIDER_COPPER);
}
public function setUser(User $user): void
{
$this->configureSentryScope($user);
$this->team = $user->getTeam();
$this->teamService->setTeam($user->getTeam());
$this->setConfiguration($user->getTeam()->getCrmConfiguration());
// Reset state.
$this->profile = $user->getProfile();
if (! $this->profile instanceof Profile) {
// Try to fetch their profile, maybe it was not yet imported?
$this->profile = $this->getProfile($user);
}
}
public function setConfiguration(Configuration $configuration): void
{
$this->config = $configuration;
$this->copperClient = $this->clientFactory->create($configuration);
if ($this->team === null) {
$this->team = $configuration->getTeam();
}
}
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);
}
private function mapObjectType(string $objectType): string
{
$objectType = strtolower($objectType);
switch ($objectType) {
case Field::OBJECT_TASK:
case Field::OBJECT_OPPORTUNITY:
case Field::OBJECT_LEAD:
$mappedType = $objectType;
break;
case Field::OBJECT_ACCOUNT:
$mappedType = 'company';
break;
case Field::OBJECT_CONTACT:
$mappedType = 'person';
break;
default:
$mappedType = self::UNSUPPORTED_OBJECT_TYPE;
break;
}
return $mappedType;
}
/**
* @param string $crmObject The name of the CRM object. i.e. Opportunity or Contact
*/
protected function getFields(string $crmObject): array
{
$mappedObjectType = $this->mapObjectType($crmObject);
if (! $this->isSupportedObjectType($mappedObjectType)) {
return [];
}
$customFields = $this->copperClient->fields()->all();
$filteredFields = array_filter(
$customFields,
static fn ($field) => in_array($mappedObjectType, $field['available_on'], true)
);
return array_map(
fn (array $property) => [
'name' => $property['id'],
'label' => $property['name'],
'type' => $this->convertFieldType($property['data_type']),
],
$filteredFields
);
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
// Setup the activity field as the default Type.
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'type',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldFilters = FieldDefinitions::taskFollowupFieldsFilter();
foreach ($fieldFilters as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
public function syncFields(): void
{
$this->syncStandardFields();
$this->syncCustomFields();
}
public function syncField(Field $field): void
{
if ($field->getCrmProviderId() === 'type') {
/**
* This field is a special case, it is not a custom field and is not returned by the Copper API.
*
* The field is created manually during layout setup.
*
* @see getDefaultFields()
*
* There is a separate endpoint to get the activity types.
* @see importPicklistValues()
*/
return;
}
if ($field->getCrmProviderId() === 'pipeline_stage_id') {
// Not a custom type
return;
}
$crmField = $this->copperClient->fields()->find($field->getCrmProviderId());
$field->label = $crmField['name'];
$field->type = $this->convertFieldType($crmField['data_type']);
$field->save();
}
/**
* @param string $fieldType How the data should be input
*/
private function convertFieldType(string $fieldType): string
{
$fieldType = strtolower($fieldType);
switch ($fieldType) {
case 'dropdown':
$convertedType = Field::TYPE_PICKLIST;
break;
case 'string':
$convertedType = Field::TYPE_TEXT;
break;
case 'float':
case 'percentage':
$convertedType = Field::TYPE_NUMBER;
break;
case 'text':
$convertedType = Field::TYPE_TEXTAREA;
break;
case 'checkbox':
$convertedType = Field::TYPE_BOOLEAN;
break;
case Field::TYPE_DATE:
case Field::TYPE_CURRENCY:
case Field::TYPE_URL:
$convertedType = $fieldType;
break;
default:
$convertedType = Field::TYPE_UNSUPPORTED;
break;
}
return $convertedType;
}
/**
* @inheritdoc
*/
public function importPicklistValues(Field $field): array
{
$fieldValues = [];
if ($field->object_type === 'opportunity' && $field->crm_provider_id === 'pipeline_stage_id') {
return $this->importFieldValuesForDealInsights($field);
}
$values = [];
if ($field->object_type === Field::OBJECT_TASK && $field->crm_provider_id === 'type') {
$activityTypes = $this->copperClient->activityTypes()->all();
/**
* We ignore "system" activity types, disabled activity types and the "Note" activity type.
*/
$activityTypes = array_filter(
$activityTypes['user'],
fn (array $activityType) => ! $activityType['is_disabled'] && $activityType['id'] !== 0
);
// Import all activity values.
$i = 0;
foreach ($activityTypes as $activityType) {
$values[] = [
'value' => $activityType['id'],
'label' => mb_strimwidth($activityType['name'], 0, Field::LABEL_MAX_LENGTH),
'sequence' => $i++,
];
}
} else {
// We just check for the field in the custom definitions.
$crmField = $this->copperClient->fields()->find($field->crm_provider_id);
// Import all values.
foreach ($crmField['options'] as $option) {
$values[] = [
'value' => $option['id'],
'label' => mb_strimwidth($option['name'], 0, 191),
'sequence' => $option['rank'],
];
}
}
// Take the existing set of field values.
$fieldsToPurge = $field->values()->get()->pluck('value')->toArray();
foreach ($values as $value) {
// For all current values, upsert the field.
$value['value'] = substr($value['value'] ?? '', 0, 255);
$fieldValues[] = $field->values()->updateOrCreate([
'value' => $value['value'],
], $value);
// Remove this value from the ones we are going to purge.
$key = array_search($value['value'], $fieldsToPurge, false);
if ($key !== false) {
unset($fieldsToPurge[$key]);
}
}
// Delete the old values that are no longer used.
$field->values()->whereIn('value', $fieldsToPurge)->delete();
return $fieldValues;
}
/**
*
* @return FieldValue[]
*/
private function importFieldValuesForDealInsights(Field $field): array
{
$fieldValues = [];
$pipelines = $this->copperClient->pipelines()->all();
foreach ($pipelines as $pipeline) {
foreach ($pipeline['stages'] as $i => $dealStage) {
$fieldValues[] = $field->values()->updateOrCreate(
['value' => $dealStage['id']],
[
'label' => $dealStage['name'],
'sequence' => $i,
]
);
}
}
return $fieldValues;
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
if ($types === null) {
$types = [Stage::TYPE_LEAD, Stage::TYPE_OPPORTUNITY];
}
$missingStage = null;
foreach ($types as $type) {
if ($type === Stage::TYPE_LEAD) {
$statuses = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leadStatuses()->all()
);
if (count($statuses) > 0) {
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => BusinessProcess::TYPE_LEAD,
], [
'team_id' => $this->team->id,
'name' => BusinessProcess::TYPE_LEAD,
'type' => BusinessProcess::TYPE_LEAD,
'is_selectable' => true,
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => BusinessProcess::TYPE_LEAD,
], [
'team_id' => $this->team->id,
'name' => BusinessProcess::TYPE_LEAD,
'is_selectable' => true,
'business_process_id' => $businessProcess->id ?? null,
]);
$leadStatuses = [];
foreach ($statuses as $status) {
// Upsert all statuses for the team.
$status = $this->config->stages()->updateOrCreate([
'crm_provider_id' => $status['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($status['name'], 0, 50),
'label' => mb_strimwidth($status['name'], 0, 191),
'type' => Stage::TYPE_LEAD,
'sequence' => $status['order'],
'is_selectable' => true,
]);
if ($missingStageName && $missingStageName === $status['id']) {
$missingStage = $status;
}
$leadStatuses[] = $status['id'];
}
$businessProcess->stages()->sync($leadStatuses);
}
} else {
// We create a business process to contain the pipeline, and later store all stages against it.
foreach ($this->copperClient->pipelines()->all() as $pipeline) {
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $pipeline['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($pipeline['name'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => true,
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $pipeline['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($pipeline['name'], 0, 150),
'is_selectable' => true,
'business_process_id' => $businessProcess->id ?? null,
]);
$stages = [];
foreach ($pipeline['stages'] as $i => $dealStage) {
// Upsert all stages for the team.
$stage = $this->config->stages()->updateOrCreate([
'crm_provider_id' => $dealStage['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($dealStage['name'], 0, 50),
'label' => mb_strimwidth($dealStage['name'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $i,
'is_selectable' => true,
'probability' => $dealStage['win_probability'],
]);
if ($missingStageName && $missingStageName === $dealStage['id']) {
$missingStage = $stage;
}
$stages[] = $stage['id'];
}
$businessProcess->stages()->sync($stages);
}
}
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int
{
$syncCount = 0;
$cpLeads = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->paginate([
'minimum_modified_date' => $since->timestamp,
'sort_by' => 'date_modified',
])
);
foreach ($cpLeads as $cpLead) {
// Only sync if previously imported.
if ($this->hasLead($cpLead['id']) === false) {
$this->importLead($cpLead);
$syncCount++;
}
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncLead(string $crmId): ?Lead
{
$cpLead = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->find($crmId)
);
if (\count($cpLead) === 0) {
return null;
}
return $this->importLead($cpLead);
}
/**
* @inheritdoc
*/
private function importLead($crmData): ?Lead
{
$countryCode = null;
if (! empty($crmData['address']) && isset($crmData['address']['country'])) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$mobilePhone = $parsedNumber = null;
if (! empty($crmData['phone_numbers'])) {
foreach ($crmData['phone_numbers'] as $phoneNumber) {
if ($phoneNumber['category'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);
} else {
$parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);
}
}
}
$name = $crmData['name'];
if (empty($crmData['company_name'])) {
$company = 'Unknown';
} else {
$company = mb_strimwidth($crmData['company_name'], 0, 191);
}
$domain = null;
if (empty($crmData['websites']) === false) {
$domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);
$domain = StringUtil::resolveDomain($domain);
}
$email = null;
if (empty($crmData['email']) === false) {
$email = mb_strimwidth($crmData['email']['email'], 0, 80);
}
$stage = $this->config
->stages()
->where('crm_provider_id', (string) $crmData['status_id'])
->where('type', Stage::TYPE_LEAD)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_LEAD], $crmData['status_id']);
}
if (! $stage instanceof Stage) {
return null;
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($name, 0, 191),
'company' => $company,
'domain' => $domain,
'title' => $crmData['title'] ? mb_strimwidth($crmData['title'], 0, 128) : null,
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'mobile_phone' => $mobilePhone,
'stage_id' => $stage->id,
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Lead::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'country_code' => $countryCode,
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->leads()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
/**
* @inheritdoc
*/
public function syncAccounts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
$cpAccounts = $this->copperClient->accounts()->paginate([
'minimum_modified_date' => $since->timestamp,
'sort_by' => 'date_modified',
]);
foreach ($cpAccounts as $cpAccount) {
// Only sync if previously imported.
if ($this->hasAccount($cpAccount['id'])) {
$this->importAccount($cpAccount);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncAccount(string $crmId): ?Account
{
$cpAccount = $this->copperClient->accounts()->find($crmId);
if (empty($cpAccount)) {
return null;
}
return $this->importAccount($cpAccount);
}
/**
* @inheritdoc
*/
private function importAccount($crmData): Account
{
$countryCode = null;
if (empty($crmData['address']) === false && $crmData['address']['country']) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$name = $crmData['name'];
$parsedNumber = null;
foreach ($crmData['phone_numbers'] as $phoneNumber) {
$parsedNumber = parsePhoneNumber($countryCode, $phoneNumber['number']);
}
$domain = null;
if (empty($crmData['websites']) === false) {
$domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);
$domain = StringUtil::resolveDomain($domain);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($name, 0, 191),
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Account::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'country_code' => $countryCode,
'domain' => $domain,
'phone' => $parsedNumber['phone'] ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->accounts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
public function syncOpportunities(array $parameters, ?string $strategy = null): int
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->copperClient,
]);
$strategies = $strategyResolver->getStrategies($this->config, $strategy);
$syncCount = 0;
try {
foreach ($strategies as $syncStrategy) {
foreach ($syncStrategy->fetchOpportunities($parameters) as $opportunityData) {
$this->importOpportunity($opportunityData);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
$this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => $exception->getMessage(),
]);
}
return $syncCount;
}
public function syncOpportunity(string $crmId): ?Opportunity
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->copperClient,
]);
$strategy = $strategyResolver->resolve(
$this->config,
OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY
);
$parameters['crm_id'] = $crmId;
$cpOpportunity = $strategy->fetchOpportunities($parameters);
return $this->importOpportunity($cpOpportunity);
}
private function importOpportunity($crmData): ?Opportunity
{
$companyId = (string) $crmData['company_id'];
if (empty($companyId)) {
$this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => 'No company id',
]);
return null;
}
$account = $this->config->accounts()->where('crm_provider_id', $companyId)->first();
if ($account === null) {
$account = $this->syncAccount($companyId);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', (string) $crmData['pipeline_id'])
->first();
if ($businessProcess === null) {
// It is possible for some deals to not be in a pipeline.
$this->logger->warning(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => 'Missing pipeline',
]);
return null;
}
$stage = $businessProcess
->stages()
->where('crm_provider_id', (string) $crmData['pipeline_stage_id'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
$this->logger->info('Stage not found, importing', [
'pipeline_id' => $crmData['pipeline_id'],
'stage_id' => $crmData['pipeline_stage_id'],
]);
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData['pipeline_stage_id']);
}
$recordType = $businessProcess->recordTypes()->first();
$closeDate = null;
$isClosed = $crmData['status'] !== self::OPPORTUNITY_STATUS_OPEN;
if ($crmData['close_date']) {
$closeDate = Carbon::parse($crmData['close_date'])->format('Y-m-d');
}
$data = [
'team_id' => $this->team->getId(),
'account_id' => $account->id,
'user_id' => $profile->user_id ?? null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($crmData['name'], 0, 128),
'value' => $crmData['monetary_value'],
'currency_code' => CurrencyFormatter::formatCode($crmData['monetary_unit']),
'close_date' => $closeDate,
'is_closed' => $isClosed,
'is_won' => $crmData['status'] === 'Won',
'stage_id' => $stage->id,
'record_type_id' => $recordType->id ?? null,
'remotely_created_at' => $crmData['date_created'],
];
/** @var Opportunity $opportunity */
$opportunity = $this->config
->opportunities()
->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data)
;
// import external fields into crm_field_data if present
$dealInsightsFields = $this->getOpportunitySyncableFields();
$this->importOpportunityCrmFieldData($crmData, $dealInsightsFields, $opportunity->id);
return $opportunity;
}
/**
* @param array<string, mixed> $opportunityData
* @param string[] $dealInsightsFields
*/
public function importOpportunityCrmFieldData(
array $opportunityData,
array $dealInsightsFields,
int $opportunityId
): void {
foreach ($dealInsightsFields as $fieldName) {
$field = $this->config->fields()->with('entities')
->where('crm_provider_id', $fieldName)
->where('object_type', Field::OBJECT_OPPORTUNITY)
->first();
if (! $field instanceof Field) {
$this->logger->warning('Field not found', [
'field' => $fieldName,
'opportunity_id' => $opportunityId,
]);
continue;
}
$entity = $field->getEntities()->first();
if (! $entity instanceof LayoutEntity) {
continue;
}
$fieldValue = $this->extractFieldValue($opportunityData, $fieldName);
$normalizedValue = $this->normalizeValue($field->getType(), (string) $fieldValue, true);
$field->data()
->updateOrCreate([
'crm_layout_entity_id' => $entity->id,
'crm_field_id' => $field->id,
'object_type' => 'opportunity',
'object_id' => $opportunityId,
], ['value' => $normalizedValue])
;
}
}
/**
* @inheritdoc
*/
public function syncContacts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
$cpContacts = $this->copperClient->contacts()->paginate([
'minimum_interaction_date' => $since->timestamp,
'sort_by' => 'date_modified',
]);
foreach ($cpContacts as $cpContact) {
// Only sync if previously imported.
if ($this->hasContact($cpContact['id'])) {
$this->importContact($cpContact);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
throw $exception;
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncContact(string $crmId): ?Contact
{
$cpContact = $this->copperClient->contacts()->find($crmId);
if (empty($cpContact)) {
return null;
}
return $this->importContact($cpContact);
}
/**
* @inheritdoc
*/
private function importContact($crmData): Contact
{
$account = null;
if ($crmData['company_id']) {
$account = $this->team
->crm
->accounts()
->where('crm_provider_id', (string) $crmData['company_id'])
->first();
if ($account === null) {
$account = $this->syncAccount($crmData['company_id']);
}
}
$countryCode = null;
if (empty($crmData['address']) === false && $crmData['address']['country']) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$mobilePhone = $parsedNumber = null;
foreach ($crmData['phone_numbers'] as $phoneNumber) {
if ($phoneNumber['category'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);
} else {
$parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);
}
}
$email = null;
if (empty($crmData['emails']) === false) {
$email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'account_id' => $account->id ?? null,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => $crmData['name'],
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'mobile_phone' => $mobilePhone ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'title' => $crmData['title'],
'country_code' => $countryCode,
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Contact::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
private function buildContactPhone(?string $countryCode, ?string $number): ?array
{
if ($number) {
// Trim to our width and attempt to parse it.
$number = mb_strimwidth($number, 0, 25);
$parsedNumber = parsePhoneNumber($countryCode, $number);
} else {
$parsedNumber = [];
}
return $parsedNumber;
}
private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string
{
return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
$organization = $this->copperClient->organisation()->all();
if ($this->config->crm_provider_id !== $organization['id']) {
$this->config->update(['crm_provider_id' => $organization['id']]);
}
}
private function syncCustomFields(): void
{
foreach ($this->getFieldTypes() as $fieldType) {
$currentFields = $this->getFields($fieldType);
foreach ($currentFields as $field) {
/** @var Field $field */
$field = $this->config->fields()->updateOrCreate([
'crm_provider_id' => $field['name'],
'object_type' => $fieldType,
], [
'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),
'type' => $field['type'],
]);
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
}
$this->config->save();
}
protected function getFieldTypes(): array
{
return [
parent::OBJECT_TASK,
parent::OBJECT_LEAD,
parent::OBJECT_ACCOUNT,
parent::OBJECT_CONTACT,
parent::OBJECT_OPPORTUNITY,
];
}
/**
* @inheritdoc
*/
public function syncProfiles(?User $userToSearch = null): ?Profile
{
$profiles = $this->copperClient->users()->all();
foreach ($profiles as $profile) {
$user = $this->userRepository->findByTeamAndEmailAddress($this->team, $profile['email'], onlyActive: true);
// Only import profiles for users we have locally.
if ($user) {
$profile = $user->crmProfile()->updateOrCreate([
'crm_configuration_id' => $this->config->id,
'crm_provider_id' => $profile['id'],
]);
if ($userToSearch && $userToSearch->id === $user->id) {
return $profile;
}
}
}
return null;
}
/**
* @inheritdoc
*/
public function syncProfileFields(): void
{
$fieldTypes = [
'task',
'lead',
'account',
'contact',
'opportunity',
];
foreach ($fieldTypes as $fieldType) {
try {
$currentFields = $this->getFields(ucfirst($fieldType));
$newFields = array_column($currentFields, 'name');
$changedFields = array_merge(
array_diff($this->profile->getFieldsAsArray($fieldType), $newFields),
array_diff($newFields, $this->profile->getFieldsAsArray($fieldType))
);
if (\count($changedFields) > 0) {
$fields = implode(',', $newFields);
$this->logger->debug(
ucfirst($fieldType)
. ' fields changed from '
. $this->profile->{$fieldType . '_fields'}
. ' to: '
. $fields
);
$this->profile->{$fieldType . '_fields'} = $fields;
}
} catch (\Exception $exception) {
$this->logger->error('No access to ' . $fieldType . ' object, skipping...');
continue;
}
}
$this->profile->save();
}
/**
* @inheritdoc
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
$scopeValues = array_map(fn ($scope) => is_string($scope) ? $scope : $scope->value, $scopes);
$cacheKey = sprintf('copper-search-%d-%s-%s-%d-%d', $this->team->id, $name, implode('-', $scopeValues), $count, $offset);
return Cache::remember($cacheKey, 300, function () use ($name, $scopes, $count, $offset) {
// Try local search first
$localResults = $this->searchLocally($name, $scopes, $count, $offset);
// If no local results, fall back to remote API search
if (empty($localResults)) {
return $this->searchRemotely($name, $scopes, $count, $offset);
}
return $localResults;
});
}
/**
* @inheritdoc
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
$contact = null;
$account = null;
if ($crmAccountId) {
$account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();
if ($account === null) {
$account = $this->syncAccount($crmAccountId);
}
}
if ($crmContactId) {
$contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();
if ($contact === null) {
$contact = $this->syncContact($crmContactId);
}
}
if ($contact || $account) {
if ($contact && $account === null) {
$account = $contact->account;
}
if ($account === null) {
return [];
}
$params = [
'company_ids' => [$account->crm_provider_id],
'status_ids' => [0], // The integer values are 0, 1, 2, 3, for "Open", "Won", "Lost", and "Abandoned".
'sort_by' => 'date_modified',
'sort_direction' => 'desc',
];
switch ($this->config->opportunity_assignment_rule) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['sort_by'] = 'date_modified';
$params['sort_direction'] = 'desc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['sort_by'] = 'date_created';
$params['sort_direction'] = 'desc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['sort_by'] = 'date_created';
$params['sort_direction'] = 'asc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['sort_by'] = 'date_modified';
$params['sort_direction'] = 'desc';
$params['status_ids'] = [0, 1, 2, 3];
}
$cpOpportunities = $this->copperClient->opportunities()->search($params);
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
foreach ($cpOpportunities as $cpOpportunity) {
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', (string) $cpOpportunity['pipeline_id'])
->first();
if ($businessProcess === null) {
// Import it.
$businessProcess = $this->importStages(
[Stage::TYPE_OPPORTUNITY],
$cpOpportunity['pipeline_stage_id']
);
}
$stage = $businessProcess
->stages()
->where('crm_provider_id', (string) $cpOpportunity['pipeline_stage_id'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $cpOpportunity['pipeline_stage_id']);
}
$recordType = $businessProcess->recordTypes()->first();
$record = [
'crmId' => $cpOpportunity['id'],
'name' => $cpOpportunity['name'],
'value' => currency_format($cpOpportunity['monetary_value'], $cpOpportunity['monetary_unit']),
'won' => $cpOpportunity['status'] === 'Won',
'stage' => [
'id' => $stage->id_string,
'name' => $stage->name,
],
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
if ($ownerId && isset($cpOpportunity['assignee_id']) && $cpOpportunity['assignee_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
}
if (! empty($ownerData)) {
return $ownerData;
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array
{
$data = $cpTasks = [];
switch ($objectType) {
case 'lead':
$cpTasks = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->relatedTasks($objectId)
);
break;
case 'account':
$cpTasks = $this->copperClient->accounts()->relatedTasks($objectId);
break;
case 'contact':
if ($opportunityId) {
$cpTasks = $this->copperClient->opportunities()->relatedTasks($opportunityId);
} elseif ($objectType === 'contact') {
$cpTasks = $this->copperClient->contacts()->relatedTasks($objectId);
}
break;
}
foreach ($cpTasks as $cpTask) {
// We only get the ID itself returned, so pull out the full object.
try {
$cpTask = $this->copperClient->tasks()->find($cpTask['id']);
} catch (Exception $exception) {
$this->logger->error('[Copper] Error fetching task', [
'resource_id' => $cpTask['id'],
'error' => $exception->getMessage(),
]);
continue;
}
// Only allow open tasks.
if ($cpTask['status'] === 'Open') {
$data[] = [
'crmId' => $cpTask['id'],
'subject' => $cpTask['name'],
'due' => $cpTask['due_date']
? Carbon::createFromTimestamp($cpTask['due_date'])->format('Y-m-d\TH:i:sO')
: null,
'type' => null,
];
}
}
return $data;
}
/**
* Try to find email address in CRM service
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$cpObjectType = 'contact';
$cpObjects = $this->copperClient->contacts()->search([
'emails' => $email,
'sort_by' => 'date_modified',
'sort_direction' => 'desc',
]);
if (empty($cpObjects)) {
$cpObjectType = 'lead';
$cpObjects = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->search([
'emails' => ...
|
45363
|
NULL
|
NULL
|
NULL
|
|
45364
|
1625
|
19
|
2026-05-14T14:32:53.884487+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769173884_m1.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
PhpStormFileEditViewNavigateCodeLaravelRefactorRun PhpStormFileEditViewNavigateCodeLaravelRefactorRunToolsGitWindowHelp•FV faVsco.jsv* #12066 on JY-20725-handle-HS-search-rate-limit K vabl19HandleHubspotRateLimitTest100% C* :8• Thu 14 May 17:32:53QProjectv=custom.logAutomatedReportGenerated.phpTrackAutomatedReportGeneratedEvent.phpPlaybackController.php© FieldDefinitions.phpUserAutomatedReportsController.phpPlanhatService.phpAutomatedReportResult.phpSendReportJob.php© FieldValueConverter.php• DeleteCrmEntityTrait.phpDeleteAccountJob.php© ImportActivityTypes.phpT WriteCrmTrait.php© Service.php© DecorateActivity.php> D CrmObjects© Salesforce/Service.php© LogActivityTrait.phpPipedrive/Service.phpClose/Service.phpCopper/Service.php X• DecorateActivity© PlainTextDecorateActivity.phpT ActivityPlaybookTrait.php© CrmHelperRepository.phpAccountController.php18© BaseDecorateActivity.php© PlainTextDecorateActivity.plT IntegrationAppTrait.php.env.stagingE.env© DetachActivityObject.phpRematchActivityOnCrmObjectDetach.php> Dummy© MatchActivityCrmData.phpv Helpers52Client.phpclass Service extends BaseService implements© HubspotPaginationService.php© HandleHubspotRateLimit.phpA11 A72 X1 X4 ^T ActivityPlaybookTrait.php© Arraylterator.phpT ConnectionStateTrait.php16621663* Othrows CrmException© CrmHelperRepository.php*/1 usage© FilterJoinedParticipants.php1664private function buildCallPayload(Activity $activity): Activity© OpportunitySyncableFieldsT 1665v D Hubspot1666• AccountSyncStrategy1667> OJ Actions |1668• ContactSyncStrategy1669> ODTO1670> D Fields1671try {if (Sadtivity->crm_provider_id) {// The activity should be logged under the existing Task (not Activity).SnewActivityType = Sthis->getCrmType(Sactivity->category);if ($newActivityType === null) {$message = sprintf( format: '[Copper] invalid CRM Custom Activity Type: %s', $activity->caz224> 0J Journal1672D Metadata1673throw new CrmException(Smessage,code: 400):v C OpportunitySyncStrategy1674› D Concerns1675© HubspotLastModifiedByF 1676© HubspotLastModifiedCre1677© HubspotLastModifiedCre1678$this->copperClient->tasks()->update($activity->crm_provider_id, ['status'= 'Completed','custom_activity_type_id' => $newActivityType->valve,'details' => $this->generateActivityDescription(Sactivity),© HubspotLastModifiedOpe 1679© HubspotLastModifiedSyn16801):j else {© HubspotSingleSyncStrate1681© HubspotSyncStrategyBa:1682it.(Sthis-getCrmType(Sactivitx-2categ0cX2mm.nulWnf$message = sprintf( format:'[Copper] Invalid CRM Activity Type: %s',Sactivity->category→© HubspotWebhookBatchS1683v [ Pagination1684throw new CrmException($message,code: 400);© HubspotPaginationServic1685=A Daninstinnfanfin nhn1686Workspace associated with branch 'JY-20725-handle-HS-search-rate-limit' has been restored // Rollback // Configure... (today 16:17)=laravel.logSF [jiminny@localhost]A HS_local [jiminny@localho:W4 console [QAI PROD] X4 console [PROD]A console (EU]DGo jiminny084143 ×4 л215|•m_layout_id =2162,1661,66799,66217218219id = 33;=220=221==222=223id THEN '(own=225=226= 227228-229=230hubspat":-231: 232233 V= 11512582;234-W Windsurf Teams1667:20UTF-8Co 4 spaces...
|
NULL
|
-7172210613695292373
|
NULL
|
click
|
ocr
|
NULL
|
PhpStormFileEditViewNavigateCodeLaravelRefactorRun PhpStormFileEditViewNavigateCodeLaravelRefactorRunToolsGitWindowHelp•FV faVsco.jsv* #12066 on JY-20725-handle-HS-search-rate-limit K vabl19HandleHubspotRateLimitTest100% C* :8• Thu 14 May 17:32:53QProjectv=custom.logAutomatedReportGenerated.phpTrackAutomatedReportGeneratedEvent.phpPlaybackController.php© FieldDefinitions.phpUserAutomatedReportsController.phpPlanhatService.phpAutomatedReportResult.phpSendReportJob.php© FieldValueConverter.php• DeleteCrmEntityTrait.phpDeleteAccountJob.php© ImportActivityTypes.phpT WriteCrmTrait.php© Service.php© DecorateActivity.php> D CrmObjects© Salesforce/Service.php© LogActivityTrait.phpPipedrive/Service.phpClose/Service.phpCopper/Service.php X• DecorateActivity© PlainTextDecorateActivity.phpT ActivityPlaybookTrait.php© CrmHelperRepository.phpAccountController.php18© BaseDecorateActivity.php© PlainTextDecorateActivity.plT IntegrationAppTrait.php.env.stagingE.env© DetachActivityObject.phpRematchActivityOnCrmObjectDetach.php> Dummy© MatchActivityCrmData.phpv Helpers52Client.phpclass Service extends BaseService implements© HubspotPaginationService.php© HandleHubspotRateLimit.phpA11 A72 X1 X4 ^T ActivityPlaybookTrait.php© Arraylterator.phpT ConnectionStateTrait.php16621663* Othrows CrmException© CrmHelperRepository.php*/1 usage© FilterJoinedParticipants.php1664private function buildCallPayload(Activity $activity): Activity© OpportunitySyncableFieldsT 1665v D Hubspot1666• AccountSyncStrategy1667> OJ Actions |1668• ContactSyncStrategy1669> ODTO1670> D Fields1671try {if (Sadtivity->crm_provider_id) {// The activity should be logged under the existing Task (not Activity).SnewActivityType = Sthis->getCrmType(Sactivity->category);if ($newActivityType === null) {$message = sprintf( format: '[Copper] invalid CRM Custom Activity Type: %s', $activity->caz224> 0J Journal1672D Metadata1673throw new CrmException(Smessage,code: 400):v C OpportunitySyncStrategy1674› D Concerns1675© HubspotLastModifiedByF 1676© HubspotLastModifiedCre1677© HubspotLastModifiedCre1678$this->copperClient->tasks()->update($activity->crm_provider_id, ['status'= 'Completed','custom_activity_type_id' => $newActivityType->valve,'details' => $this->generateActivityDescription(Sactivity),© HubspotLastModifiedOpe 1679© HubspotLastModifiedSyn16801):j else {© HubspotSingleSyncStrate1681© HubspotSyncStrategyBa:1682it.(Sthis-getCrmType(Sactivitx-2categ0cX2mm.nulWnf$message = sprintf( format:'[Copper] Invalid CRM Activity Type: %s',Sactivity->category→© HubspotWebhookBatchS1683v [ Pagination1684throw new CrmException($message,code: 400);© HubspotPaginationServic1685=A Daninstinnfanfin nhn1686Workspace associated with branch 'JY-20725-handle-HS-search-rate-limit' has been restored // Rollback // Configure... (today 16:17)=laravel.logSF [jiminny@localhost]A HS_local [jiminny@localho:W4 console [QAI PROD] X4 console [PROD]A console (EU]DGo jiminny084143 ×4 л215|•m_layout_id =2162,1661,66799,66217218219id = 33;=220=221==222=223id THEN '(own=225=226= 227228-229=230hubspat":-231: 232233 V= 11512582;234-W Windsurf Teams1667:20UTF-8Co 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
45363
|
1626
|
11
|
2026-05-14T14:32:51.284451+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769171284_m2.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
ActivityFilesLaterJiminny... ~@ jiminny-x-integrat ActivityFilesLaterJiminny... ~@ jiminny-x-integrati& platform-inner-team© Channels# ai-chapter# alertsi backend# bugscontusion-cllnia# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the people of iimi..• Direct messages8. A...• A3 62P. Galya Dimitrova Mvasil VasilevA. Stefka Stoyanova%: Todor Stamatovf. Mario GeorgievP. Nikolay Ivanov2o James Graham "2. Stoyan Tanev. Steliyan Georgiev. Petko Kashinski*. Lukas Kovali...a: Apps® ToastS lira Gloud6 Huddle with Aneliya Angelova& R. Aneliya Angelova •• Messagest Add canvasur FilesAneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук,нали?пои останалите скМі тоябва оъчно ла се въвелат.Lukas Kovalik 2:47 PMтряова да се за всички, някьде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova @ 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725X Preview insackt[HubSpot] Optimise CRM rematctC OpenReady for QA- MediumAA Aneliya AngelovaAs of today at 4:00 PM RetreshOpen in Jira+ SummariseLukas Kovalik 4:02 PMzean-iurwiniareelYou joined the huddle LIVE 4:06 PMAneliva Angelova is here toolAneliya Angelova 4:44 PM11512582Lukas Kovalik O 5:16 PMcurl --location "httns:ani.hubani.com/crm/v3/obiects/contacts/search--header 'Content-Type: application/json'\--header "Authorization: BearerC|Kvma?iMx7OINOM8kOFwrAowAcAkUAhIR24?A05D?xiVrIYMILuP6SA01Kwcmhr=n.v2 hytorDniMvDalYck-CMalovolNOM9kOFwrAUAcrkcaws-ThwRARIRAOF-ATFSAOFRAO-ROIEBAQUBEggBAQEBAYICFIґ7Au8O2Nwal9YW2CbCCxYvwngmSgNldTFSAFoAYABoAHAAeAA'\--data "{ "limit", 13'Message Aneliva Angelova+ AaIAl Notes: OffLeave~ (Q SearchDate ModifiedYesterdav at 13.36Yesterday at 13:36Yesterday at 13.30Yesterday at 13:34Yesterday at 13:34resterday at 15.5sYesterdav at 13:3kYesterday at 13:32Yesterday at 13.31Yesterday at 13:31Yesterday at 13:30resterday at 15.30Yesterdav at 13:29Yesterday at 13:29Yesterday at 13:28Yesterday at 13:28Yesterday at 13:27resterday at 13-40Yesterdav at 13:26Yesterday at 13:25Yesterday at 13:25Yesterday at 13:24Yesterday at 13:24Yesterday at 13.22Yesterdav at 13:21Yesterday at 13:20Yesterday at 13:19Yesterday at 13.18Yecterdav at 12:19Yesterday at 13-1/Yesterdav at 13:16Yesterday at 13:16Yesterday at 13:15Yecterdav at 12:1/Yesterday at 13:14Yesterday at 13.13Yecterdav at 13:10Yesterday at 13:12Yesterday at 13:11Yesterday at 13:11Yesterday at 13:10Yesterday at 13.10Yecterdav at 12:091Yesterday at 13:09Yesterdav at 13:0823K:MPEG-4 movie9KBMPEG-4 movie13 KB16 Kb17 KEMPEG-4 movieMPEG-4 movie29 KB6 KBMPE0"4 movie12 K:9 KBMPEG-4 movie7 KBMP2G-4 movie37 KBMPEG-4 movie10 KBI KDMPEG"4 movie8 KE9KBMPEG-4 movie8 KB72 KBMPEG-4 movie14 KBMPEG-4 movie13 KB9KBMPEG-4 movie18 KEMPEG-4 movie12 KBMPEG-4 movie10 KB16 K:MPEG-4 movie6 KBMPEG-4 movie12 KBMPEG-4 movie23 KBMPEG-4 movie8 KBMPEG-4 movie6 KBMPEG-4 movie16 K:11 KBMPEG-4 movie20 KBMPEG-4 movie21 KPMPEG-4 movie10 KB MPEG-4 movie7 KBMPEG-4 movie5 KB1MPEG-4 movie11 KBMPEG-4 movie26 KB111 KB102 KRMPEG-4 movieMDEG-A movie88 KB59 KBMPEG-4 movie08 KBIMPEG-A movie97 KB MPEG-4 movie66 KB44 KB02 KpMPEG-4 movieMPEG-4 movie78 KB50 KBMPEG-4 movie58 KГMPEG-A movid27 KBMPEG-4 movie7 KB12K8MPEG-4 movieFavouritesE jiminny© Recents* ApplicationsiCloudiCloud Drive228 Sync folderQ DXP4800PLUS-B5FA@ Network|• CRMI• Orange• Red• Yellow• Green• Purple•) All lags..lohlDownloadsNameLoom.pkgAlfred copv.alfredoreterencesB KeychronAssist-1.0.2 (1).dmgA Keychron Assist-1.0.2.dmgmazanoke-images-yWJo.zioPhotos-3-001.zip→mage U.loge1 Orioninstaller.dmaimage.jpg- image (2).1pc• ПО-22221726037035-004-001_ORGES.pdf• %D0%9F%D0%9E-22221726037035-004-001_archive.zipПO-22221726037035-004-001_archive (1).zipD report(2) xmlAltred copy2.altredoreterences05012026_0000000026574472_ SWIFT_OB70501260015890.pdf27022026_0000000026574472_SWIFT_OB72702260049200.pdf= 03042026 [CREDIT_CARD] SWIFT [CREDIT_CARD].001B reporti) xm=pdt.odipdf-1.pdfD pdf-2.pdf-pdf-5.pd1= ndf-1 ndipdf-3.pdfKoválik Family Tree.gedbitwarden export 20251031122528.isonKoválik Family Tree.zip*macOS Storage_Cleanup.mdal favicon icofirst_aid_notes_complete.docxrenortl2).esvconfig.ymlIteration run Search HS.postman_collection.jsonm licence hettertouchtoolMariusHosting Config.json1ooks-891a6503-bbb7-4b2b-9c3.csv•AlfredwPmazanoko.imnaoc.YWIfана Ковалик.jpg•искане даниел Ковалик..pa• Фактура Март Даниел Ковалик.jpс• Фактура Април Даниел Ковалик.jpg• Dhotac 2.001Q SearchKind00,4 MDinstdlle..dckage55.9 MBAlfred...ferences10,1 MBDisk Image10,1 MBDisk ImageIL MBLiP archive6,6 MBZIP archive2,5 MB PDF Document2,5 MBJreo lmage2.2 MBDisk Image2,2 MB PDF Document2 MBJPEG image1,9 MBJPEG imaqe192 KBPDF Document140 KbZIP archive148 KВZIP archivel148 KBZIP archive122 KBXML document111 KBAlfred...ferences94 KBPDF Document92 KBPDr DocumentPDF Document91 KB91 KB30 KB29 KBXML documentPDF Document28 KB28 KR28 KB27 KB14 KB11 KB6 KB6KB5KR4 KB3 KBPDF DocumentPDE DocumentDocumentJSONICSV DocumentZIP archiveMarkdo…..umentWindo...n imageword ..cumentCSV Document2 KBYAML document1 KBcSV Document928 byteshttlicence183 bytesZero butesJSONAlfred.. ferencesZero bytes1,9 MB1,8 MB17 MB1,7 MBFoldeColdorJPEG imageJPEG ImageJPEG imageJPEG imageColdo1 of 58 selected, 8.5 GB availab!i• Inu 14 May 1/.32:00Date AddedIs Mdl ZUzo dl 19:4530 Jan 2026 at 12:3617 Mar 2026 at 20:2717 Mar 2026 at 20:26Z3 Aor 2020 al 13:0229 Jan 2026 at 15:2019 Dec 2025 at 10:1619 Dec 2025 at 12:238 Aor 2026 at 20:3519 Dec 2025 at 10:2919 Dec 2025 at 12:1819 Dec 2025 at 12:4026 Mar 2026 at 11:2410 May 2026 at 13:5326 Mar 2026 at 11:2426 Mar 2026 at 11:2426 Mar 2026 at 11:2310 May 2026 at 14:3730 Jan 2026 at 12:3713 Feb 2026 at 11:54Z3 Apr 2026 at 13.0823 Aor 2026 at 13:0810 May 2026 at 13:5410 May 2026 at 14:3710 May 2026 at 13:4910 May 2026 at 13:5010 May 2026 at 13:5110 Mav 2026 at 12:51110 May 2026 at 13:5019 Dec 2025 at 11:3431 Oct 2025 at 12:2525 Nov 2025 at 17:596 Mar 2026 at 11.2224 Anr 2026 at 16:5220 Oct 2025 at 11:0218 Mar 2026 at 15:29• Mav 2026 at 11:09129 Oct 2025 at 19:329 May 2026 at 10:0418 Mar 2026 at 11:5510 May 2026 at 13:5712 Jun 2025 at 19:0430 Jan 2026 at 12:3630 Jan 2026 at 12:3616 Oct 2025 aт 16:0123 Apr 2026 at 13:0223 Apr 2026 at 13:0223 Apr 2026 at 13:0222 Anr 2026 at 12:0223 Apr 2026 at 13:0229 Jan 2026 at 15:20...
|
NULL
|
-4264175401579078456
|
NULL
|
click
|
ocr
|
NULL
|
ActivityFilesLaterJiminny... ~@ jiminny-x-integrat ActivityFilesLaterJiminny... ~@ jiminny-x-integrati& platform-inner-team© Channels# ai-chapter# alertsi backend# bugscontusion-cllnia# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the people of iimi..• Direct messages8. A...• A3 62P. Galya Dimitrova Mvasil VasilevA. Stefka Stoyanova%: Todor Stamatovf. Mario GeorgievP. Nikolay Ivanov2o James Graham "2. Stoyan Tanev. Steliyan Georgiev. Petko Kashinski*. Lukas Kovali...a: Apps® ToastS lira Gloud6 Huddle with Aneliya Angelova& R. Aneliya Angelova •• Messagest Add canvasur FilesAneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук,нали?пои останалите скМі тоябва оъчно ла се въвелат.Lukas Kovalik 2:47 PMтряова да се за всички, някьде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova @ 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725X Preview insackt[HubSpot] Optimise CRM rematctC OpenReady for QA- MediumAA Aneliya AngelovaAs of today at 4:00 PM RetreshOpen in Jira+ SummariseLukas Kovalik 4:02 PMzean-iurwiniareelYou joined the huddle LIVE 4:06 PMAneliva Angelova is here toolAneliya Angelova 4:44 PM11512582Lukas Kovalik O 5:16 PMcurl --location "httns:ani.hubani.com/crm/v3/obiects/contacts/search--header 'Content-Type: application/json'\--header "Authorization: BearerC|Kvma?iMx7OINOM8kOFwrAowAcAkUAhIR24?A05D?xiVrIYMILuP6SA01Kwcmhr=n.v2 hytorDniMvDalYck-CMalovolNOM9kOFwrAUAcrkcaws-ThwRARIRAOF-ATFSAOFRAO-ROIEBAQUBEggBAQEBAYICFIґ7Au8O2Nwal9YW2CbCCxYvwngmSgNldTFSAFoAYABoAHAAeAA'\--data "{ "limit", 13'Message Aneliva Angelova+ AaIAl Notes: OffLeave~ (Q SearchDate ModifiedYesterdav at 13.36Yesterday at 13:36Yesterday at 13.30Yesterday at 13:34Yesterday at 13:34resterday at 15.5sYesterdav at 13:3kYesterday at 13:32Yesterday at 13.31Yesterday at 13:31Yesterday at 13:30resterday at 15.30Yesterdav at 13:29Yesterday at 13:29Yesterday at 13:28Yesterday at 13:28Yesterday at 13:27resterday at 13-40Yesterdav at 13:26Yesterday at 13:25Yesterday at 13:25Yesterday at 13:24Yesterday at 13:24Yesterday at 13.22Yesterdav at 13:21Yesterday at 13:20Yesterday at 13:19Yesterday at 13.18Yecterdav at 12:19Yesterday at 13-1/Yesterdav at 13:16Yesterday at 13:16Yesterday at 13:15Yecterdav at 12:1/Yesterday at 13:14Yesterday at 13.13Yecterdav at 13:10Yesterday at 13:12Yesterday at 13:11Yesterday at 13:11Yesterday at 13:10Yesterday at 13.10Yecterdav at 12:091Yesterday at 13:09Yesterdav at 13:0823K:MPEG-4 movie9KBMPEG-4 movie13 KB16 Kb17 KEMPEG-4 movieMPEG-4 movie29 KB6 KBMPE0"4 movie12 K:9 KBMPEG-4 movie7 KBMP2G-4 movie37 KBMPEG-4 movie10 KBI KDMPEG"4 movie8 KE9KBMPEG-4 movie8 KB72 KBMPEG-4 movie14 KBMPEG-4 movie13 KB9KBMPEG-4 movie18 KEMPEG-4 movie12 KBMPEG-4 movie10 KB16 K:MPEG-4 movie6 KBMPEG-4 movie12 KBMPEG-4 movie23 KBMPEG-4 movie8 KBMPEG-4 movie6 KBMPEG-4 movie16 K:11 KBMPEG-4 movie20 KBMPEG-4 movie21 KPMPEG-4 movie10 KB MPEG-4 movie7 KBMPEG-4 movie5 KB1MPEG-4 movie11 KBMPEG-4 movie26 KB111 KB102 KRMPEG-4 movieMDEG-A movie88 KB59 KBMPEG-4 movie08 KBIMPEG-A movie97 KB MPEG-4 movie66 KB44 KB02 KpMPEG-4 movieMPEG-4 movie78 KB50 KBMPEG-4 movie58 KГMPEG-A movid27 KBMPEG-4 movie7 KB12K8MPEG-4 movieFavouritesE jiminny© Recents* ApplicationsiCloudiCloud Drive228 Sync folderQ DXP4800PLUS-B5FA@ Network|• CRMI• Orange• Red• Yellow• Green• Purple•) All lags..lohlDownloadsNameLoom.pkgAlfred copv.alfredoreterencesB KeychronAssist-1.0.2 (1).dmgA Keychron Assist-1.0.2.dmgmazanoke-images-yWJo.zioPhotos-3-001.zip→mage U.loge1 Orioninstaller.dmaimage.jpg- image (2).1pc• ПО-22221726037035-004-001_ORGES.pdf• %D0%9F%D0%9E-22221726037035-004-001_archive.zipПO-22221726037035-004-001_archive (1).zipD report(2) xmlAltred copy2.altredoreterences05012026_0000000026574472_ SWIFT_OB70501260015890.pdf27022026_0000000026574472_SWIFT_OB72702260049200.pdf= 03042026 [CREDIT_CARD] SWIFT [CREDIT_CARD].001B reporti) xm=pdt.odipdf-1.pdfD pdf-2.pdf-pdf-5.pd1= ndf-1 ndipdf-3.pdfKoválik Family Tree.gedbitwarden export 20251031122528.isonKoválik Family Tree.zip*macOS Storage_Cleanup.mdal favicon icofirst_aid_notes_complete.docxrenortl2).esvconfig.ymlIteration run Search HS.postman_collection.jsonm licence hettertouchtoolMariusHosting Config.json1ooks-891a6503-bbb7-4b2b-9c3.csv•AlfredwPmazanoko.imnaoc.YWIfана Ковалик.jpg•искане даниел Ковалик..pa• Фактура Март Даниел Ковалик.jpс• Фактура Април Даниел Ковалик.jpg• Dhotac 2.001Q SearchKind00,4 MDinstdlle..dckage55.9 MBAlfred...ferences10,1 MBDisk Image10,1 MBDisk ImageIL MBLiP archive6,6 MBZIP archive2,5 MB PDF Document2,5 MBJreo lmage2.2 MBDisk Image2,2 MB PDF Document2 MBJPEG image1,9 MBJPEG imaqe192 KBPDF Document140 KbZIP archive148 KВZIP archivel148 KBZIP archive122 KBXML document111 KBAlfred...ferences94 KBPDF Document92 KBPDr DocumentPDF Document91 KB91 KB30 KB29 KBXML documentPDF Document28 KB28 KR28 KB27 KB14 KB11 KB6 KB6KB5KR4 KB3 KBPDF DocumentPDE DocumentDocumentJSONICSV DocumentZIP archiveMarkdo…..umentWindo...n imageword ..cumentCSV Document2 KBYAML document1 KBcSV Document928 byteshttlicence183 bytesZero butesJSONAlfred.. ferencesZero bytes1,9 MB1,8 MB17 MB1,7 MBFoldeColdorJPEG imageJPEG ImageJPEG imageJPEG imageColdo1 of 58 selected, 8.5 GB availab!i• Inu 14 May 1/.32:00Date AddedIs Mdl ZUzo dl 19:4530 Jan 2026 at 12:3617 Mar 2026 at 20:2717 Mar 2026 at 20:26Z3 Aor 2020 al 13:0229 Jan 2026 at 15:2019 Dec 2025 at 10:1619 Dec 2025 at 12:238 Aor 2026 at 20:3519 Dec 2025 at 10:2919 Dec 2025 at 12:1819 Dec 2025 at 12:4026 Mar 2026 at 11:2410 May 2026 at 13:5326 Mar 2026 at 11:2426 Mar 2026 at 11:2426 Mar 2026 at 11:2310 May 2026 at 14:3730 Jan 2026 at 12:3713 Feb 2026 at 11:54Z3 Apr 2026 at 13.0823 Aor 2026 at 13:0810 May 2026 at 13:5410 May 2026 at 14:3710 May 2026 at 13:4910 May 2026 at 13:5010 May 2026 at 13:5110 Mav 2026 at 12:51110 May 2026 at 13:5019 Dec 2025 at 11:3431 Oct 2025 at 12:2525 Nov 2025 at 17:596 Mar 2026 at 11.2224 Anr 2026 at 16:5220 Oct 2025 at 11:0218 Mar 2026 at 15:29• Mav 2026 at 11:09129 Oct 2025 at 19:329 May 2026 at 10:0418 Mar 2026 at 11:5510 May 2026 at 13:5712 Jun 2025 at 19:0430 Jan 2026 at 12:3630 Jan 2026 at 12:3616 Oct 2025 aт 16:0123 Apr 2026 at 13:0223 Apr 2026 at 13:0223 Apr 2026 at 13:0222 Anr 2026 at 12:0223 Apr 2026 at 13:0229 Jan 2026 at 15:20...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
45361
|
1626
|
10
|
2026-05-14T14:32:45.610188+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769165610_m2.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
ActivityFilesLaterJiminny... ~@ jiminny-x-integrat ActivityFilesLaterJiminny... ~@ jiminny-x-integrati& platform-inner-team© Channels# ai-chapter# alertsi backend# bugscontusion-cllnia# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the people of iimi..• Direct messages8. A...• A3 62P. Galya Dimitrova Mvasil VasilevA. Stefka Stoyanova%: Todor Stamatovf. Mario GeorgievP. Nikolay Ivanov2o James Graham "2. Stoyan Tanev. Steliyan Georgiev. Petko Kashinski*. Lukas Kovali...a: Apps® ToastS lira Gloud6 Huddle with Aneliya Angelova& R. Aneliya Angelova •• Messagest Add canvasur FilesAneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук,нали?пои останалите скМі тоябва оъчно ла се въвелат.Lukas Kovalik 2:47 PMтряова да се за всички, някьде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova @ 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725X Preview insackt[HubSpot] Optimise CRM rematctC OpenReady for QA- MediumAA Aneliya AngelovaAs of today at 4:00 PM RetreshOpen in Jira+ SummariseLukas Kovalik 4:02 PMzean-iurwiniareelYou joined the huddle LIVE 4:06 PMAneliva Angelova is here toolAneliya Angelova 4:44 PM11512582Lukas Kovalik O 5:16 PMcurl --location "httns:ani.hubani.com/crm/v3/obiects/contacts/search--header 'Content-Type: application/json'\--header "Authorization: BearerC|Kvma?iMx7OINOM8kOFwrAowAcAkUAhIR24?A05D?xiVrIYMILuP6SA01Kwcmhr=n.v2 hytorDniMvDalYck-CMalovolNOM9kOFwrAUAcrkcaws-ThwRARIRAOF-ATFSAOFRAO-ROIEBAQUBEggBAQEBAYICFIґ7Au8O2Nwal9YW2CbCCxYvwngmSgNldTFSAFoAYABoAHAAeAA'\--data "{ "limit", 13'Message Aneliva Angelova+ AaIđ 0Pm~ (Q SearchDate ModifiedYesterdav at 13.36Yesterday at 13:35Yesterday at 13.34Yesterday at 13:34Yesterday at 13:33resterday at 15.5sYesterdav at 13:37Yesterday at 13:32Yesterday ar 13.31Yesterday at 13:30Yesterday at 13:30resterday at 15.4gYesterdav at 13:29Yesterday at 13:28Yesterday at 13:28Yesterday at 13:27Yesterday at 13:27resterday at 13-40Yesterdav at 13:25Yesterday at 13:25Yesterday at 13:24Yesterday at 13:24Yesterday at 13:23Yesterday at 13.21Yesterdav at 13:21Yesterday at 13:20Yesterday at 13:20Yesterday at 13:19Yesterday at 13:19Yesterday at 13.18Vecterdav at 12:17Yesterday at 13:16Yesterdav at 13:16Yesterday at 13:15Yesterday at 13:14Yecterdav at 12:1/Yesterday at 13:13Yesterday at 13.13Yecterdav at 12:12Yesterday at 13:12Yesterday at 13:11Yesterday at 13:10Yesterday at 13:10Yesterday at 13.09Yecterdav at 12:091Yesterday at 13:08Yesterdav at 13:07MPEG-4 movie13 KBMPEG-4 movie16 KB1/ Kb29 KBMPEG-4 movieMPEG-4 movie6 KB12 KBMPE0"4 movie9 K:7 KBMPEG-4 movie8 KB37 KBMP2G-4 movie10 KBMPEG-4 movie7 KBMPEG"4 movie9K:8KBMPEG-4 movie72 KB14 K8|13 KRIMPEG-4 movieMPEG-4 movie9 KB18 KBMPEG-4 movie12 KEMPEG-4 movie10 KBMPEG-4 movie16 KB6 KB1MPEG-4 movie6 KBMPEG-4 movie12 KB23 KBMPEG-4 movie8 KEMPEG-4 movie6 KBMPEG-4 movie6 KBMPEG-4 movie11 K:MPEG-4 movie11 KBMPEG-4 movie34 KBMPEG-4 movie10 KPMPEG-4 movie7 KBMPEG-4 movie5 KBMPEG-4 movie11 KBIMPEG-4 movie26 KBMPEG-4 movie111 KB102 KBRR KRMPEG-4 movieMDEG-A movie59 KB98 KBMPEG-4 movie07 K:MPEG-A movie66 KB MPEG-4 movie44 KB93 KB79 KpMPEG-4 movieMPEG-4 movie58 KBMPEG-4 movie27 KP7 KBMPEG-4 movie12 KB32 K8MPEG-4 movieAl Notes: OffLeave• 0FavouritesE jiminny© Recents* ApplicationsiCloudiCloud Drive228 Sync folderQ DXP4800PLUS-B5FA@ Network|• CRMI• Orange• Red• Yellow• Green• Purple•) All lags..lohlDownloadsNameLoom.pkgAlfred copv.alfredoreterencesB KeychronAssist-1.0.2 (1).dmgA Keychron Assist-1.0.2.dmgmazanoke-images-yWJo.zioPhotos-3-001.zipD Transcript.pdf→mage U.loge1 Orioninstaller.dmaimage.jpg- image (2).1pc• ПО-22221726037035-004-001_ORGES.pdf• %D0%9F%D0%9E-22221726037035-004-001_archive.zipПO-22221726037035-004-001_archive (1).zip• repon 4).XmAltred copy2.altredoreterences05012026_0000000026574472_ SWIFT_OB70501260015890.pdf27022026_0000000026574472_SWIFT_OB72702260049200.pdf= 03042026 [CREDIT_CARD] SWIFT [CREDIT_CARD].001B reporti) xm=pdt.odipdf-1.pdfD pdf-2.pdf-pdf-5.pd1= ndf-1 ndipdf-3.pdfKoválik Family Tree.gedbitwarden export 20251031122528.isonKoválik Family Tree.zip*macOS Storage_Cleanup.mdal favicon icofirst_aid_notes_complete.docxrenortl2).esvconfig.ymlIteration run Search HS.postman_collection.jsonm licence bettertouchtoalMariusHosting Config.json1ooks-891a6503-bbb7-4b2b-9c3.csv•Alfredmazanoke-images-YWJ6ана Ковалик.jpg•искане даниел Ковалик..pa• Фактура Март Даниел Ковалик.jрс• Фактура Април Даниел Ковалик.jpg• Dhotac 2.001Q SearchKind00,4 MDinstdlle..dckage55.9 MBAlfred...ferences10,1 MBDisk Image10,1 MBDisk ImageIL MBLiP archive6,6 MBZIP archive2,5 MB PDF Document2,5 MBJreo lmage2.2 MBDisk Image2,2 MB PDF Document2 MBJPEG image1,9 MBJPEG imaqe192 KBPDF Document140 KbZIP archive148 KВ148 KB122 KB111 KB94 KBZIP archivelZIP archiveXML documentAlfred...ferencesPDF Document92 KBPDr DocumentK:91 KB91 KB30 KB29 KBPDF DocumentXML documentPDF Document28 KBPDF Document28 KR28 KB27 KB14 KB11 KB6 KB6KBPDE DocumentDocumentJSONICSV DocumentZIP archiveMarkdo…..ument5KRWindo...n image4 KB3 KBword ..cumentCSV Document2 KBYAML document1 KBcSV Document928 byteshttlicence183 bytesZero butesJSONAlfred.. ferencesZero bytesFolde1,9 MB1,8 MB17 MB1,7 MBColdorJPEG imageJPEG ImageIPEG imadeJPEG imageColdo1 of 58 selected, 8.5 GB availab!i• Inu 14 Mау 1/•32.42Date AddedIs Mdl ZUzo dl 19:4530 Jan 2026 at 12:3617 Mar 2026 at 20:2717 Mar 2026 at 20:26Z3 Aor 2020 al 13:0229 Jan 2026 at 15:2019 Dec 2025 at 10:1619 Dec 2025 at 12:238 Aor 2026 at 20:3519 Dec 2025 at 10:2919 Dec 2025 at 12:1819 Dec 2025 at 12:4026 Mar 2026 at 11:2410 May 2026 at 13:5326 Mar 2026 at 11:2426 Mar 2026 at 11:2426 Mar 2026 at 11:2310 May 2026 at 14:3730 Jan 2026 at 12:3713 Feb 2026 at 11:54Z3 Apr 2026 at 13.0823 Aor 2026 at 13:0810 May 2026 at 13:5410 May 2026 at 14:3710 May 2026 at 13:4910 May 2026 at 13:5010 May 2026 at 13:5110 Mav 2026 at 12:51110 May 2026 at 13:5019 Dec 2025 at 11:3431 Oct 2025 at 12:2525 Nov 2025 at 17:596 Mar 2026 at 11.2224 Anr 2026 at 16:5220 Oct 2025 at 11:0218 Mar 2026 at 15:29• Mav 2026 at 11:09129 Oct 2025 at 19:329 May 2026 at 10:0418 Mar 2026 at 11:5510 May 2026 at 13:5712 Jun 2025 at 19:0430 Jan 2026 at 12:3630 Jan 2026 at 12:3616 Oct 2025 aт 16:0123 Apr 2026 at 13:0223 Apr 2026 at 13:0223 Apr 2026 at 13:0222 Anr 2026 at 12:0223 Apr 2026 at 13:0229 Jan 2026 at 15:20...
|
NULL
|
-4760999809465567111
|
NULL
|
click
|
ocr
|
NULL
|
ActivityFilesLaterJiminny... ~@ jiminny-x-integrat ActivityFilesLaterJiminny... ~@ jiminny-x-integrati& platform-inner-team© Channels# ai-chapter# alertsi backend# bugscontusion-cllnia# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the people of iimi..• Direct messages8. A...• A3 62P. Galya Dimitrova Mvasil VasilevA. Stefka Stoyanova%: Todor Stamatovf. Mario GeorgievP. Nikolay Ivanov2o James Graham "2. Stoyan Tanev. Steliyan Georgiev. Petko Kashinski*. Lukas Kovali...a: Apps® ToastS lira Gloud6 Huddle with Aneliya Angelova& R. Aneliya Angelova •• Messagest Add canvasur FilesAneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук,нали?пои останалите скМі тоябва оъчно ла се въвелат.Lukas Kovalik 2:47 PMтряова да се за всички, някьде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova @ 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725X Preview insackt[HubSpot] Optimise CRM rematctC OpenReady for QA- MediumAA Aneliya AngelovaAs of today at 4:00 PM RetreshOpen in Jira+ SummariseLukas Kovalik 4:02 PMzean-iurwiniareelYou joined the huddle LIVE 4:06 PMAneliva Angelova is here toolAneliya Angelova 4:44 PM11512582Lukas Kovalik O 5:16 PMcurl --location "httns:ani.hubani.com/crm/v3/obiects/contacts/search--header 'Content-Type: application/json'\--header "Authorization: BearerC|Kvma?iMx7OINOM8kOFwrAowAcAkUAhIR24?A05D?xiVrIYMILuP6SA01Kwcmhr=n.v2 hytorDniMvDalYck-CMalovolNOM9kOFwrAUAcrkcaws-ThwRARIRAOF-ATFSAOFRAO-ROIEBAQUBEggBAQEBAYICFIґ7Au8O2Nwal9YW2CbCCxYvwngmSgNldTFSAFoAYABoAHAAeAA'\--data "{ "limit", 13'Message Aneliva Angelova+ AaIđ 0Pm~ (Q SearchDate ModifiedYesterdav at 13.36Yesterday at 13:35Yesterday at 13.34Yesterday at 13:34Yesterday at 13:33resterday at 15.5sYesterdav at 13:37Yesterday at 13:32Yesterday ar 13.31Yesterday at 13:30Yesterday at 13:30resterday at 15.4gYesterdav at 13:29Yesterday at 13:28Yesterday at 13:28Yesterday at 13:27Yesterday at 13:27resterday at 13-40Yesterdav at 13:25Yesterday at 13:25Yesterday at 13:24Yesterday at 13:24Yesterday at 13:23Yesterday at 13.21Yesterdav at 13:21Yesterday at 13:20Yesterday at 13:20Yesterday at 13:19Yesterday at 13:19Yesterday at 13.18Vecterdav at 12:17Yesterday at 13:16Yesterdav at 13:16Yesterday at 13:15Yesterday at 13:14Yecterdav at 12:1/Yesterday at 13:13Yesterday at 13.13Yecterdav at 12:12Yesterday at 13:12Yesterday at 13:11Yesterday at 13:10Yesterday at 13:10Yesterday at 13.09Yecterdav at 12:091Yesterday at 13:08Yesterdav at 13:07MPEG-4 movie13 KBMPEG-4 movie16 KB1/ Kb29 KBMPEG-4 movieMPEG-4 movie6 KB12 KBMPE0"4 movie9 K:7 KBMPEG-4 movie8 KB37 KBMP2G-4 movie10 KBMPEG-4 movie7 KBMPEG"4 movie9K:8KBMPEG-4 movie72 KB14 K8|13 KRIMPEG-4 movieMPEG-4 movie9 KB18 KBMPEG-4 movie12 KEMPEG-4 movie10 KBMPEG-4 movie16 KB6 KB1MPEG-4 movie6 KBMPEG-4 movie12 KB23 KBMPEG-4 movie8 KEMPEG-4 movie6 KBMPEG-4 movie6 KBMPEG-4 movie11 K:MPEG-4 movie11 KBMPEG-4 movie34 KBMPEG-4 movie10 KPMPEG-4 movie7 KBMPEG-4 movie5 KBMPEG-4 movie11 KBIMPEG-4 movie26 KBMPEG-4 movie111 KB102 KBRR KRMPEG-4 movieMDEG-A movie59 KB98 KBMPEG-4 movie07 K:MPEG-A movie66 KB MPEG-4 movie44 KB93 KB79 KpMPEG-4 movieMPEG-4 movie58 KBMPEG-4 movie27 KP7 KBMPEG-4 movie12 KB32 K8MPEG-4 movieAl Notes: OffLeave• 0FavouritesE jiminny© Recents* ApplicationsiCloudiCloud Drive228 Sync folderQ DXP4800PLUS-B5FA@ Network|• CRMI• Orange• Red• Yellow• Green• Purple•) All lags..lohlDownloadsNameLoom.pkgAlfred copv.alfredoreterencesB KeychronAssist-1.0.2 (1).dmgA Keychron Assist-1.0.2.dmgmazanoke-images-yWJo.zioPhotos-3-001.zipD Transcript.pdf→mage U.loge1 Orioninstaller.dmaimage.jpg- image (2).1pc• ПО-22221726037035-004-001_ORGES.pdf• %D0%9F%D0%9E-22221726037035-004-001_archive.zipПO-22221726037035-004-001_archive (1).zip• repon 4).XmAltred copy2.altredoreterences05012026_0000000026574472_ SWIFT_OB70501260015890.pdf27022026_0000000026574472_SWIFT_OB72702260049200.pdf= 03042026 [CREDIT_CARD] SWIFT [CREDIT_CARD].001B reporti) xm=pdt.odipdf-1.pdfD pdf-2.pdf-pdf-5.pd1= ndf-1 ndipdf-3.pdfKoválik Family Tree.gedbitwarden export 20251031122528.isonKoválik Family Tree.zip*macOS Storage_Cleanup.mdal favicon icofirst_aid_notes_complete.docxrenortl2).esvconfig.ymlIteration run Search HS.postman_collection.jsonm licence bettertouchtoalMariusHosting Config.json1ooks-891a6503-bbb7-4b2b-9c3.csv•Alfredmazanoke-images-YWJ6ана Ковалик.jpg•искане даниел Ковалик..pa• Фактура Март Даниел Ковалик.jрс• Фактура Април Даниел Ковалик.jpg• Dhotac 2.001Q SearchKind00,4 MDinstdlle..dckage55.9 MBAlfred...ferences10,1 MBDisk Image10,1 MBDisk ImageIL MBLiP archive6,6 MBZIP archive2,5 MB PDF Document2,5 MBJreo lmage2.2 MBDisk Image2,2 MB PDF Document2 MBJPEG image1,9 MBJPEG imaqe192 KBPDF Document140 KbZIP archive148 KВ148 KB122 KB111 KB94 KBZIP archivelZIP archiveXML documentAlfred...ferencesPDF Document92 KBPDr DocumentK:91 KB91 KB30 KB29 KBPDF DocumentXML documentPDF Document28 KBPDF Document28 KR28 KB27 KB14 KB11 KB6 KB6KBPDE DocumentDocumentJSONICSV DocumentZIP archiveMarkdo…..ument5KRWindo...n image4 KB3 KBword ..cumentCSV Document2 KBYAML document1 KBcSV Document928 byteshttlicence183 bytesZero butesJSONAlfred.. ferencesZero bytesFolde1,9 MB1,8 MB17 MB1,7 MBColdorJPEG imageJPEG ImageIPEG imadeJPEG imageColdo1 of 58 selected, 8.5 GB availab!i• Inu 14 Mау 1/•32.42Date AddedIs Mdl ZUzo dl 19:4530 Jan 2026 at 12:3617 Mar 2026 at 20:2717 Mar 2026 at 20:26Z3 Aor 2020 al 13:0229 Jan 2026 at 15:2019 Dec 2025 at 10:1619 Dec 2025 at 12:238 Aor 2026 at 20:3519 Dec 2025 at 10:2919 Dec 2025 at 12:1819 Dec 2025 at 12:4026 Mar 2026 at 11:2410 May 2026 at 13:5326 Mar 2026 at 11:2426 Mar 2026 at 11:2426 Mar 2026 at 11:2310 May 2026 at 14:3730 Jan 2026 at 12:3713 Feb 2026 at 11:54Z3 Apr 2026 at 13.0823 Aor 2026 at 13:0810 May 2026 at 13:5410 May 2026 at 14:3710 May 2026 at 13:4910 May 2026 at 13:5010 May 2026 at 13:5110 Mav 2026 at 12:51110 May 2026 at 13:5019 Dec 2025 at 11:3431 Oct 2025 at 12:2525 Nov 2025 at 17:596 Mar 2026 at 11.2224 Anr 2026 at 16:5220 Oct 2025 at 11:0218 Mar 2026 at 15:29• Mav 2026 at 11:09129 Oct 2025 at 19:329 May 2026 at 10:0418 Mar 2026 at 11:5510 May 2026 at 13:5712 Jun 2025 at 19:0430 Jan 2026 at 12:3630 Jan 2026 at 12:3616 Oct 2025 aт 16:0123 Apr 2026 at 13:0223 Apr 2026 at 13:0223 Apr 2026 at 13:0222 Anr 2026 at 12:0223 Apr 2026 at 13:0229 Jan 2026 at 15:20...
|
45359
|
NULL
|
NULL
|
NULL
|
|
45360
|
1625
|
17
|
2026-05-14T14:32:44.935525+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769164935_m1.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
PhpStormFileEditViewNavigateCodeLaravelRefactorRun PhpStormFileEditViewNavigateCodeLaravelRefactorRunToolsGitWindowHelp•FV faVsco.jsv* #12066 on JY-20725-handle-HS-search-rate-limit k vabl19HandleHubspotRateLimitTest100% C8• Thu 14 May 17:32:44* :QProjectv=custom.logAutomatedReportGenerated.phpTrackAutomatedReportGeneratedEvent.phpPlaybackController.php© FieldDefinitions.phpUserAutomatedReportsController.phpPlanhatService.phpAutomatedReportResult.phpSendReportJob.php© FieldValueConverter.php• DeleteCrmEntityTrait.phpDeleteAccountJob.php© ImportActivityTypes.phpT WriteCrmTrait.php© Service.php© DecorateActivity.php© StandardFieldMetadata.php© Salesforce/Service.php© LogActivityTrait.phpPipedrive/Service.phpClose/Service.phpCopper/Service.php Xv D Copper© PlainTextDecorateActivity.phpT ActivityPlaybookTrait.php© CrmHelperRepository.phpAccountController.php18> D Api› D ExceptionT IntegrationAppTrait.php.env.stagingE.env© DetachActivityObject.phpRematchActivityOnCrmObjectDetach.php> C OpportunitySyncStrategy© MatchActivityCrmData.php> D ProspectSearchStrategy52© Client.phpclass Service extends BaseService implements© HubspotPaginationService.php© HandleHubspotRateLimit.phpA11 A72 X1 X4 ^> CJ Traits© FieldDefinitions.php16621663* Othrows CrmException© FieldValueConverter.php© Service.php*/1 usage> D CrmObjects1664private function buildCallPayload(Activity $activity): Activityv DecorateActivity1665© BaseDecorateActivity.php1666try{© PlainTextDecorateActivity.pl1667> D Dummy1668v Helpers1669T ActivityPlaybookTrait.php1670© Arraylterator.php1671if (Sactivity->crm_provider_id) {// The activity should be logged under the existing Task (not Activity).SnewActivityType = Sthis->getCrmType(Sactivity->category);if ($newActivityType === null) {$message = sprintf( format: '[Copper] invalid CRM Custom Activity Type: %s', $activity->ca224• ConnectionStateTrait.php1672© CrmHelperRepository.php1673throw new CrmException(Smessage,code: 400);© FilterJoinedParticipants.php1674* OpportunitySyncableFieldsT1675v D Hubspot1676• AccountSyncStrategy1677> OJ Actions |1678$this->copperClient->tasks()->update($activity->crm_provider_id, ['status'= 'Completed','custom_activity_type_id' => $newActivityType->value,'details' => $this->generateActivityDescription($activity),• ContactSyncStrategy1679> ODTO16801):j else {› Fields1681> • Journal1682if (Sthis-~getCrmType(SactivitX-scategocx)minulln$message = sprintf( format:' [Copper] Invalid CRM Activity Type: %s', Sactivity->category→D Metadata1683v D OpportunitySyncStrategy1684throw new CrmException($message,code: 400);> D Concerns1685=A Unhonntl actlAndifiaNDur 1686Workspace associated with branch 'JY-20725-handle-HS-search-rate-limit' has been restored // Rollback // Configure... (today 16:17)=laravel.logSF [jiminny@localhost]A HS_local [jiminny@localho:W4 console [QAI PROD] X4 console [PROD]A console (EU]DGo jiminny084143 ×4 л215|•m_layout_id =2162,1661,66799,66217218219id = 33;=220=221=222=223id THEN •(own=225=226= 227228229=230hubspat":.231I232233V= 11512582;=234-W Windsurf Teams1664:31UTF-8P. 4 spaces...
|
NULL
|
5212527082351262392
|
NULL
|
click
|
ocr
|
NULL
|
PhpStormFileEditViewNavigateCodeLaravelRefactorRun PhpStormFileEditViewNavigateCodeLaravelRefactorRunToolsGitWindowHelp•FV faVsco.jsv* #12066 on JY-20725-handle-HS-search-rate-limit k vabl19HandleHubspotRateLimitTest100% C8• Thu 14 May 17:32:44* :QProjectv=custom.logAutomatedReportGenerated.phpTrackAutomatedReportGeneratedEvent.phpPlaybackController.php© FieldDefinitions.phpUserAutomatedReportsController.phpPlanhatService.phpAutomatedReportResult.phpSendReportJob.php© FieldValueConverter.php• DeleteCrmEntityTrait.phpDeleteAccountJob.php© ImportActivityTypes.phpT WriteCrmTrait.php© Service.php© DecorateActivity.php© StandardFieldMetadata.php© Salesforce/Service.php© LogActivityTrait.phpPipedrive/Service.phpClose/Service.phpCopper/Service.php Xv D Copper© PlainTextDecorateActivity.phpT ActivityPlaybookTrait.php© CrmHelperRepository.phpAccountController.php18> D Api› D ExceptionT IntegrationAppTrait.php.env.stagingE.env© DetachActivityObject.phpRematchActivityOnCrmObjectDetach.php> C OpportunitySyncStrategy© MatchActivityCrmData.php> D ProspectSearchStrategy52© Client.phpclass Service extends BaseService implements© HubspotPaginationService.php© HandleHubspotRateLimit.phpA11 A72 X1 X4 ^> CJ Traits© FieldDefinitions.php16621663* Othrows CrmException© FieldValueConverter.php© Service.php*/1 usage> D CrmObjects1664private function buildCallPayload(Activity $activity): Activityv DecorateActivity1665© BaseDecorateActivity.php1666try{© PlainTextDecorateActivity.pl1667> D Dummy1668v Helpers1669T ActivityPlaybookTrait.php1670© Arraylterator.php1671if (Sactivity->crm_provider_id) {// The activity should be logged under the existing Task (not Activity).SnewActivityType = Sthis->getCrmType(Sactivity->category);if ($newActivityType === null) {$message = sprintf( format: '[Copper] invalid CRM Custom Activity Type: %s', $activity->ca224• ConnectionStateTrait.php1672© CrmHelperRepository.php1673throw new CrmException(Smessage,code: 400);© FilterJoinedParticipants.php1674* OpportunitySyncableFieldsT1675v D Hubspot1676• AccountSyncStrategy1677> OJ Actions |1678$this->copperClient->tasks()->update($activity->crm_provider_id, ['status'= 'Completed','custom_activity_type_id' => $newActivityType->value,'details' => $this->generateActivityDescription($activity),• ContactSyncStrategy1679> ODTO16801):j else {› Fields1681> • Journal1682if (Sthis-~getCrmType(SactivitX-scategocx)minulln$message = sprintf( format:' [Copper] Invalid CRM Activity Type: %s', Sactivity->category→D Metadata1683v D OpportunitySyncStrategy1684throw new CrmException($message,code: 400);> D Concerns1685=A Unhonntl actlAndifiaNDur 1686Workspace associated with branch 'JY-20725-handle-HS-search-rate-limit' has been restored // Rollback // Configure... (today 16:17)=laravel.logSF [jiminny@localhost]A HS_local [jiminny@localho:W4 console [QAI PROD] X4 console [PROD]A console (EU]DGo jiminny084143 ×4 л215|•m_layout_id =2162,1661,66799,66217218219id = 33;=220=221=222=223id THEN •(own=225=226= 227228229=230hubspat":.231I232233V= 11512582;=234-W Windsurf Teams1664:31UTF-8P. 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
45359
|
1626
|
9
|
2026-05-14T14:32:42.185935+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769162185_m2.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
ActivityFilesLaterJiminny... ~@ jiminny-x-integrat ActivityFilesLaterJiminny... ~@ jiminny-x-integrati& platform-inner-team© Channels# ai-chapter# alertsi backend# bugscontusion-cllnia# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the people of iimi..• Direct messages8. A...• A3 62P. Galya Dimitrova Mvasil VasilevA. Stefka Stoyanova%: Todor Stamatovf. Mario GeorgievP. Nikolay Ivanov2o James Graham "2. Stoyan Tanev. Steliyan Georgiev. Petko Kashinski*. Lukas Kovali...a: Apps® ToastS lira Gloud6 Huddle with Aneliya Angelova& R. Aneliya Angelova •• Messagest Add canvasur FilesAneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук,нали?пои останалите скМі тоябва оъчно ла се въвелат.Lukas Kovalik 2:47 PMтряова да се за всички, някьде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova @ 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725X Preview insackt[HubSpot] Optimise CRM rematctC OpenReady for QA- MediumAA Aneliya AngelovaAs of today at 4:00 PM RetreshOpen in Jira+ SummariseLukas Kovalik 4:02 PMzean-iurwiniareelYou joined the huddle LIVE 4:06 PMAneliva Angelova is here toolAneliya Angelova 4:44 PM11512582Lukas Kovalik O 5:16 PMcurl --location "httns:ani.hubani.com/crm/v3/obiects/contacts/search--header 'Content-Type: application/json'\--header "Authorization: BearerC|Kvma?iMx7OINOM8kOFwrAowAcAkUAhIR24?A05D?xiVrIYMILuP6SA01Kwcmhr=n.v2 hytorDniMvDalYck-CMalovolNOM9kOFwrAUAcrkcaws-ThwRARIRAOF-ATFSAOFRAO-ROIEBAQUBEggBAQEBAYICFIґ7Au8O2Nwal9YW2CbCCxYvwngmSgNldTFSAFoAYABoAHAAeAA'\--data "{ "limit", 13'Message Aneliva Angelova+ AaIđ 0Pm~ (Q SearchDate ModifiedYesterdav at 13.36Yesterday at 13:35Yesterday at 13.34Yesterday at 13:34Yesterday at 13:33resterday at 15.5sYesterdav at 13:37Yesterday at 13:32Yesterday ar 13.31Yesterday at 13:30Yesterday at 13:30resterday at 15.4gYesterdav at 13:29Yesterday at 13:28Yesterday at 13:28Yesterday at 13:27Yesterday at 13:27resterday at 13-40Yesterdav at 13:25Yesterday at 13:25Yesterday at 13:24Yesterday at 13:24Yesterday at 13:23Yesterday at 13.21Yesterdav at 13:21Yesterday at 13:20Yesterday at 13:20Yesterday at 13:19Yesterday at 13:19Yesterday at 13.18Vecterdav at 12:17Yesterday at 13:16Yesterdav at 13:16Yesterday at 13:15Yesterday at 13:14Yecterdav at 12:1/Yesterday at 13:13Yesterday at 13.13Yecterdav at 12:12Yesterday at 13:12Yesterday at 13:11Yesterday at 13:10Yesterday at 13:10Yesterday at 13.09Yecterdav at 12:091Yesterday at 13:08Yesterdav at 13:07MPEG-4 movie13 KBMPEG-4 movie16 KB1/ Kb29 KBMPEG-4 movieMPEG-4 movie6 KB12 KBMPE0"4 movie9 K:7 KBMPEG-4 movie8 KB37 KBMP2G-4 movie10 KBMPEG-4 movie7 KBMPEG"4 movie9K:8KBMPEG-4 movie72 KB14 K8|13 KRIMPEG-4 movieMPEG-4 movie9 KB18 KBMPEG-4 movie12 KEMPEG-4 movie10 KBMPEG-4 movie16 KB6 KB1MPEG-4 movie6 KBMPEG-4 movie12 KB23 KBMPEG-4 movie8 KEMPEG-4 movie6 KBMPEG-4 movie6 KBMPEG-4 movie11 K:MPEG-4 movie11 KBMPEG-4 movie34 KBMPEG-4 movie10 KPMPEG-4 movie7 KBMPEG-4 movie5 KBMPEG-4 movie11 KBIMPEG-4 movie26 KBMPEG-4 movie111 KB102 KBRR KRMPEG-4 movieMDEG-A movie59 KB98 KBMPEG-4 movie07 K:MPEG-A movie66 KB MPEG-4 movie44 KB93 KB79 KpMPEG-4 movieMPEG-4 movie58 KBMPEG-4 movie27 KP7 KBMPEG-4 movie12 KB32 K8MPEG-4 movieAl Notes: OffLeave• 0FavouritesE jiminny© Recents* ApplicationsiCloudiCloud Drive228 Sync folderQ DXP4800PLUS-B5FA@ Network|• CRMI• Orange• Red• Yellow• Green• Purple•) All lags..lohlDownloadsNameLoom.pkgAlfred copv.alfredoreterencesB KeychronAssist-1.0.2 (1).dmgA Keychron Assist-1.0.2.dmgmazanoke-images-yWJo.zioPhotos-3-001.zipD Transcript.pdf→mage U.loge1 Orioninstaller.dmaimage.jpg- image (2).1pc• ПО-22221726037035-004-001_ORGES.pdf• %D0%9F%D0%9E-22221726037035-004-001_archive.zipПO-22221726037035-004-001_archive (1).zip• repon 4).XmAltred copy2.altredoreterences05012026_0000000026574472_ SWIFT_OB70501260015890.pdf27022026_0000000026574472_SWIFT_OB72702260049200.pdf= 03042026 [CREDIT_CARD] SWIFT [CREDIT_CARD].001B reporti) xm=pdt.odipdf-1.pdfD pdf-2.pdf-pdf-5.pd1= ndf-1 ndipdf-3.pdfKoválik Family Tree.gedbitwarden export 20251031122528.isonKoválik Family Tree.zip*macOS Storage_Cleanup.mdal favicon icofirst_aid_notes_complete.docxrenortl2).esvconfig.ymlIteration run Search HS.postman_collection.jsonm licence bettertouchtoalMariusHosting Config.json1ooks-891a6503-bbb7-4b2b-9c3.csv•Alfredmazanoke-images-YWJ6ана Ковалик.jpg•искане даниел Ковалик..pa• Фактура Март Даниел Ковалик.jрс• Фактура Април Даниел Ковалик.jpg• Dhotac 2.001Q SearchKind00,4 MDinstdlle..dckage55.9 MBAlfred...ferences10,1 MBDisk Image10,1 MBDisk ImageIL MBLiP archive6,6 MBZIP archive2,5 MB PDF Document2,5 MBJreo lmage2.2 MBDisk Image2,2 MB PDF Document2 MBJPEG image1,9 MBJPEG imaqe192 KBPDF Document140 KbZIP archive148 KВ148 KB122 KB111 KB94 KBZIP archivelZIP archiveXML documentAlfred...ferencesPDF Document92 KBPDr DocumentK:91 KB91 KB30 KB29 KBPDF DocumentXML documentPDF Document28 KBPDF Document28 KR28 KB27 KB14 KB11 KB6 KB6KBPDE DocumentDocumentJSONICSV DocumentZIP archiveMarkdo…..ument5KRWindo...n image4 KB3 KBword ..cumentCSV Document2 KBYAML document1 KBcSV Document928 byteshttlicence183 bytesZero butesJSONAlfred.. ferencesZero bytesFolde1,9 MB1,8 MB17 MB1,7 MBColdorJPEG imageJPEG ImageJPEG imageJPEG imageColdo1 of 58 selected, 8.5 GB availab!i• Inu 14 Mау 1/•32.4]Date AddedIs Mdl ZUzo dl 19:4530 Jan 2026 at 12:3617 Mar 2026 at 20:2717 Mar 2026 at 20:26Z3 Aor 2020 al 13:0229 Jan 2026 at 15:2019 Dec 2025 at 10:1619 Dec 2025 at 12:238 Aor 2026 at 20:3519 Dec 2025 at 10:2919 Dec 2025 at 12:1819 Dec 2025 at 12:4026 Mar 2026 at 11:2410 May 2026 at 13:5326 Mar 2026 at 11:2426 Mar 2026 at 11:2426 Mar 2026 at 11:2310 May 2026 at 14:3730 Jan 2026 at 12:3713 Feb 2026 at 11:54Z3 Apr 2026 at 13.0823 Aor 2026 at 13:0810 May 2026 at 13:5410 May 2026 at 14:3710 May 2026 at 13:4910 May 2026 at 13:5010 May 2026 at 13:5110 Mav 2026 at 12:51110 May 2026 at 13:5019 Dec 2025 at 11:3431 Oct 2025 at 12:2525 Nov 2025 at 17:596 Mar 2026 at 11.2224 Anr 2026 at 16:5220 Oct 2025 at 11:0218 Mar 2026 at 15:29• Mav 2026 at 11:09129 Oct 2025 at 19:329 May 2026 at 10:0418 Mar 2026 at 11:5510 May 2026 at 13:5712 Jun 2025 at 19:0430 Jan 2026 at 12:3630 Jan 2026 at 12:3616 Oct 2025 aт 16:0123 Apr 2026 at 13:0223 Apr 2026 at 13:0223 Apr 2026 at 13:0222 Anr 2026 at 12:0223 Apr 2026 at 13:0229 Jan 2026 at 15:20...
|
NULL
|
9187213961329440757
|
NULL
|
click
|
ocr
|
NULL
|
ActivityFilesLaterJiminny... ~@ jiminny-x-integrat ActivityFilesLaterJiminny... ~@ jiminny-x-integrati& platform-inner-team© Channels# ai-chapter# alertsi backend# bugscontusion-cllnia# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the people of iimi..• Direct messages8. A...• A3 62P. Galya Dimitrova Mvasil VasilevA. Stefka Stoyanova%: Todor Stamatovf. Mario GeorgievP. Nikolay Ivanov2o James Graham "2. Stoyan Tanev. Steliyan Georgiev. Petko Kashinski*. Lukas Kovali...a: Apps® ToastS lira Gloud6 Huddle with Aneliya Angelova& R. Aneliya Angelova •• Messagest Add canvasur FilesAneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук,нали?пои останалите скМі тоябва оъчно ла се въвелат.Lukas Kovalik 2:47 PMтряова да се за всички, някьде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova @ 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725X Preview insackt[HubSpot] Optimise CRM rematctC OpenReady for QA- MediumAA Aneliya AngelovaAs of today at 4:00 PM RetreshOpen in Jira+ SummariseLukas Kovalik 4:02 PMzean-iurwiniareelYou joined the huddle LIVE 4:06 PMAneliva Angelova is here toolAneliya Angelova 4:44 PM11512582Lukas Kovalik O 5:16 PMcurl --location "httns:ani.hubani.com/crm/v3/obiects/contacts/search--header 'Content-Type: application/json'\--header "Authorization: BearerC|Kvma?iMx7OINOM8kOFwrAowAcAkUAhIR24?A05D?xiVrIYMILuP6SA01Kwcmhr=n.v2 hytorDniMvDalYck-CMalovolNOM9kOFwrAUAcrkcaws-ThwRARIRAOF-ATFSAOFRAO-ROIEBAQUBEggBAQEBAYICFIґ7Au8O2Nwal9YW2CbCCxYvwngmSgNldTFSAFoAYABoAHAAeAA'\--data "{ "limit", 13'Message Aneliva Angelova+ AaIđ 0Pm~ (Q SearchDate ModifiedYesterdav at 13.36Yesterday at 13:35Yesterday at 13.34Yesterday at 13:34Yesterday at 13:33resterday at 15.5sYesterdav at 13:37Yesterday at 13:32Yesterday ar 13.31Yesterday at 13:30Yesterday at 13:30resterday at 15.4gYesterdav at 13:29Yesterday at 13:28Yesterday at 13:28Yesterday at 13:27Yesterday at 13:27resterday at 13-40Yesterdav at 13:25Yesterday at 13:25Yesterday at 13:24Yesterday at 13:24Yesterday at 13:23Yesterday at 13.21Yesterdav at 13:21Yesterday at 13:20Yesterday at 13:20Yesterday at 13:19Yesterday at 13:19Yesterday at 13.18Vecterdav at 12:17Yesterday at 13:16Yesterdav at 13:16Yesterday at 13:15Yesterday at 13:14Yecterdav at 12:1/Yesterday at 13:13Yesterday at 13.13Yecterdav at 12:12Yesterday at 13:12Yesterday at 13:11Yesterday at 13:10Yesterday at 13:10Yesterday at 13.09Yecterdav at 12:091Yesterday at 13:08Yesterdav at 13:07MPEG-4 movie13 KBMPEG-4 movie16 KB1/ Kb29 KBMPEG-4 movieMPEG-4 movie6 KB12 KBMPE0"4 movie9 K:7 KBMPEG-4 movie8 KB37 KBMP2G-4 movie10 KBMPEG-4 movie7 KBMPEG"4 movie9K:8KBMPEG-4 movie72 KB14 K8|13 KRIMPEG-4 movieMPEG-4 movie9 KB18 KBMPEG-4 movie12 KEMPEG-4 movie10 KBMPEG-4 movie16 KB6 KB1MPEG-4 movie6 KBMPEG-4 movie12 KB23 KBMPEG-4 movie8 KEMPEG-4 movie6 KBMPEG-4 movie6 KBMPEG-4 movie11 K:MPEG-4 movie11 KBMPEG-4 movie34 KBMPEG-4 movie10 KPMPEG-4 movie7 KBMPEG-4 movie5 KBMPEG-4 movie11 KBIMPEG-4 movie26 KBMPEG-4 movie111 KB102 KBRR KRMPEG-4 movieMDEG-A movie59 KB98 KBMPEG-4 movie07 K:MPEG-A movie66 KB MPEG-4 movie44 KB93 KB79 KpMPEG-4 movieMPEG-4 movie58 KBMPEG-4 movie27 KP7 KBMPEG-4 movie12 KB32 K8MPEG-4 movieAl Notes: OffLeave• 0FavouritesE jiminny© Recents* ApplicationsiCloudiCloud Drive228 Sync folderQ DXP4800PLUS-B5FA@ Network|• CRMI• Orange• Red• Yellow• Green• Purple•) All lags..lohlDownloadsNameLoom.pkgAlfred copv.alfredoreterencesB KeychronAssist-1.0.2 (1).dmgA Keychron Assist-1.0.2.dmgmazanoke-images-yWJo.zioPhotos-3-001.zipD Transcript.pdf→mage U.loge1 Orioninstaller.dmaimage.jpg- image (2).1pc• ПО-22221726037035-004-001_ORGES.pdf• %D0%9F%D0%9E-22221726037035-004-001_archive.zipПO-22221726037035-004-001_archive (1).zip• repon 4).XmAltred copy2.altredoreterences05012026_0000000026574472_ SWIFT_OB70501260015890.pdf27022026_0000000026574472_SWIFT_OB72702260049200.pdf= 03042026 [CREDIT_CARD] SWIFT [CREDIT_CARD].001B reporti) xm=pdt.odipdf-1.pdfD pdf-2.pdf-pdf-5.pd1= ndf-1 ndipdf-3.pdfKoválik Family Tree.gedbitwarden export 20251031122528.isonKoválik Family Tree.zip*macOS Storage_Cleanup.mdal favicon icofirst_aid_notes_complete.docxrenortl2).esvconfig.ymlIteration run Search HS.postman_collection.jsonm licence bettertouchtoalMariusHosting Config.json1ooks-891a6503-bbb7-4b2b-9c3.csv•Alfredmazanoke-images-YWJ6ана Ковалик.jpg•искане даниел Ковалик..pa• Фактура Март Даниел Ковалик.jрс• Фактура Април Даниел Ковалик.jpg• Dhotac 2.001Q SearchKind00,4 MDinstdlle..dckage55.9 MBAlfred...ferences10,1 MBDisk Image10,1 MBDisk ImageIL MBLiP archive6,6 MBZIP archive2,5 MB PDF Document2,5 MBJreo lmage2.2 MBDisk Image2,2 MB PDF Document2 MBJPEG image1,9 MBJPEG imaqe192 KBPDF Document140 KbZIP archive148 KВ148 KB122 KB111 KB94 KBZIP archivelZIP archiveXML documentAlfred...ferencesPDF Document92 KBPDr DocumentK:91 KB91 KB30 KB29 KBPDF DocumentXML documentPDF Document28 KBPDF Document28 KR28 KB27 KB14 KB11 KB6 KB6KBPDE DocumentDocumentJSONICSV DocumentZIP archiveMarkdo…..ument5KRWindo...n image4 KB3 KBword ..cumentCSV Document2 KBYAML document1 KBcSV Document928 byteshttlicence183 bytesZero butesJSONAlfred.. ferencesZero bytesFolde1,9 MB1,8 MB17 MB1,7 MBColdorJPEG imageJPEG ImageJPEG imageJPEG imageColdo1 of 58 selected, 8.5 GB availab!i• Inu 14 Mау 1/•32.4]Date AddedIs Mdl ZUzo dl 19:4530 Jan 2026 at 12:3617 Mar 2026 at 20:2717 Mar 2026 at 20:26Z3 Aor 2020 al 13:0229 Jan 2026 at 15:2019 Dec 2025 at 10:1619 Dec 2025 at 12:238 Aor 2026 at 20:3519 Dec 2025 at 10:2919 Dec 2025 at 12:1819 Dec 2025 at 12:4026 Mar 2026 at 11:2410 May 2026 at 13:5326 Mar 2026 at 11:2426 Mar 2026 at 11:2426 Mar 2026 at 11:2310 May 2026 at 14:3730 Jan 2026 at 12:3713 Feb 2026 at 11:54Z3 Apr 2026 at 13.0823 Aor 2026 at 13:0810 May 2026 at 13:5410 May 2026 at 14:3710 May 2026 at 13:4910 May 2026 at 13:5010 May 2026 at 13:5110 Mav 2026 at 12:51110 May 2026 at 13:5019 Dec 2025 at 11:3431 Oct 2025 at 12:2525 Nov 2025 at 17:596 Mar 2026 at 11.2224 Anr 2026 at 16:5220 Oct 2025 at 11:0218 Mar 2026 at 15:29• Mav 2026 at 11:09129 Oct 2025 at 19:329 May 2026 at 10:0418 Mar 2026 at 11:5510 May 2026 at 13:5712 Jun 2025 at 19:0430 Jan 2026 at 12:3630 Jan 2026 at 12:3616 Oct 2025 aт 16:0123 Apr 2026 at 13:0223 Apr 2026 at 13:0223 Apr 2026 at 13:0222 Anr 2026 at 12:0223 Apr 2026 at 13:0229 Jan 2026 at 15:20...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
45358
|
1625
|
16
|
2026-05-14T14:32:43.744332+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769163744_m1.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
11
72
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Copper;
use Carbon\Carbon;
use Exception;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Support\Facades\Cache;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\CopperInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Crm\LayoutEntity;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Repositories\UserRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Copper\Api\Client;
use Jiminny\Services\Crm\Copper\Api\ClientFactory;
use Jiminny\Services\Crm\Copper\Exception\RequestFailedException;
use Jiminny\Services\Crm\Helpers\FilterJoinedParticipants;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\Copper\Traits\SearchesCrmEntities;
use Jiminny\Utils\CurrencyFormatter;
use Jiminny\Utils\StringUtil;
class Service extends BaseService implements
CopperInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
RemoteEntityManipulationInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use SearchesCrmEntities;
private const int NOTE_BODY_MAX_LENGTH = 3000000;
private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day
private const array STANDARD_OPPORTUNITY_FIELDS = [
'monetary_value' => [
'label' => 'Value',
'available_on' => Field::OBJECT_OPPORTUNITY,
'type' => Field::TYPE_CURRENCY,
],
'pipeline_stage_id' => [
'label' => 'Stage',
'type' => Field::TYPE_PICKLIST,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
'close_date' => [
'label' => 'Close date',
'type' => Field::TYPE_DATE,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
'win_probability' => [
'label' => 'Win probability',
'type' => Field::TYPE_NUMBER,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
];
private const string UNSUPPORTED_OBJECT_TYPE = 'unsupported';
private const string OPPORTUNITY_STATUS_OPEN = 'Open';
private const string OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE = 'Opportunity import failed';
private const string RESOURCE_UPDATE_FAILED_ERROR_MESSAGE = 'Failed to update resource';
private FieldValueConverter $fieldValueConverter;
private ClientFactory $clientFactory;
private ?Client $copperClient = null;
public function __construct(
ClientFactory $clientFactory,
FieldValueConverter $fieldValueConverter,
private readonly UserRepository $userRepository,
private readonly ProspectPhotoPathService $prospectPhotoPathService,
private readonly CrmEntityRepository $crmEntityRepository
) {
parent::__construct();
$this->clientFactory = $clientFactory;
$this->fieldValueConverter = $fieldValueConverter;
}
public function getDisplayName(): string
{
return 'Copper';
}
/**
* Get the CRM entity repository (used by SearchesCrmEntities trait)
*/
protected function getCrmEntityRepository(): CrmEntityRepository
{
return $this->crmEntityRepository;
}
public function getMinimumApiVersion(): string
{
return Client::MIN_API_VERSION;
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
$owner = $user->team->owner;
return $owner->getSocialAccount(SocialAccount::PROVIDER_COPPER);
}
public function setUser(User $user): void
{
$this->configureSentryScope($user);
$this->team = $user->getTeam();
$this->teamService->setTeam($user->getTeam());
$this->setConfiguration($user->getTeam()->getCrmConfiguration());
// Reset state.
$this->profile = $user->getProfile();
if (! $this->profile instanceof Profile) {
// Try to fetch their profile, maybe it was not yet imported?
$this->profile = $this->getProfile($user);
}
}
public function setConfiguration(Configuration $configuration): void
{
$this->config = $configuration;
$this->copperClient = $this->clientFactory->create($configuration);
if ($this->team === null) {
$this->team = $configuration->getTeam();
}
}
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);
}
private function mapObjectType(string $objectType): string
{
$objectType = strtolower($objectType);
switch ($objectType) {
case Field::OBJECT_TASK:
case Field::OBJECT_OPPORTUNITY:
case Field::OBJECT_LEAD:
$mappedType = $objectType;
break;
case Field::OBJECT_ACCOUNT:
$mappedType = 'company';
break;
case Field::OBJECT_CONTACT:
$mappedType = 'person';
break;
default:
$mappedType = self::UNSUPPORTED_OBJECT_TYPE;
break;
}
return $mappedType;
}
/**
* @param string $crmObject The name of the CRM object. i.e. Opportunity or Contact
*/
protected function getFields(string $crmObject): array
{
$mappedObjectType = $this->mapObjectType($crmObject);
if (! $this->isSupportedObjectType($mappedObjectType)) {
return [];
}
$customFields = $this->copperClient->fields()->all();
$filteredFields = array_filter(
$customFields,
static fn ($field) => in_array($mappedObjectType, $field['available_on'], true)
);
return array_map(
fn (array $property) => [
'name' => $property['id'],
'label' => $property['name'],
'type' => $this->convertFieldType($property['data_type']),
],
$filteredFields
);
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
// Setup the activity field as the default Type.
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'type',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldFilters = FieldDefinitions::taskFollowupFieldsFilter();
foreach ($fieldFilters as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
public function syncFields(): void
{
$this->syncStandardFields();
$this->syncCustomFields();
}
public function syncField(Field $field): void
{
if ($field->getCrmProviderId() === 'type') {
/**
* This field is a special case, it is not a custom field and is not returned by the Copper API.
*
* The field is created manually during layout setup.
*
* @see getDefaultFields()
*
* There is a separate endpoint to get the activity types.
* @see importPicklistValues()
*/
return;
}
if ($field->getCrmProviderId() === 'pipeline_stage_id') {
// Not a custom type
return;
}
$crmField = $this->copperClient->fields()->find($field->getCrmProviderId());
$field->label = $crmField['name'];
$field->type = $this->convertFieldType($crmField['data_type']);
$field->save();
}
/**
* @param string $fieldType How the data should be input
*/
private function convertFieldType(string $fieldType): string
{
$fieldType = strtolower($fieldType);
switch ($fieldType) {
case 'dropdown':
$convertedType = Field::TYPE_PICKLIST;
break;
case 'string':
$convertedType = Field::TYPE_TEXT;
break;
case 'float':
case 'percentage':
$convertedType = Field::TYPE_NUMBER;
break;
case 'text':
$convertedType = Field::TYPE_TEXTAREA;
break;
case 'checkbox':
$convertedType = Field::TYPE_BOOLEAN;
break;
case Field::TYPE_DATE:
case Field::TYPE_CURRENCY:
case Field::TYPE_URL:
$convertedType = $fieldType;
break;
default:
$convertedType = Field::TYPE_UNSUPPORTED;
break;
}
return $convertedType;
}
/**
* @inheritdoc
*/
public function importPicklistValues(Field $field): array
{
$fieldValues = [];
if ($field->object_type === 'opportunity' && $field->crm_provider_id === 'pipeline_stage_id') {
return $this->importFieldValuesForDealInsights($field);
}
$values = [];
if ($field->object_type === Field::OBJECT_TASK && $field->crm_provider_id === 'type') {
$activityTypes = $this->copperClient->activityTypes()->all();
/**
* We ignore "system" activity types, disabled activity types and the "Note" activity type.
*/
$activityTypes = array_filter(
$activityTypes['user'],
fn (array $activityType) => ! $activityType['is_disabled'] && $activityType['id'] !== 0
);
// Import all activity values.
$i = 0;
foreach ($activityTypes as $activityType) {
$values[] = [
'value' => $activityType['id'],
'label' => mb_strimwidth($activityType['name'], 0, Field::LABEL_MAX_LENGTH),
'sequence' => $i++,
];
}
} else {
// We just check for the field in the custom definitions.
$crmField = $this->copperClient->fields()->find($field->crm_provider_id);
// Import all values.
foreach ($crmField['options'] as $option) {
$values[] = [
'value' => $option['id'],
'label' => mb_strimwidth($option['name'], 0, 191),
'sequence' => $option['rank'],
];
}
}
// Take the existing set of field values.
$fieldsToPurge = $field->values()->get()->pluck('value')->toArray();
foreach ($values as $value) {
// For all current values, upsert the field.
$value['value'] = substr($value['value'] ?? '', 0, 255);
$fieldValues[] = $field->values()->updateOrCreate([
'value' => $value['value'],
], $value);
// Remove this value from the ones we are going to purge.
$key = array_search($value['value'], $fieldsToPurge, false);
if ($key !== false) {
unset($fieldsToPurge[$key]);
}
}
// Delete the old values that are no longer used.
$field->values()->whereIn('value', $fieldsToPurge)->delete();
return $fieldValues;
}
/**
*
* @return FieldValue[]
*/
private function importFieldValuesForDealInsights(Field $field): array
{
$fieldValues = [];
$pipelines = $this->copperClient->pipelines()->all();
foreach ($pipelines as $pipeline) {
foreach ($pipeline['stages'] as $i => $dealStage) {
$fieldValues[] = $field->values()->updateOrCreate(
['value' => $dealStage['id']],
[
'label' => $dealStage['name'],
'sequence' => $i,
]
);
}
}
return $fieldValues;
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
if ($types === null) {
$types = [Stage::TYPE_LEAD, Stage::TYPE_OPPORTUNITY];
}
$missingStage = null;
foreach ($types as $type) {
if ($type === Stage::TYPE_LEAD) {
$statuses = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leadStatuses()->all()
);
if (count($statuses) > 0) {
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => BusinessProcess::TYPE_LEAD,
], [
'team_id' => $this->team->id,
'name' => BusinessProcess::TYPE_LEAD,
'type' => BusinessProcess::TYPE_LEAD,
'is_selectable' => true,
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => BusinessProcess::TYPE_LEAD,
], [
'team_id' => $this->team->id,
'name' => BusinessProcess::TYPE_LEAD,
'is_selectable' => true,
'business_process_id' => $businessProcess->id ?? null,
]);
$leadStatuses = [];
foreach ($statuses as $status) {
// Upsert all statuses for the team.
$status = $this->config->stages()->updateOrCreate([
'crm_provider_id' => $status['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($status['name'], 0, 50),
'label' => mb_strimwidth($status['name'], 0, 191),
'type' => Stage::TYPE_LEAD,
'sequence' => $status['order'],
'is_selectable' => true,
]);
if ($missingStageName && $missingStageName === $status['id']) {
$missingStage = $status;
}
$leadStatuses[] = $status['id'];
}
$businessProcess->stages()->sync($leadStatuses);
}
} else {
// We create a business process to contain the pipeline, and later store all stages against it.
foreach ($this->copperClient->pipelines()->all() as $pipeline) {
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $pipeline['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($pipeline['name'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => true,
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $pipeline['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($pipeline['name'], 0, 150),
'is_selectable' => true,
'business_process_id' => $businessProcess->id ?? null,
]);
$stages = [];
foreach ($pipeline['stages'] as $i => $dealStage) {
// Upsert all stages for the team.
$stage = $this->config->stages()->updateOrCreate([
'crm_provider_id' => $dealStage['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($dealStage['name'], 0, 50),
'label' => mb_strimwidth($dealStage['name'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $i,
'is_selectable' => true,
'probability' => $dealStage['win_probability'],
]);
if ($missingStageName && $missingStageName === $dealStage['id']) {
$missingStage = $stage;
}
$stages[] = $stage['id'];
}
$businessProcess->stages()->sync($stages);
}
}
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int
{
$syncCount = 0;
$cpLeads = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->paginate([
'minimum_modified_date' => $since->timestamp,
'sort_by' => 'date_modified',
])
);
foreach ($cpLeads as $cpLead) {
// Only sync if previously imported.
if ($this->hasLead($cpLead['id']) === false) {
$this->importLead($cpLead);
$syncCount++;
}
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncLead(string $crmId): ?Lead
{
$cpLead = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->find($crmId)
);
if (\count($cpLead) === 0) {
return null;
}
return $this->importLead($cpLead);
}
/**
* @inheritdoc
*/
private function importLead($crmData): ?Lead
{
$countryCode = null;
if (! empty($crmData['address']) && isset($crmData['address']['country'])) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$mobilePhone = $parsedNumber = null;
if (! empty($crmData['phone_numbers'])) {
foreach ($crmData['phone_numbers'] as $phoneNumber) {
if ($phoneNumber['category'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);
} else {
$parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);
}
}
}
$name = $crmData['name'];
if (empty($crmData['company_name'])) {
$company = 'Unknown';
} else {
$company = mb_strimwidth($crmData['company_name'], 0, 191);
}
$domain = null;
if (empty($crmData['websites']) === false) {
$domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);
$domain = StringUtil::resolveDomain($domain);
}
$email = null;
if (empty($crmData['email']) === false) {
$email = mb_strimwidth($crmData['email']['email'], 0, 80);
}
$stage = $this->config
->stages()
->where('crm_provider_id', (string) $crmData['status_id'])
->where('type', Stage::TYPE_LEAD)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_LEAD], $crmData['status_id']);
}
if (! $stage instanceof Stage) {
return null;
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($name, 0, 191),
'company' => $company,
'domain' => $domain,
'title' => $crmData['title'] ? mb_strimwidth($crmData['title'], 0, 128) : null,
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'mobile_phone' => $mobilePhone,
'stage_id' => $stage->id,
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Lead::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'country_code' => $countryCode,
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->leads()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
/**
* @inheritdoc
*/
public function syncAccounts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
$cpAccounts = $this->copperClient->accounts()->paginate([
'minimum_modified_date' => $since->timestamp,
'sort_by' => 'date_modified',
]);
foreach ($cpAccounts as $cpAccount) {
// Only sync if previously imported.
if ($this->hasAccount($cpAccount['id'])) {
$this->importAccount($cpAccount);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncAccount(string $crmId): ?Account
{
$cpAccount = $this->copperClient->accounts()->find($crmId);
if (empty($cpAccount)) {
return null;
}
return $this->importAccount($cpAccount);
}
/**
* @inheritdoc
*/
private function importAccount($crmData): Account
{
$countryCode = null;
if (empty($crmData['address']) === false && $crmData['address']['country']) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$name = $crmData['name'];
$parsedNumber = null;
foreach ($crmData['phone_numbers'] as $phoneNumber) {
$parsedNumber = parsePhoneNumber($countryCode, $phoneNumber['number']);
}
$domain = null;
if (empty($crmData['websites']) === false) {
$domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);
$domain = StringUtil::resolveDomain($domain);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($name, 0, 191),
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Account::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'country_code' => $countryCode,
'domain' => $domain,
'phone' => $parsedNumber['phone'] ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->accounts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
public function syncOpportunities(array $parameters, ?string $strategy = null): int
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->copperClient,
]);
$strategies = $strategyResolver->getStrategies($this->config, $strategy);
$syncCount = 0;
try {
foreach ($strategies as $syncStrategy) {
foreach ($syncStrategy->fetchOpportunities($parameters) as $opportunityData) {
$this->importOpportunity($opportunityData);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
$this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => $exception->getMessage(),
]);
}
return $syncCount;
}
public function syncOpportunity(string $crmId): ?Opportunity
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->copperClient,
]);
$strategy = $strategyResolver->resolve(
$this->config,
OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY
);
$parameters['crm_id'] = $crmId;
$cpOpportunity = $strategy->fetchOpportunities($parameters);
return $this->importOpportunity($cpOpportunity);
}
private function importOpportunity($crmData): ?Opportunity
{
$companyId = (string) $crmData['company_id'];
if (empty($companyId)) {
$this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => 'No company id',
]);
return null;
}
$account = $this->config->accounts()->where('crm_provider_id', $companyId)->first();
if ($account === null) {
$account = $this->syncAccount($companyId);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', (string) $crmData['pipeline_id'])
->first();
if ($businessProcess === null) {
// It is possible for some deals to not be in a pipeline.
$this->logger->warning(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => 'Missing pipeline',
]);
return null;
}
$stage = $businessProcess
->stages()
->where('crm_provider_id', (string) $crmData['pipeline_stage_id'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
$this->logger->info('Stage not found, importing', [
'pipeline_id' => $crmData['pipeline_id'],
'stage_id' => $crmData['pipeline_stage_id'],
]);
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData['pipeline_stage_id']);
}
$recordType = $businessProcess->recordTypes()->first();
$closeDate = null;
$isClosed = $crmData['status'] !== self::OPPORTUNITY_STATUS_OPEN;
if ($crmData['close_date']) {
$closeDate = Carbon::parse($crmData['close_date'])->format('Y-m-d');
}
$data = [
'team_id' => $this->team->getId(),
'account_id' => $account->id,
'user_id' => $profile->user_id ?? null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($crmData['name'], 0, 128),
'value' => $crmData['monetary_value'],
'currency_code' => CurrencyFormatter::formatCode($crmData['monetary_unit']),
'close_date' => $closeDate,
'is_closed' => $isClosed,
'is_won' => $crmData['status'] === 'Won',
'stage_id' => $stage->id,
'record_type_id' => $recordType->id ?? null,
'remotely_created_at' => $crmData['date_created'],
];
/** @var Opportunity $opportunity */
$opportunity = $this->config
->opportunities()
->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data)
;
// import external fields into crm_field_data if present
$dealInsightsFields = $this->getOpportunitySyncableFields();
$this->importOpportunityCrmFieldData($crmData, $dealInsightsFields, $opportunity->id);
return $opportunity;
}
/**
* @param array<string, mixed> $opportunityData
* @param string[] $dealInsightsFields
*/
public function importOpportunityCrmFieldData(
array $opportunityData,
array $dealInsightsFields,
int $opportunityId
): void {
foreach ($dealInsightsFields as $fieldName) {
$field = $this->config->fields()->with('entities')
->where('crm_provider_id', $fieldName)
->where('object_type', Field::OBJECT_OPPORTUNITY)
->first();
if (! $field instanceof Field) {
$this->logger->warning('Field not found', [
'field' => $fieldName,
'opportunity_id' => $opportunityId,
]);
continue;
}
$entity = $field->getEntities()->first();
if (! $entity instanceof LayoutEntity) {
continue;
}
$fieldValue = $this->extractFieldValue($opportunityData, $fieldName);
$normalizedValue = $this->normalizeValue($field->getType(), (string) $fieldValue, true);
$field->data()
->updateOrCreate([
'crm_layout_entity_id' => $entity->id,
'crm_field_id' => $field->id,
'object_type' => 'opportunity',
'object_id' => $opportunityId,
], ['value' => $normalizedValue])
;
}
}
/**
* @inheritdoc
*/
public function syncContacts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
$cpContacts = $this->copperClient->contacts()->paginate([
'minimum_interaction_date' => $since->timestamp,
'sort_by' => 'date_modified',
]);
foreach ($cpContacts as $cpContact) {
// Only sync if previously imported.
if ($this->hasContact($cpContact['id'])) {
$this->importContact($cpContact);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
throw $exception;
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncContact(string $crmId): ?Contact
{
$cpContact = $this->copperClient->contacts()->find($crmId);
if (empty($cpContact)) {
return null;
}
return $this->importContact($cpContact);
}
/**
* @inheritdoc
*/
private function importContact($crmData): Contact
{
$account = null;
if ($crmData['company_id']) {
$account = $this->team
->crm
->accounts()
->where('crm_provider_id', (string) $crmData['company_id'])
->first();
if ($account === null) {
$account = $this->syncAccount($crmData['company_id']);
}
}
$countryCode = null;
if (empty($crmData['address']) === false && $crmData['address']['country']) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$mobilePhone = $parsedNumber = null;
foreach ($crmData['phone_numbers'] as $phoneNumber) {
if ($phoneNumber['category'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);
} else {
$parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);
}
}
$email = null;
if (empty($crmData['emails']) === false) {
$email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'account_id' => $account->id ?? null,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => $crmData['name'],
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'mobile_phone' => $mobilePhone ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'title' => $crmData['title'],
'country_code' => $countryCode,
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Contact::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
private function buildContactPhone(?string $countryCode, ?string $number): ?array
{
if ($number) {
// Trim to our width and attempt to parse it.
$number = mb_strimwidth($number, 0, 25);
$parsedNumber = parsePhoneNumber($countryCode, $number);
} else {
$parsedNumber = [];
}
return $parsedNumber;
}
private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string
{
return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
$organization = $this->copperClient->organisation()->all();
if ($this->config->crm_provider_id !== $organization['id']) {
$this->config->update(['crm_provider_id' => $organization['id']]);
}
}
private function syncCustomFields(): void
{
foreach ($this->getFieldTypes() as $fieldType) {
$currentFields = $this->getFields($fieldType);
foreach ($currentFields as $field) {
/** @var Field $field */
$field = $this->config->fields()->updateOrCreate([
'crm_provider_id' => $field['name'],
'object_type' => $fieldType,
], [
'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),
'type' => $field['type'],
]);
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
}
$this->config->save();
}
protected function getFieldTypes(): array
{
return [
parent::OBJECT_TASK,
parent::OBJECT_LEAD,
parent::OBJECT_ACCOUNT,
parent::OBJECT_CONTACT,
parent::OBJECT_OPPORTUNITY,
];
}
/**
* @inheritdoc
*/
public function syncProfiles(?User $userToSearch = null): ?Profile
{
$profiles = $this->copperClient->users()->all();
foreach ($profiles as $profile) {
$user = $this->userRepository->findByTeamAndEmailAddress($this->team, $profile['email'], onlyActive: true);
// Only import profiles for users we have locally.
if ($user) {
$profile = $user->crmProfile()->updateOrCreate([
'crm_configuration_id' => $this->config->id,
'crm_provider_id' => $profile['id'],
]);
if ($userToSearch && $userToSearch->id === $user->id) {
return $profile;
}
}
}
return null;
}
/**
* @inheritdoc
*/
public function syncProfileFields(): void
{
$fieldTypes = [
'task',
'lead',
'account',
'contact',
'opportunity',
];
foreach ($fieldTypes as $fieldType) {
try {
$currentFields = $this->getFields(ucfirst($fieldType));
$newFields = array_column($currentFields, 'name');
$changedFields = array_merge(
array_diff($this->profile->getFieldsAsArray($fieldType), $newFields),
array_diff($newFields, $this->profile->getFieldsAsArray($fieldType))
);
if (\count($changedFields) > 0) {
$fields = implode(',', $newFields);
$this->logger->debug(
ucfirst($fieldType)
. ' fields changed from '
. $this->profile->{$fieldType . '_fields'}
. ' to: '
. $fields
);
$this->profile->{$fieldType . '_fields'} = $fields;
}
} catch (\Exception $exception) {
$this->logger->error('No access to ' . $fieldType . ' object, skipping...');
continue;
}
}
$this->profile->save();
}
/**
* @inheritdoc
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
$scopeValues = array_map(fn ($scope) => is_string($scope) ? $scope : $scope->value, $scopes);
$cacheKey = sprintf('copper-search-%d-%s-%s-%d-%d', $this->team->id, $name, implode('-', $scopeValues), $count, $offset);
return Cache::remember($cacheKey, 300, function () use ($name, $scopes, $count, $offset) {
// Try local search first
$localResults = $this->searchLocally($name, $scopes, $count, $offset);
// If no local results, fall back to remote API search
if (empty($localResults)) {
return $this->searchRemotely($name, $scopes, $count, $offset);
}
return $localResults;
});
}
/**
* @inheritdoc
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
$contact = null;
$account = null;
if ($crmAccountId) {
$account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();
if ($account === null) {
$account = $this->syncAccount($crmAccountId);
}
}
if ($crmContactId) {
$contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();
if ($contact === null) {
$contact = $this->syncContact($crmContactId);
}
}
if ($contact || $account) {
if ($contact && $account === null) {
$account = $contact->account;
}
if ($account === null) {
return [];
}
$params = [
'company_ids' => [$account->crm_provider_id],
'status_ids' => [0], // The integer values are 0, 1, 2, 3, for "Open", "Won", "Lost", and "Abandoned".
'sort_by' => 'date_modified',
'sort_direction' => 'desc',
];
switch ($this->config->opportunity_assignment_rule) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['sort_by'] = 'date_modified';
$params['sort_direction'] = 'desc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['sort_by'] = 'date_created';
$params['sort_direction'] = 'desc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['sort_by'] = 'date_created';
$params['sort_direction'] = 'asc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['sort_by'] = 'date_modified';
$params['sort_direction'] = 'desc';
$params['status_ids'] = [0, 1, 2, 3];
}
$cpOpportunities = $this->copperClient->opportunities()->search($params);
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
foreach ($cpOpportunities as $cpOpportunity) {
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', (string) $cpOpportunity['pipeline_id'])
->first();
if ($businessProcess === null) {
// Import it.
$businessProcess = $this->importStages(
[Stage::TYPE_OPPORTUNITY],
$cpOpportunity['pipeline_stage_id']
);
}
$stage = $businessProcess
->stages()
->where('crm_provider_id', (string) $cpOpportunity['pipeline_stage_id'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $cpOpportunity['pipeline_stage_id']);
}
$recordType = $businessProcess->recordTypes()->first();
$record = [
'crmId' => $cpOpportunity['id'],
'name' => $cpOpportunity['name'],
'value' => currency_format($cpOpportunity['monetary_value'], $cpOpportunity['monetary_unit']),
'won' => $cpOpportunity['status'] === 'Won',
'stage' => [
'id' => $stage->id_string,
'name' => $stage->name,
],
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
if ($ownerId && isset($cpOpportunity['assignee_id']) && $cpOpportunity['assignee_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
}
if (! empty($ownerData)) {
return $ownerData;
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array
{
$data = $cpTasks = [];
switch ($objectType) {
case 'lead':
$cpTasks = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->relatedTasks($objectId)
);
break;
case 'account':
$cpTasks = $this->copperClient->accounts()->relatedTasks($objectId);
break;
case 'contact':
if ($opportunityId) {
$cpTasks = $this->copperClient->opportunities()->relatedTasks($opportunityId);
} elseif ($objectType === 'contact') {
$cpTasks = $this->copperClient->contacts()->relatedTasks($objectId);
}
break;
}
foreach ($cpTasks as $cpTask) {
// We only get the ID itself returned, so pull out the full object.
try {
$cpTask = $this->copperClient->tasks()->find($cpTask['id']);
} catch (Exception $exception) {
$this->logger->error('[Copper] Error fetching task', [
'resource_id' => $cpTask['id'],
'error' => $exception->getMessage(),
]);
continue;
}
// Only allow open tasks.
if ($cpTask['status'] === 'Open') {
$data[] = [
'crmId' => $cpTask['id'],
'subject' => $cpTask['name'],
'due' => $cpTask['due_date']
? Carbon::createFromTimestamp($cpTask['due_date'])->format('Y-m-d\TH:i:sO')
: null,
'type' => null,
];
}
}
return $data;
}
/**
* Try to find email address in CRM service
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$cpObjectType = 'contact';
$cpObjects = $this->copperClient->contacts()->search([
'emails' => $email,
'sort_by' => 'date_modified',
'sort_direction' => 'desc',
]);
if (empty($cpObjects)) {
$cpObjectType = 'lead';
$cpObjects = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->search([
'emails' => ...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.054166667,"top":0.027777778,"width":0.08055556,"height":0.035555556},"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":"#12066 on JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.13472222,"top":0.027777778,"width":0.25555557,"height":0.035555556},"on_screen":true,"help_text":"Pull request #12066 exists for current branch JY-20725-handle-HS-search-rate-limit, but local branch is out of sync with remote","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.6326389,"top":0.027777778,"width":0.023611112,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.6645833,"top":0.027777778,"width":0.15902779,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.82361114,"top":0.027777778,"width":0.023611112,"height":0.035555556},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.8472222,"top":0.027777778,"width":0.023611112,"height":0.035555556},"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.87083334,"top":0.027777778,"width":0.023611112,"height":0.035555556},"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.9291667,"top":0.027777778,"width":0.023611112,"height":0.035555556},"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.9527778,"top":0.027777778,"width":0.023611112,"height":0.035555556},"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.9763889,"top":0.027777778,"width":0.023611112,"height":0.035555556},"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":"11","depth":4,"bounds":{"left":0.7340278,"top":0.3122222,"width":0.01875,"height":0.02111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"72","depth":4,"bounds":{"left":0.7569444,"top":0.3122222,"width":0.020833334,"height":0.02111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.78194445,"top":0.3122222,"width":0.015277778,"height":0.02111111},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"bounds":{"left":0.80138886,"top":0.3122222,"width":0.016666668,"height":0.02111111},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.8215278,"top":0.31,"width":0.015277778,"height":0.025555555},"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.8368056,"top":0.31,"width":0.014583333,"height":0.025555555},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Crm\\Copper;\n\nuse Carbon\\Carbon;\nuse Exception;\nuse GuzzleHttp\\Exception\\ClientException;\nuse Illuminate\\Support\\Facades\\Cache;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\CopperInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Crm\\LayoutEntity;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Copper\\Api\\Client;\nuse Jiminny\\Services\\Crm\\Copper\\Api\\ClientFactory;\nuse Jiminny\\Services\\Crm\\Copper\\Exception\\RequestFailedException;\nuse Jiminny\\Services\\Crm\\Helpers\\FilterJoinedParticipants;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Services\\Crm\\Copper\\Traits\\SearchesCrmEntities;\nuse Jiminny\\Utils\\CurrencyFormatter;\nuse Jiminny\\Utils\\StringUtil;\n\nclass Service extends BaseService implements\n CopperInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n RemoteEntityManipulationInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n VerifyTaskExistsInterface\n{\n use SearchesCrmEntities;\n private const int NOTE_BODY_MAX_LENGTH = 3000000;\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n private const array STANDARD_OPPORTUNITY_FIELDS = [\n 'monetary_value' => [\n 'label' => 'Value',\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n 'type' => Field::TYPE_CURRENCY,\n ],\n 'pipeline_stage_id' => [\n 'label' => 'Stage',\n 'type' => Field::TYPE_PICKLIST,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n 'close_date' => [\n 'label' => 'Close date',\n 'type' => Field::TYPE_DATE,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n 'win_probability' => [\n 'label' => 'Win probability',\n 'type' => Field::TYPE_NUMBER,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n ];\n private const string UNSUPPORTED_OBJECT_TYPE = 'unsupported';\n private const string OPPORTUNITY_STATUS_OPEN = 'Open';\n private const string OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE = 'Opportunity import failed';\n private const string RESOURCE_UPDATE_FAILED_ERROR_MESSAGE = 'Failed to update resource';\n\n private FieldValueConverter $fieldValueConverter;\n private ClientFactory $clientFactory;\n private ?Client $copperClient = null;\n\n public function __construct(\n ClientFactory $clientFactory,\n FieldValueConverter $fieldValueConverter,\n private readonly UserRepository $userRepository,\n private readonly ProspectPhotoPathService $prospectPhotoPathService,\n private readonly CrmEntityRepository $crmEntityRepository\n ) {\n parent::__construct();\n\n $this->clientFactory = $clientFactory;\n $this->fieldValueConverter = $fieldValueConverter;\n }\n\n public function getDisplayName(): string\n {\n return 'Copper';\n }\n\n /**\n * Get the CRM entity repository (used by SearchesCrmEntities trait)\n */\n protected function getCrmEntityRepository(): CrmEntityRepository\n {\n return $this->crmEntityRepository;\n }\n\n public function getMinimumApiVersion(): string\n {\n return Client::MIN_API_VERSION;\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n $owner = $user->team->owner;\n\n return $owner->getSocialAccount(SocialAccount::PROVIDER_COPPER);\n }\n\n public function setUser(User $user): void\n {\n $this->configureSentryScope($user);\n\n $this->team = $user->getTeam();\n $this->teamService->setTeam($user->getTeam());\n $this->setConfiguration($user->getTeam()->getCrmConfiguration());\n\n // Reset state.\n $this->profile = $user->getProfile();\n\n if (! $this->profile instanceof Profile) {\n // Try to fetch their profile, maybe it was not yet imported?\n $this->profile = $this->getProfile($user);\n }\n }\n\n public function setConfiguration(Configuration $configuration): void\n {\n $this->config = $configuration;\n $this->copperClient = $this->clientFactory->create($configuration);\n\n if ($this->team === null) {\n $this->team = $configuration->getTeam();\n }\n }\n\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);\n }\n\n private function mapObjectType(string $objectType): string\n {\n $objectType = strtolower($objectType);\n\n switch ($objectType) {\n case Field::OBJECT_TASK:\n case Field::OBJECT_OPPORTUNITY:\n case Field::OBJECT_LEAD:\n $mappedType = $objectType;\n\n break;\n case Field::OBJECT_ACCOUNT:\n $mappedType = 'company';\n\n break;\n case Field::OBJECT_CONTACT:\n $mappedType = 'person';\n\n break;\n default:\n $mappedType = self::UNSUPPORTED_OBJECT_TYPE;\n\n break;\n }\n\n return $mappedType;\n }\n\n /**\n * @param string $crmObject The name of the CRM object. i.e. Opportunity or Contact\n */\n protected function getFields(string $crmObject): array\n {\n $mappedObjectType = $this->mapObjectType($crmObject);\n\n if (! $this->isSupportedObjectType($mappedObjectType)) {\n return [];\n }\n\n $customFields = $this->copperClient->fields()->all();\n\n $filteredFields = array_filter(\n $customFields,\n static fn ($field) => in_array($mappedObjectType, $field['available_on'], true)\n );\n\n return array_map(\n fn (array $property) => [\n 'name' => $property['id'],\n 'label' => $property['name'],\n 'type' => $this->convertFieldType($property['data_type']),\n ],\n $filteredFields\n );\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n // Setup the activity field as the default Type.\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'type',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n $fieldFilters = FieldDefinitions::taskFollowupFieldsFilter();\n\n foreach ($fieldFilters as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n public function syncFields(): void\n {\n $this->syncStandardFields();\n $this->syncCustomFields();\n }\n\n public function syncField(Field $field): void\n {\n if ($field->getCrmProviderId() === 'type') {\n /**\n * This field is a special case, it is not a custom field and is not returned by the Copper API.\n *\n * The field is created manually during layout setup.\n *\n * @see getDefaultFields()\n *\n * There is a separate endpoint to get the activity types.\n * @see importPicklistValues()\n */\n return;\n }\n\n if ($field->getCrmProviderId() === 'pipeline_stage_id') {\n // Not a custom type\n return;\n }\n\n $crmField = $this->copperClient->fields()->find($field->getCrmProviderId());\n $field->label = $crmField['name'];\n $field->type = $this->convertFieldType($crmField['data_type']);\n\n $field->save();\n }\n\n /**\n * @param string $fieldType How the data should be input\n */\n private function convertFieldType(string $fieldType): string\n {\n $fieldType = strtolower($fieldType);\n\n switch ($fieldType) {\n case 'dropdown':\n $convertedType = Field::TYPE_PICKLIST;\n\n break;\n case 'string':\n $convertedType = Field::TYPE_TEXT;\n\n break;\n case 'float':\n case 'percentage':\n $convertedType = Field::TYPE_NUMBER;\n\n break;\n case 'text':\n $convertedType = Field::TYPE_TEXTAREA;\n\n break;\n case 'checkbox':\n $convertedType = Field::TYPE_BOOLEAN;\n\n break;\n case Field::TYPE_DATE:\n case Field::TYPE_CURRENCY:\n case Field::TYPE_URL:\n $convertedType = $fieldType;\n\n break;\n default:\n $convertedType = Field::TYPE_UNSUPPORTED;\n\n break;\n }\n\n return $convertedType;\n }\n\n /**\n * @inheritdoc\n */\n public function importPicklistValues(Field $field): array\n {\n $fieldValues = [];\n\n if ($field->object_type === 'opportunity' && $field->crm_provider_id === 'pipeline_stage_id') {\n return $this->importFieldValuesForDealInsights($field);\n }\n\n $values = [];\n\n if ($field->object_type === Field::OBJECT_TASK && $field->crm_provider_id === 'type') {\n $activityTypes = $this->copperClient->activityTypes()->all();\n\n /**\n * We ignore \"system\" activity types, disabled activity types and the \"Note\" activity type.\n */\n $activityTypes = array_filter(\n $activityTypes['user'],\n fn (array $activityType) => ! $activityType['is_disabled'] && $activityType['id'] !== 0\n );\n\n // Import all activity values.\n $i = 0;\n foreach ($activityTypes as $activityType) {\n $values[] = [\n 'value' => $activityType['id'],\n 'label' => mb_strimwidth($activityType['name'], 0, Field::LABEL_MAX_LENGTH),\n 'sequence' => $i++,\n ];\n }\n } else {\n // We just check for the field in the custom definitions.\n $crmField = $this->copperClient->fields()->find($field->crm_provider_id);\n\n // Import all values.\n foreach ($crmField['options'] as $option) {\n $values[] = [\n 'value' => $option['id'],\n 'label' => mb_strimwidth($option['name'], 0, 191),\n 'sequence' => $option['rank'],\n ];\n }\n }\n\n // Take the existing set of field values.\n $fieldsToPurge = $field->values()->get()->pluck('value')->toArray();\n\n foreach ($values as $value) {\n // For all current values, upsert the field.\n $value['value'] = substr($value['value'] ?? '', 0, 255);\n $fieldValues[] = $field->values()->updateOrCreate([\n 'value' => $value['value'],\n ], $value);\n\n // Remove this value from the ones we are going to purge.\n $key = array_search($value['value'], $fieldsToPurge, false);\n if ($key !== false) {\n unset($fieldsToPurge[$key]);\n }\n }\n\n // Delete the old values that are no longer used.\n $field->values()->whereIn('value', $fieldsToPurge)->delete();\n\n return $fieldValues;\n }\n\n /**\n *\n * @return FieldValue[]\n */\n private function importFieldValuesForDealInsights(Field $field): array\n {\n $fieldValues = [];\n $pipelines = $this->copperClient->pipelines()->all();\n\n foreach ($pipelines as $pipeline) {\n foreach ($pipeline['stages'] as $i => $dealStage) {\n $fieldValues[] = $field->values()->updateOrCreate(\n ['value' => $dealStage['id']],\n [\n 'label' => $dealStage['name'],\n 'sequence' => $i,\n ]\n );\n }\n }\n\n return $fieldValues;\n }\n\n /**\n * @inheritdoc\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n if ($types === null) {\n $types = [Stage::TYPE_LEAD, Stage::TYPE_OPPORTUNITY];\n }\n $missingStage = null;\n\n foreach ($types as $type) {\n if ($type === Stage::TYPE_LEAD) {\n $statuses = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leadStatuses()->all()\n );\n\n if (count($statuses) > 0) {\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => BusinessProcess::TYPE_LEAD,\n ], [\n 'team_id' => $this->team->id,\n 'name' => BusinessProcess::TYPE_LEAD,\n 'type' => BusinessProcess::TYPE_LEAD,\n 'is_selectable' => true,\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => BusinessProcess::TYPE_LEAD,\n ], [\n 'team_id' => $this->team->id,\n 'name' => BusinessProcess::TYPE_LEAD,\n 'is_selectable' => true,\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n $leadStatuses = [];\n foreach ($statuses as $status) {\n // Upsert all statuses for the team.\n $status = $this->config->stages()->updateOrCreate([\n 'crm_provider_id' => $status['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($status['name'], 0, 50),\n 'label' => mb_strimwidth($status['name'], 0, 191),\n 'type' => Stage::TYPE_LEAD,\n 'sequence' => $status['order'],\n 'is_selectable' => true,\n ]);\n\n if ($missingStageName && $missingStageName === $status['id']) {\n $missingStage = $status;\n }\n\n $leadStatuses[] = $status['id'];\n }\n\n $businessProcess->stages()->sync($leadStatuses);\n }\n } else {\n // We create a business process to contain the pipeline, and later store all stages against it.\n foreach ($this->copperClient->pipelines()->all() as $pipeline) {\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => $pipeline['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($pipeline['name'], 0, 150),\n 'type' => BusinessProcess::TYPE_OPPORTUNITY,\n 'is_selectable' => true,\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => $pipeline['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($pipeline['name'], 0, 150),\n 'is_selectable' => true,\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n $stages = [];\n\n foreach ($pipeline['stages'] as $i => $dealStage) {\n // Upsert all stages for the team.\n $stage = $this->config->stages()->updateOrCreate([\n 'crm_provider_id' => $dealStage['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($dealStage['name'], 0, 50),\n 'label' => mb_strimwidth($dealStage['name'], 0, 191),\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'sequence' => $i,\n 'is_selectable' => true,\n 'probability' => $dealStage['win_probability'],\n ]);\n\n if ($missingStageName && $missingStageName === $dealStage['id']) {\n $missingStage = $stage;\n }\n\n $stages[] = $stage['id'];\n }\n\n $businessProcess->stages()->sync($stages);\n }\n }\n }\n\n return $missingStage;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int\n {\n $syncCount = 0;\n\n $cpLeads = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->paginate([\n 'minimum_modified_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ])\n );\n\n foreach ($cpLeads as $cpLead) {\n // Only sync if previously imported.\n if ($this->hasLead($cpLead['id']) === false) {\n $this->importLead($cpLead);\n $syncCount++;\n }\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLead(string $crmId): ?Lead\n {\n $cpLead = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->find($crmId)\n );\n\n if (\\count($cpLead) === 0) {\n return null;\n }\n\n return $this->importLead($cpLead);\n }\n\n /**\n * @inheritdoc\n */\n private function importLead($crmData): ?Lead\n {\n $countryCode = null;\n if (! empty($crmData['address']) && isset($crmData['address']['country'])) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $mobilePhone = $parsedNumber = null;\n if (! empty($crmData['phone_numbers'])) {\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n if ($phoneNumber['category'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);\n } else {\n $parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);\n }\n }\n }\n\n $name = $crmData['name'];\n\n if (empty($crmData['company_name'])) {\n $company = 'Unknown';\n } else {\n $company = mb_strimwidth($crmData['company_name'], 0, 191);\n }\n\n $domain = null;\n if (empty($crmData['websites']) === false) {\n $domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);\n $domain = StringUtil::resolveDomain($domain);\n }\n\n $email = null;\n if (empty($crmData['email']) === false) {\n $email = mb_strimwidth($crmData['email']['email'], 0, 80);\n }\n\n $stage = $this->config\n ->stages()\n ->where('crm_provider_id', (string) $crmData['status_id'])\n ->where('type', Stage::TYPE_LEAD)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_LEAD], $crmData['status_id']);\n }\n\n if (! $stage instanceof Stage) {\n return null;\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($name, 0, 191),\n 'company' => $company,\n 'domain' => $domain,\n 'title' => $crmData['title'] ? mb_strimwidth($crmData['title'], 0, 128) : null,\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'mobile_phone' => $mobilePhone,\n 'stage_id' => $stage->id,\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Lead::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'country_code' => $countryCode,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->leads()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n /**\n * @inheritdoc\n */\n public function syncAccounts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n $cpAccounts = $this->copperClient->accounts()->paginate([\n 'minimum_modified_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ]);\n\n foreach ($cpAccounts as $cpAccount) {\n // Only sync if previously imported.\n if ($this->hasAccount($cpAccount['id'])) {\n $this->importAccount($cpAccount);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncAccount(string $crmId): ?Account\n {\n $cpAccount = $this->copperClient->accounts()->find($crmId);\n\n if (empty($cpAccount)) {\n return null;\n }\n\n return $this->importAccount($cpAccount);\n }\n\n /**\n * @inheritdoc\n */\n private function importAccount($crmData): Account\n {\n $countryCode = null;\n if (empty($crmData['address']) === false && $crmData['address']['country']) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $name = $crmData['name'];\n\n $parsedNumber = null;\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n $parsedNumber = parsePhoneNumber($countryCode, $phoneNumber['number']);\n }\n\n $domain = null;\n if (empty($crmData['websites']) === false) {\n $domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);\n $domain = StringUtil::resolveDomain($domain);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($name, 0, 191),\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Account::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'country_code' => $countryCode,\n 'domain' => $domain,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->accounts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n public function syncOpportunities(array $parameters, ?string $strategy = null): int\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->copperClient,\n ]);\n $strategies = $strategyResolver->getStrategies($this->config, $strategy);\n\n $syncCount = 0;\n\n try {\n foreach ($strategies as $syncStrategy) {\n foreach ($syncStrategy->fetchOpportunities($parameters) as $opportunityData) {\n $this->importOpportunity($opportunityData);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n $this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => $exception->getMessage(),\n ]);\n }\n\n return $syncCount;\n }\n\n public function syncOpportunity(string $crmId): ?Opportunity\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->copperClient,\n ]);\n $strategy = $strategyResolver->resolve(\n $this->config,\n OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY\n );\n\n $parameters['crm_id'] = $crmId;\n\n $cpOpportunity = $strategy->fetchOpportunities($parameters);\n\n return $this->importOpportunity($cpOpportunity);\n }\n\n private function importOpportunity($crmData): ?Opportunity\n {\n $companyId = (string) $crmData['company_id'];\n\n if (empty($companyId)) {\n $this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => 'No company id',\n ]);\n\n return null;\n }\n\n $account = $this->config->accounts()->where('crm_provider_id', $companyId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($companyId);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', (string) $crmData['pipeline_id'])\n ->first();\n\n if ($businessProcess === null) {\n // It is possible for some deals to not be in a pipeline.\n $this->logger->warning(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => 'Missing pipeline',\n ]);\n\n return null;\n }\n\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', (string) $crmData['pipeline_stage_id'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n $this->logger->info('Stage not found, importing', [\n 'pipeline_id' => $crmData['pipeline_id'],\n 'stage_id' => $crmData['pipeline_stage_id'],\n ]);\n\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData['pipeline_stage_id']);\n }\n\n $recordType = $businessProcess->recordTypes()->first();\n $closeDate = null;\n $isClosed = $crmData['status'] !== self::OPPORTUNITY_STATUS_OPEN;\n\n if ($crmData['close_date']) {\n $closeDate = Carbon::parse($crmData['close_date'])->format('Y-m-d');\n }\n\n $data = [\n 'team_id' => $this->team->getId(),\n 'account_id' => $account->id,\n 'user_id' => $profile->user_id ?? null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($crmData['name'], 0, 128),\n 'value' => $crmData['monetary_value'],\n 'currency_code' => CurrencyFormatter::formatCode($crmData['monetary_unit']),\n 'close_date' => $closeDate,\n 'is_closed' => $isClosed,\n 'is_won' => $crmData['status'] === 'Won',\n 'stage_id' => $stage->id,\n 'record_type_id' => $recordType->id ?? null,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n /** @var Opportunity $opportunity */\n $opportunity = $this->config\n ->opportunities()\n ->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data)\n ;\n\n // import external fields into crm_field_data if present\n $dealInsightsFields = $this->getOpportunitySyncableFields();\n $this->importOpportunityCrmFieldData($crmData, $dealInsightsFields, $opportunity->id);\n\n return $opportunity;\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n * @param string[] $dealInsightsFields\n */\n public function importOpportunityCrmFieldData(\n array $opportunityData,\n array $dealInsightsFields,\n int $opportunityId\n ): void {\n foreach ($dealInsightsFields as $fieldName) {\n $field = $this->config->fields()->with('entities')\n ->where('crm_provider_id', $fieldName)\n ->where('object_type', Field::OBJECT_OPPORTUNITY)\n ->first();\n\n if (! $field instanceof Field) {\n $this->logger->warning('Field not found', [\n 'field' => $fieldName,\n 'opportunity_id' => $opportunityId,\n ]);\n\n continue;\n }\n\n $entity = $field->getEntities()->first();\n\n if (! $entity instanceof LayoutEntity) {\n continue;\n }\n\n $fieldValue = $this->extractFieldValue($opportunityData, $fieldName);\n $normalizedValue = $this->normalizeValue($field->getType(), (string) $fieldValue, true);\n\n $field->data()\n ->updateOrCreate([\n 'crm_layout_entity_id' => $entity->id,\n 'crm_field_id' => $field->id,\n 'object_type' => 'opportunity',\n 'object_id' => $opportunityId,\n ], ['value' => $normalizedValue])\n ;\n }\n }\n\n /**\n * @inheritdoc\n */\n public function syncContacts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n $cpContacts = $this->copperClient->contacts()->paginate([\n 'minimum_interaction_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ]);\n\n foreach ($cpContacts as $cpContact) {\n // Only sync if previously imported.\n if ($this->hasContact($cpContact['id'])) {\n $this->importContact($cpContact);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n throw $exception;\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncContact(string $crmId): ?Contact\n {\n $cpContact = $this->copperClient->contacts()->find($crmId);\n\n if (empty($cpContact)) {\n return null;\n }\n\n return $this->importContact($cpContact);\n }\n\n /**\n * @inheritdoc\n */\n private function importContact($crmData): Contact\n {\n $account = null;\n if ($crmData['company_id']) {\n $account = $this->team\n ->crm\n ->accounts()\n ->where('crm_provider_id', (string) $crmData['company_id'])\n ->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmData['company_id']);\n }\n }\n\n $countryCode = null;\n if (empty($crmData['address']) === false && $crmData['address']['country']) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $mobilePhone = $parsedNumber = null;\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n if ($phoneNumber['category'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);\n } else {\n $parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);\n }\n }\n\n $email = null;\n if (empty($crmData['emails']) === false) {\n $email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'account_id' => $account->id ?? null,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => $crmData['name'],\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'mobile_phone' => $mobilePhone ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'title' => $crmData['title'],\n 'country_code' => $countryCode,\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Contact::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n private function buildContactPhone(?string $countryCode, ?string $number): ?array\n {\n if ($number) {\n // Trim to our width and attempt to parse it.\n $number = mb_strimwidth($number, 0, 25);\n $parsedNumber = parsePhoneNumber($countryCode, $number);\n } else {\n $parsedNumber = [];\n }\n\n return $parsedNumber;\n }\n\n private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string\n {\n return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;\n }\n\n /**\n * @inheritdoc\n */\n public function syncOrganization(): void\n {\n $organization = $this->copperClient->organisation()->all();\n\n if ($this->config->crm_provider_id !== $organization['id']) {\n $this->config->update(['crm_provider_id' => $organization['id']]);\n }\n }\n\n private function syncCustomFields(): void\n {\n foreach ($this->getFieldTypes() as $fieldType) {\n $currentFields = $this->getFields($fieldType);\n\n foreach ($currentFields as $field) {\n /** @var Field $field */\n $field = $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => $field['name'],\n 'object_type' => $fieldType,\n ], [\n 'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),\n 'type' => $field['type'],\n ]);\n\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n }\n\n $this->config->save();\n }\n\n protected function getFieldTypes(): array\n {\n return [\n parent::OBJECT_TASK,\n parent::OBJECT_LEAD,\n parent::OBJECT_ACCOUNT,\n parent::OBJECT_CONTACT,\n parent::OBJECT_OPPORTUNITY,\n ];\n }\n\n /**\n * @inheritdoc\n */\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n $profiles = $this->copperClient->users()->all();\n\n foreach ($profiles as $profile) {\n $user = $this->userRepository->findByTeamAndEmailAddress($this->team, $profile['email'], onlyActive: true);\n\n // Only import profiles for users we have locally.\n if ($user) {\n $profile = $user->crmProfile()->updateOrCreate([\n 'crm_configuration_id' => $this->config->id,\n 'crm_provider_id' => $profile['id'],\n ]);\n\n if ($userToSearch && $userToSearch->id === $user->id) {\n return $profile;\n }\n }\n }\n\n return null;\n }\n\n /**\n * @inheritdoc\n */\n public function syncProfileFields(): void\n {\n $fieldTypes = [\n 'task',\n 'lead',\n 'account',\n 'contact',\n 'opportunity',\n ];\n\n foreach ($fieldTypes as $fieldType) {\n try {\n $currentFields = $this->getFields(ucfirst($fieldType));\n\n $newFields = array_column($currentFields, 'name');\n $changedFields = array_merge(\n array_diff($this->profile->getFieldsAsArray($fieldType), $newFields),\n array_diff($newFields, $this->profile->getFieldsAsArray($fieldType))\n );\n\n if (\\count($changedFields) > 0) {\n $fields = implode(',', $newFields);\n $this->logger->debug(\n ucfirst($fieldType)\n . ' fields changed from '\n . $this->profile->{$fieldType . '_fields'}\n . ' to: '\n . $fields\n );\n\n $this->profile->{$fieldType . '_fields'} = $fields;\n }\n } catch (\\Exception $exception) {\n $this->logger->error('No access to ' . $fieldType . ' object, skipping...');\n\n continue;\n }\n }\n\n $this->profile->save();\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n $scopeValues = array_map(fn ($scope) => is_string($scope) ? $scope : $scope->value, $scopes);\n $cacheKey = sprintf('copper-search-%d-%s-%s-%d-%d', $this->team->id, $name, implode('-', $scopeValues), $count, $offset);\n\n return Cache::remember($cacheKey, 300, function () use ($name, $scopes, $count, $offset) {\n // Try local search first\n $localResults = $this->searchLocally($name, $scopes, $count, $offset);\n\n // If no local results, fall back to remote API search\n if (empty($localResults)) {\n return $this->searchRemotely($name, $scopes, $count, $offset);\n }\n\n return $localResults;\n });\n }\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n $contact = null;\n $account = null;\n\n if ($crmAccountId) {\n $account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmAccountId);\n }\n }\n\n if ($crmContactId) {\n $contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();\n\n if ($contact === null) {\n $contact = $this->syncContact($crmContactId);\n }\n }\n\n if ($contact || $account) {\n if ($contact && $account === null) {\n $account = $contact->account;\n }\n\n if ($account === null) {\n return [];\n }\n\n $params = [\n 'company_ids' => [$account->crm_provider_id],\n 'status_ids' => [0], // The integer values are 0, 1, 2, 3, for \"Open\", \"Won\", \"Lost\", and \"Abandoned\".\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ];\n\n switch ($this->config->opportunity_assignment_rule) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['sort_by'] = 'date_modified';\n $params['sort_direction'] = 'desc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['sort_by'] = 'date_created';\n $params['sort_direction'] = 'desc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['sort_by'] = 'date_created';\n $params['sort_direction'] = 'asc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['sort_by'] = 'date_modified';\n $params['sort_direction'] = 'desc';\n $params['status_ids'] = [0, 1, 2, 3];\n }\n\n $cpOpportunities = $this->copperClient->opportunities()->search($params);\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n foreach ($cpOpportunities as $cpOpportunity) {\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', (string) $cpOpportunity['pipeline_id'])\n ->first();\n\n if ($businessProcess === null) {\n // Import it.\n $businessProcess = $this->importStages(\n [Stage::TYPE_OPPORTUNITY],\n $cpOpportunity['pipeline_stage_id']\n );\n }\n\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', (string) $cpOpportunity['pipeline_stage_id'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $cpOpportunity['pipeline_stage_id']);\n }\n\n $recordType = $businessProcess->recordTypes()->first();\n\n $record = [\n 'crmId' => $cpOpportunity['id'],\n 'name' => $cpOpportunity['name'],\n 'value' => currency_format($cpOpportunity['monetary_value'], $cpOpportunity['monetary_unit']),\n 'won' => $cpOpportunity['status'] === 'Won',\n 'stage' => [\n 'id' => $stage->id_string,\n 'name' => $stage->name,\n ],\n 'recordType' => [\n 'id' => $recordType->id_string,\n 'name' => $recordType->name,\n ],\n ];\n\n if ($ownerId && isset($cpOpportunity['assignee_id']) && $cpOpportunity['assignee_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = $cpTasks = [];\n\n switch ($objectType) {\n case 'lead':\n $cpTasks = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->relatedTasks($objectId)\n );\n\n break;\n\n case 'account':\n $cpTasks = $this->copperClient->accounts()->relatedTasks($objectId);\n\n break;\n case 'contact':\n if ($opportunityId) {\n $cpTasks = $this->copperClient->opportunities()->relatedTasks($opportunityId);\n } elseif ($objectType === 'contact') {\n $cpTasks = $this->copperClient->contacts()->relatedTasks($objectId);\n }\n\n break;\n }\n\n foreach ($cpTasks as $cpTask) {\n // We only get the ID itself returned, so pull out the full object.\n try {\n $cpTask = $this->copperClient->tasks()->find($cpTask['id']);\n } catch (Exception $exception) {\n $this->logger->error('[Copper] Error fetching task', [\n 'resource_id' => $cpTask['id'],\n 'error' => $exception->getMessage(),\n ]);\n\n continue;\n }\n\n // Only allow open tasks.\n if ($cpTask['status'] === 'Open') {\n $data[] = [\n 'crmId' => $cpTask['id'],\n 'subject' => $cpTask['name'],\n 'due' => $cpTask['due_date']\n ? Carbon::createFromTimestamp($cpTask['due_date'])->format('Y-m-d\\TH:i:sO')\n : null,\n 'type' => null,\n ];\n }\n }\n\n return $data;\n }\n\n /**\n * Try to find email address in CRM service\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $cpObjectType = 'contact';\n\n $cpObjects = $this->copperClient->contacts()->search([\n 'emails' => $email,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (empty($cpObjects)) {\n $cpObjectType = 'lead';\n $cpObjects = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'emails' => $email,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (empty($cpObjects)) {\n return null;\n }\n\n // Search returns an array of results, but we only want the first\n $cpObject = reset($cpObjects);\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n // Check if the user is internal.\n $teamMember = $this->team->users()->where('phone', $phone)->exists();\n\n // Skip the attendee if internal.\n if ($teamMember === false) {\n $cpObjectType = 'contact';\n $cpObject = $this->copperClient->contacts()->search([\n 'phone_number' => $phone,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (\\count($cpObject) === 0) {\n $cpObjectType = 'lead';\n $cpObject = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'phone_number' => $phone,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (empty($cpObject)) {\n return null;\n }\n\n $cpObject = reset($cpObject);\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n return null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $result = \\Cache::remember($this->team->id . $name, 60, function () use ($name, $userId) {\n $cpObjectType = 'contact';\n $cpObject = $this->copperClient->contacts()->search([\n 'name' => $name,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (\\count($cpObject) === 0) {\n $cpObjectType = 'lead';\n $cpObject = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'name' => $name,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (! empty($cpObject)) {\n $cpObject = reset($cpObject);\n }\n\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : false;\n });\n\n return is_array($result) ? $result : null;\n }\n\n private function convertCrmData(array $object, string $objectType, ?int $userId = null): array\n {\n $lead = null;\n $contact = null;\n $opportunity = null;\n $account = null;\n $stage = null;\n $countryCode = null;\n\n if ($objectType === 'lead') {\n $lead = $this->importLead($object);\n\n // Lead might not be imported if the Stage is null for example.\n if ($lead) {\n $countryCode = $lead->country_code;\n $stage = $lead->stage;\n }\n } else {\n $contact = $this->importContact($object);\n $account = $contact->account;\n\n if ($contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account) {\n $countryCode = $account->country_code;\n }\n\n try {\n $cpOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId,\n );\n\n if (! empty($cpOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($cpOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (\\Exception $e) {\n // Nothing to see here.\n }\n }\n\n return [\n $lead,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n public function saveActivity(Activity $activity): Activity\n {\n switch ($activity->type) {\n case Activity::TYPE_CONFERENCE:\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n $activity = $this->buildCallPayload($activity);\n\n break;\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $activity = $this->buildTextMessagePayload($activity);\n\n break;\n }\n\n return $activity;\n }\n\n private function convertActivityAssociations(Activity $activity): array\n {\n if ($activity->lead) {\n $type = 'lead';\n $id = $activity->lead->crm_provider_id;\n } elseif ($activity->contact) {\n $type = 'person';\n $id = $activity->contact->crm_provider_id;\n } elseif ($activity->opportunity) {\n $type = 'opportunity';\n $id = $activity->opportunity->crm_provider_id;\n } else {\n $type = 'company';\n $id = $activity->account->crm_provider_id;\n }\n\n return [\n 'type' => $type,\n 'id' => $id,\n ];\n }\n\n private function convertActivityType(PlaybookCategory $activityType): array\n {\n return [\n 'category' => 'user',\n 'id' => $this->getCrmType($activityType)->value,\n ];\n }\n\n /**\n * @throws CrmException\n */\n private function buildCallPayload(Activity $activity): Activity\n {\n try {\n if ($activity->crm_provider_id) {\n // The activity should be logged under the existing Task (not Activity).\n $newActivityType = $this->getCrmType($activity->category);\n if ($newActivityType === null) {\n $message = sprintf('[Copper] invalid CRM Custom Activity Type: %s', $activity->category);\n\n throw new CrmException($message, 400);\n }\n $this->copperClient->tasks()->update($activity->crm_provider_id, [\n 'status' => 'Completed',\n 'custom_activity_type_id' => $newActivityType->value,\n 'details' => $this->generateActivityDescription($activity),\n ]);\n } else {\n if ($this->getCrmType($activity->category) === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n if ($this->getCrmType($activity->category)->value === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n // Just create an activity.\n $cpActivity = $this->copperClient->activities()->create([\n 'user_id' => $this->profile->crm_provider_id,\n 'activity_date' => $activity->scheduled_start_time->timestamp,\n 'parent' => $this->convertActivityAssociations($activity),\n 'type' => $this->convertActivityType($activity->category),\n 'details' => $this->generateActivityDescription($activity),\n ]);\n\n $activity->crm_provider_id = $cpActivity['id'];\n $activity->save();\n }\n } catch (ClientException $exception) {\n //Log all errors to Sentry\n \\Sentry::captureException($exception);\n\n $response = $exception->getResponse();\n\n $responseBody = $response->getBody();\n $message = $responseBody;\n $errorCode = $response->getStatusCode();\n\n $jsonResponse = json_decode($responseBody, true);\n if (isset($jsonResponse[0]['message'])) {\n $message = $jsonResponse[0]['message'];\n }\n\n throw new CrmException($message, $errorCode);\n }\n\n return $activity;\n }\n\n private function buildTextMessagePayload(Activity $activity): Activity\n {\n if ($this->getCrmType($activity->category) === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n if ($this->getCrmType($activity->category)->value === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n $cpActivity = $this->copperClient->activities()->create([\n 'user_id' => $this->profile->crm_provider_id,\n 'activity_date' => $activity->created_at->timestamp,\n 'parent' => $this->convertActivityAssociations($activity),\n 'type' => $this->convertActivityType($activity->category),\n 'details' => $this->generateActivityDescription($activity),\n ]);\n\n $activity->crm_provider_id = $cpActivity['id'];\n $activity->save();\n\n return $activity;\n }\n\n private function generateActivityDescription(Activity $activity): string\n {\n $description = '';\n\n switch ($activity->type) {\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n case Activity::TYPE_CONFERENCE:\n\n $description = 'Jiminny Call Summary' . PHP_EOL . PHP_EOL;\n $description .= 'Call Duration: ' . $activity->duration_for_humans . PHP_EOL . PHP_EOL;\n\n // Tell them which number was dialed.\n if ($activity->to) {\n $description .= 'Dialed: ' . $activity->to->phone_number . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->hasReasonCodeBotKicked()) {\n $description .= 'Notetaker removed from this meeting' . PHP_EOL . PHP_EOL;\n // When we fix the state to be Activity::RECORDING_RECORDED as it should be this can change.\n } elseif ($activity->hasReasonCodeNotCompliant()) {\n $description .= 'Notetaker did not join due to recording consent not being provided by attendees' . PHP_EOL . PHP_EOL;\n } elseif ($activity->canReviewActivity()) {\n $playbackUrl = $activity->user->team->partner->getPlaybackUrl($activity);\n $description .= 'Review Activity:' . PHP_EOL . $playbackUrl . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->getCrmType() === Activity::TYPE_CONFERENCE) {\n $description .= 'Attendees:'\n . PHP_EOL\n . (new FilterJoinedParticipants())->toString($activity);\n }\n\n if (\\count($activity->notes) > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Notes: ' . PHP_EOL;\n\n foreach ($activity->notes as $note) {\n $nTime = (int) ceil($note->time);\n $time = ($nTime > 3600) ? gmdate('H:i:s', $nTime) : gmdate('i:s', $nTime);\n $description .= $time . ' ' . $note->note . PHP_EOL;\n }\n }\n\n // Get all private messages.\n $messages = $activity->messages()\n ->where('is_private', 1)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Coaching Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n // Get all public messages.\n $messages = $activity->messages()\n ->where('is_private', 0)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Customer Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n if ($activity->summary) {\n $description .= PHP_EOL . PHP_EOL . 'Summary: ' . PHP_EOL . $activity->summary;\n }\n\n break;\n\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $description = $activity->description;\n\n break;\n }\n\n return $description;\n }\n\n public function saveFollowupActivity(Activity $activity, array $fields): ?string\n {\n // This is the user provided activity subject field.\n if (empty($fields['type'])) {\n return null;\n }\n\n $reminder = null;\n if (empty($fields['reminder_date']) === false) {\n $formatReminder = Carbon::createFromFormat('Y-m-d\\TH:i:s\\Z', $fields['reminder_date']);\n $reminder = $formatReminder->getTimestamp();\n }\n\n $due = null;\n if (empty($fields['due_date']) === false) {\n $formatDue = Carbon::createFromFormat('Y-m-d\\TH:i:s\\Z', $fields['due_date']);\n $due = $formatDue->getTimestamp();\n }\n\n $data = [\n 'custom_activity_type_id' => $fields['type'],\n 'status' => 'Open',\n 'assignee_id' => $this->profile->crm_provider_id,\n 'due_date' => $due,\n 'details' => $fields['details'] ?? '',\n 'reminder_date' => $reminder,\n 'name' => $fields['name'] ?? 'Follow-up',\n 'related_resource' => $this->convertActivityAssociations($activity),\n 'custom_fields' => $this->fetchCustomFieldData($activity, Field::OBJECT_TASK),\n ];\n\n // We don't actually create a corresponding activity object on our side yet.\n return $this->copperClient->tasks()->create($data)['id'];\n }\n\n /**\n * Store transcripts as note.\n *\n * @throws \\Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, static::NOTE_BODY_MAX_LENGTH);\n\n $data = [\n 'user_id' => $this->profile->crm_provider_id,\n 'type' => [\n 'category' => 'user',\n 'id' => 0, // This creates a note.\n ],\n 'activity_date' => time(),\n 'details' => $transcripts,\n 'parent' => $this->convertActivityAssociations($activity),\n ];\n\n $cpActivity = $this->copperClient->activities()->create($data);\n\n // Store CRM Activity ID in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $cpActivity['id'];\n $transcription->save();\n }\n\n /**\n * @inheritdoc\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n if ($crmObject instanceof Lead) {\n $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->update($crmObject->crm_provider_id, [\n 'status_id' => $stage->crm_provider_id,\n ])\n );\n } else {\n $this->copperClient->opportunities()->update($crmObject->crm_provider_id, [\n 'pipeline_stage_id' => $stage->crm_provider_id,\n ]);\n }\n }\n\n public function prepareValueForUpdate(array $params): array\n {\n return [$params['fieldName'] => $params['fieldValue']];\n }\n\n /*\n * @inheritdoc\n */\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $preparedData = $data;\n\n if ($objectType === Field::OBJECT_OPPORTUNITY) {\n $preparedData = $this->prepareOpportunityFieldsForUpdate($data);\n }\n\n try {\n $this->copperClient\n ->createResourceFromObjectType($objectType)\n ->update($objectId, $preparedData)\n ;\n } catch (Exception $e) {\n $this->logger->error(self::RESOURCE_UPDATE_FAILED_ERROR_MESSAGE, [\n 'resource_id' => $objectId,\n 'data' => $preparedData,\n 'error' => $e->getMessage(),\n ]);\n\n throw new CrmException(self::RESOURCE_UPDATE_FAILED_ERROR_MESSAGE, $e->getCode(), $e);\n }\n }\n\n /**\n * @param array<string,string> $fieldData\n *\n * @throws CrmException\n *\n * @return array<string,array<int,array<string,bool|float|int|string|null>>|bool|float|int|string|null>\n */\n private function prepareOpportunityFieldsForUpdate(array $fieldData): array\n {\n $preparedData = [];\n $customFields = [];\n\n foreach ($fieldData as $fieldName => $fieldValue) {\n $field = $this->config\n ->fields()\n ->where('crm_provider_id', $fieldName)\n ->first();\n\n if (! $field instanceof Field) {\n throw new CrmException('Field not found');\n }\n\n $convertedValue = $this->fieldValueConverter->convertToCrm($field->getType(), $fieldValue);\n\n if ($this->isStandardField($fieldName)) {\n $preparedData[$fieldName] = $convertedValue;\n\n continue;\n }\n\n $customFields[] = [\n 'custom_field_definition_id' => $fieldName,\n 'value' => $convertedValue,\n ];\n }\n\n if (! empty($customFields)) {\n $preparedData['custom_fields'] = $customFields;\n }\n\n return $preparedData;\n }\n\n /*\n * @inheritdoc\n */\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n return $this->copperClient->createResourceFromObjectType($objectType)->find($objectId);\n }\n\n private function fetchCustomFieldData(Activity $activity, string $objectType): array\n {\n $payload = [];\n\n $fieldData = FieldData::where([\n 'object_id' => $activity->id,\n ])->whereHas('field', function ($query) use ($objectType) {\n $query->where('object_type', $objectType);\n })->get();\n\n foreach ($fieldData as $data) {\n // Add the field and value to the payload.\n $payload += [\n 'custom_field_definition_id' => $data->field->crm_provider_id,\n 'value' => $data->value,\n ];\n }\n\n return $payload;\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $baseUrl = 'https://app.prosperworks.com/companies/' . $this->config->crm_provider_id . '/app#/';\n switch ($objectType) {\n case 'lead':\n $url = $baseUrl . 'leads/' . $providerId;\n\n break;\n\n case 'account':\n $url = $baseUrl . 'organization/' . $providerId;\n\n break;\n\n case 'contact':\n $url = $baseUrl . 'contact/' . $providerId;\n\n break;\n\n case 'opportunity':\n $url = $baseUrl . 'deal/' . $providerId;\n\n break;\n\n default:\n case 'task':\n case 'activity':\n // Sadly we can't deeplink to these in Copper UI.\n $url = null;\n }\n\n return $url;\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! ($this->config->store_transcript)) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n return $this->transcriptionService\n ->findTranscriptionByActivity($activity)\n ->map(static function (array $transcriptionSegment): string {\n return $transcriptionSegment['formattedStartsAt'] . ' | ' . $transcriptionSegment['transcript'];\n })\n ->implode(PHP_EOL);\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n *\n * @return int|string|bool|float|null\n */\n private function extractFieldValue(array $opportunityData, string $fieldName)\n {\n $fieldValue = $this->isStandardField($fieldName)\n ? $opportunityData[$fieldName]\n : $this->resolveCustomFieldFromOpportunityData($opportunityData, $fieldName);\n\n if (is_array($fieldValue)) {\n $fieldValue = implode(', ', $fieldValue);\n }\n\n return $fieldValue;\n }\n\n private function isStandardField(string $fieldName): bool\n {\n return array_key_exists($fieldName, self::STANDARD_OPPORTUNITY_FIELDS);\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n *\n * @return string|int|float|bool|null|array<string, mixed>\n */\n private function resolveCustomFieldFromOpportunityData(array $opportunityData, string $fieldName)\n {\n $fieldData = array_filter(\n $opportunityData['custom_fields'],\n static fn ($field) => (string) $field['custom_field_definition_id'] === $fieldName\n );\n\n return array_pop($fieldData)['value'] ?? '';\n }\n\n private function isSupportedObjectType(string $objectType): bool\n {\n return $objectType !== self::UNSUPPORTED_OBJECT_TYPE;\n }\n\n private function syncStandardFields(): void\n {\n foreach (self::STANDARD_OPPORTUNITY_FIELDS as $fieldId => $fieldData) {\n $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => mb_strimwidth($fieldId, 0, 128),\n 'object_type' => Field::OBJECT_OPPORTUNITY,\n ], [\n 'label' => mb_strimwidth($fieldData['label'], 0, Field::LABEL_MAX_LENGTH),\n 'type' => $fieldData['type'],\n ]);\n }\n\n $this->importStages([Stage::TYPE_OPPORTUNITY]);\n }\n\n private function requestWithExceptionHandling(\\Closure $apiRequest): iterable\n {\n try {\n return $apiRequest();\n } catch (\\Exception $exception) {\n if ($exception->getCode() === 403) {\n // Object might not be supported\n return [];\n }\n\n \\Sentry::captureException($exception);\n\n return [];\n }\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n if ($this->copperClient === null) {\n return false;\n }\n\n $task = $this->copperClient->tasks()->find($crmProviderId);\n\n return ! empty($task);\n } catch (HttpNotFoundException) {\n // Task not found in CRM - this is expected and permanent\n $this->logger->info('[Copper] Task not found during verification', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n } catch (RequestFailedException $e) {\n // Handle 404 responses from Copper API\n if ($e->getCode() === 404) {\n $this->logger->info('[Copper] Task not found during verification (404)', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n\n // Re-throw other Copper exceptions for retry\n throw $e;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\n });\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Crm\\Copper;\n\nuse Carbon\\Carbon;\nuse Exception;\nuse GuzzleHttp\\Exception\\ClientException;\nuse Illuminate\\Support\\Facades\\Cache;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\CopperInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Crm\\LayoutEntity;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Copper\\Api\\Client;\nuse Jiminny\\Services\\Crm\\Copper\\Api\\ClientFactory;\nuse Jiminny\\Services\\Crm\\Copper\\Exception\\RequestFailedException;\nuse Jiminny\\Services\\Crm\\Helpers\\FilterJoinedParticipants;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Services\\Crm\\Copper\\Traits\\SearchesCrmEntities;\nuse Jiminny\\Utils\\CurrencyFormatter;\nuse Jiminny\\Utils\\StringUtil;\n\nclass Service extends BaseService implements\n CopperInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n RemoteEntityManipulationInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n VerifyTaskExistsInterface\n{\n use SearchesCrmEntities;\n private const int NOTE_BODY_MAX_LENGTH = 3000000;\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n private const array STANDARD_OPPORTUNITY_FIELDS = [\n 'monetary_value' => [\n 'label' => 'Value',\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n 'type' => Field::TYPE_CURRENCY,\n ],\n 'pipeline_stage_id' => [\n 'label' => 'Stage',\n 'type' => Field::TYPE_PICKLIST,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n 'close_date' => [\n 'label' => 'Close date',\n 'type' => Field::TYPE_DATE,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n 'win_probability' => [\n 'label' => 'Win probability',\n 'type' => Field::TYPE_NUMBER,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n ];\n private const string UNSUPPORTED_OBJECT_TYPE = 'unsupported';\n private const string OPPORTUNITY_STATUS_OPEN = 'Open';\n private const string OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE = 'Opportunity import failed';\n private const string RESOURCE_UPDATE_FAILED_ERROR_MESSAGE = 'Failed to update resource';\n\n private FieldValueConverter $fieldValueConverter;\n private ClientFactory $clientFactory;\n private ?Client $copperClient = null;\n\n public function __construct(\n ClientFactory $clientFactory,\n FieldValueConverter $fieldValueConverter,\n private readonly UserRepository $userRepository,\n private readonly ProspectPhotoPathService $prospectPhotoPathService,\n private readonly CrmEntityRepository $crmEntityRepository\n ) {\n parent::__construct();\n\n $this->clientFactory = $clientFactory;\n $this->fieldValueConverter = $fieldValueConverter;\n }\n\n public function getDisplayName(): string\n {\n return 'Copper';\n }\n\n /**\n * Get the CRM entity repository (used by SearchesCrmEntities trait)\n */\n protected function getCrmEntityRepository(): CrmEntityRepository\n {\n return $this->crmEntityRepository;\n }\n\n public function getMinimumApiVersion(): string\n {\n return Client::MIN_API_VERSION;\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n $owner = $user->team->owner;\n\n return $owner->getSocialAccount(SocialAccount::PROVIDER_COPPER);\n }\n\n public function setUser(User $user): void\n {\n $this->configureSentryScope($user);\n\n $this->team = $user->getTeam();\n $this->teamService->setTeam($user->getTeam());\n $this->setConfiguration($user->getTeam()->getCrmConfiguration());\n\n // Reset state.\n $this->profile = $user->getProfile();\n\n if (! $this->profile instanceof Profile) {\n // Try to fetch their profile, maybe it was not yet imported?\n $this->profile = $this->getProfile($user);\n }\n }\n\n public function setConfiguration(Configuration $configuration): void\n {\n $this->config = $configuration;\n $this->copperClient = $this->clientFactory->create($configuration);\n\n if ($this->team === null) {\n $this->team = $configuration->getTeam();\n }\n }\n\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);\n }\n\n private function mapObjectType(string $objectType): string\n {\n $objectType = strtolower($objectType);\n\n switch ($objectType) {\n case Field::OBJECT_TASK:\n case Field::OBJECT_OPPORTUNITY:\n case Field::OBJECT_LEAD:\n $mappedType = $objectType;\n\n break;\n case Field::OBJECT_ACCOUNT:\n $mappedType = 'company';\n\n break;\n case Field::OBJECT_CONTACT:\n $mappedType = 'person';\n\n break;\n default:\n $mappedType = self::UNSUPPORTED_OBJECT_TYPE;\n\n break;\n }\n\n return $mappedType;\n }\n\n /**\n * @param string $crmObject The name of the CRM object. i.e. Opportunity or Contact\n */\n protected function getFields(string $crmObject): array\n {\n $mappedObjectType = $this->mapObjectType($crmObject);\n\n if (! $this->isSupportedObjectType($mappedObjectType)) {\n return [];\n }\n\n $customFields = $this->copperClient->fields()->all();\n\n $filteredFields = array_filter(\n $customFields,\n static fn ($field) => in_array($mappedObjectType, $field['available_on'], true)\n );\n\n return array_map(\n fn (array $property) => [\n 'name' => $property['id'],\n 'label' => $property['name'],\n 'type' => $this->convertFieldType($property['data_type']),\n ],\n $filteredFields\n );\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n // Setup the activity field as the default Type.\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'type',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n $fieldFilters = FieldDefinitions::taskFollowupFieldsFilter();\n\n foreach ($fieldFilters as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n public function syncFields(): void\n {\n $this->syncStandardFields();\n $this->syncCustomFields();\n }\n\n public function syncField(Field $field): void\n {\n if ($field->getCrmProviderId() === 'type') {\n /**\n * This field is a special case, it is not a custom field and is not returned by the Copper API.\n *\n * The field is created manually during layout setup.\n *\n * @see getDefaultFields()\n *\n * There is a separate endpoint to get the activity types.\n * @see importPicklistValues()\n */\n return;\n }\n\n if ($field->getCrmProviderId() === 'pipeline_stage_id') {\n // Not a custom type\n return;\n }\n\n $crmField = $this->copperClient->fields()->find($field->getCrmProviderId());\n $field->label = $crmField['name'];\n $field->type = $this->convertFieldType($crmField['data_type']);\n\n $field->save();\n }\n\n /**\n * @param string $fieldType How the data should be input\n */\n private function convertFieldType(string $fieldType): string\n {\n $fieldType = strtolower($fieldType);\n\n switch ($fieldType) {\n case 'dropdown':\n $convertedType = Field::TYPE_PICKLIST;\n\n break;\n case 'string':\n $convertedType = Field::TYPE_TEXT;\n\n break;\n case 'float':\n case 'percentage':\n $convertedType = Field::TYPE_NUMBER;\n\n break;\n case 'text':\n $convertedType = Field::TYPE_TEXTAREA;\n\n break;\n case 'checkbox':\n $convertedType = Field::TYPE_BOOLEAN;\n\n break;\n case Field::TYPE_DATE:\n case Field::TYPE_CURRENCY:\n case Field::TYPE_URL:\n $convertedType = $fieldType;\n\n break;\n default:\n $convertedType = Field::TYPE_UNSUPPORTED;\n\n break;\n }\n\n return $convertedType;\n }\n\n /**\n * @inheritdoc\n */\n public function importPicklistValues(Field $field): array\n {\n $fieldValues = [];\n\n if ($field->object_type === 'opportunity' && $field->crm_provider_id === 'pipeline_stage_id') {\n return $this->importFieldValuesForDealInsights($field);\n }\n\n $values = [];\n\n if ($field->object_type === Field::OBJECT_TASK && $field->crm_provider_id === 'type') {\n $activityTypes = $this->copperClient->activityTypes()->all();\n\n /**\n * We ignore \"system\" activity types, disabled activity types and the \"Note\" activity type.\n */\n $activityTypes = array_filter(\n $activityTypes['user'],\n fn (array $activityType) => ! $activityType['is_disabled'] && $activityType['id'] !== 0\n );\n\n // Import all activity values.\n $i = 0;\n foreach ($activityTypes as $activityType) {\n $values[] = [\n 'value' => $activityType['id'],\n 'label' => mb_strimwidth($activityType['name'], 0, Field::LABEL_MAX_LENGTH),\n 'sequence' => $i++,\n ];\n }\n } else {\n // We just check for the field in the custom definitions.\n $crmField = $this->copperClient->fields()->find($field->crm_provider_id);\n\n // Import all values.\n foreach ($crmField['options'] as $option) {\n $values[] = [\n 'value' => $option['id'],\n 'label' => mb_strimwidth($option['name'], 0, 191),\n 'sequence' => $option['rank'],\n ];\n }\n }\n\n // Take the existing set of field values.\n $fieldsToPurge = $field->values()->get()->pluck('value')->toArray();\n\n foreach ($values as $value) {\n // For all current values, upsert the field.\n $value['value'] = substr($value['value'] ?? '', 0, 255);\n $fieldValues[] = $field->values()->updateOrCreate([\n 'value' => $value['value'],\n ], $value);\n\n // Remove this value from the ones we are going to purge.\n $key = array_search($value['value'], $fieldsToPurge, false);\n if ($key !== false) {\n unset($fieldsToPurge[$key]);\n }\n }\n\n // Delete the old values that are no longer used.\n $field->values()->whereIn('value', $fieldsToPurge)->delete();\n\n return $fieldValues;\n }\n\n /**\n *\n * @return FieldValue[]\n */\n private function importFieldValuesForDealInsights(Field $field): array\n {\n $fieldValues = [];\n $pipelines = $this->copperClient->pipelines()->all();\n\n foreach ($pipelines as $pipeline) {\n foreach ($pipeline['stages'] as $i => $dealStage) {\n $fieldValues[] = $field->values()->updateOrCreate(\n ['value' => $dealStage['id']],\n [\n 'label' => $dealStage['name'],\n 'sequence' => $i,\n ]\n );\n }\n }\n\n return $fieldValues;\n }\n\n /**\n * @inheritdoc\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n if ($types === null) {\n $types = [Stage::TYPE_LEAD, Stage::TYPE_OPPORTUNITY];\n }\n $missingStage = null;\n\n foreach ($types as $type) {\n if ($type === Stage::TYPE_LEAD) {\n $statuses = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leadStatuses()->all()\n );\n\n if (count($statuses) > 0) {\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => BusinessProcess::TYPE_LEAD,\n ], [\n 'team_id' => $this->team->id,\n 'name' => BusinessProcess::TYPE_LEAD,\n 'type' => BusinessProcess::TYPE_LEAD,\n 'is_selectable' => true,\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => BusinessProcess::TYPE_LEAD,\n ], [\n 'team_id' => $this->team->id,\n 'name' => BusinessProcess::TYPE_LEAD,\n 'is_selectable' => true,\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n $leadStatuses = [];\n foreach ($statuses as $status) {\n // Upsert all statuses for the team.\n $status = $this->config->stages()->updateOrCreate([\n 'crm_provider_id' => $status['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($status['name'], 0, 50),\n 'label' => mb_strimwidth($status['name'], 0, 191),\n 'type' => Stage::TYPE_LEAD,\n 'sequence' => $status['order'],\n 'is_selectable' => true,\n ]);\n\n if ($missingStageName && $missingStageName === $status['id']) {\n $missingStage = $status;\n }\n\n $leadStatuses[] = $status['id'];\n }\n\n $businessProcess->stages()->sync($leadStatuses);\n }\n } else {\n // We create a business process to contain the pipeline, and later store all stages against it.\n foreach ($this->copperClient->pipelines()->all() as $pipeline) {\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => $pipeline['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($pipeline['name'], 0, 150),\n 'type' => BusinessProcess::TYPE_OPPORTUNITY,\n 'is_selectable' => true,\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => $pipeline['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($pipeline['name'], 0, 150),\n 'is_selectable' => true,\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n $stages = [];\n\n foreach ($pipeline['stages'] as $i => $dealStage) {\n // Upsert all stages for the team.\n $stage = $this->config->stages()->updateOrCreate([\n 'crm_provider_id' => $dealStage['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($dealStage['name'], 0, 50),\n 'label' => mb_strimwidth($dealStage['name'], 0, 191),\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'sequence' => $i,\n 'is_selectable' => true,\n 'probability' => $dealStage['win_probability'],\n ]);\n\n if ($missingStageName && $missingStageName === $dealStage['id']) {\n $missingStage = $stage;\n }\n\n $stages[] = $stage['id'];\n }\n\n $businessProcess->stages()->sync($stages);\n }\n }\n }\n\n return $missingStage;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int\n {\n $syncCount = 0;\n\n $cpLeads = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->paginate([\n 'minimum_modified_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ])\n );\n\n foreach ($cpLeads as $cpLead) {\n // Only sync if previously imported.\n if ($this->hasLead($cpLead['id']) === false) {\n $this->importLead($cpLead);\n $syncCount++;\n }\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLead(string $crmId): ?Lead\n {\n $cpLead = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->find($crmId)\n );\n\n if (\\count($cpLead) === 0) {\n return null;\n }\n\n return $this->importLead($cpLead);\n }\n\n /**\n * @inheritdoc\n */\n private function importLead($crmData): ?Lead\n {\n $countryCode = null;\n if (! empty($crmData['address']) && isset($crmData['address']['country'])) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $mobilePhone = $parsedNumber = null;\n if (! empty($crmData['phone_numbers'])) {\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n if ($phoneNumber['category'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);\n } else {\n $parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);\n }\n }\n }\n\n $name = $crmData['name'];\n\n if (empty($crmData['company_name'])) {\n $company = 'Unknown';\n } else {\n $company = mb_strimwidth($crmData['company_name'], 0, 191);\n }\n\n $domain = null;\n if (empty($crmData['websites']) === false) {\n $domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);\n $domain = StringUtil::resolveDomain($domain);\n }\n\n $email = null;\n if (empty($crmData['email']) === false) {\n $email = mb_strimwidth($crmData['email']['email'], 0, 80);\n }\n\n $stage = $this->config\n ->stages()\n ->where('crm_provider_id', (string) $crmData['status_id'])\n ->where('type', Stage::TYPE_LEAD)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_LEAD], $crmData['status_id']);\n }\n\n if (! $stage instanceof Stage) {\n return null;\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($name, 0, 191),\n 'company' => $company,\n 'domain' => $domain,\n 'title' => $crmData['title'] ? mb_strimwidth($crmData['title'], 0, 128) : null,\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'mobile_phone' => $mobilePhone,\n 'stage_id' => $stage->id,\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Lead::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'country_code' => $countryCode,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->leads()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n /**\n * @inheritdoc\n */\n public function syncAccounts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n $cpAccounts = $this->copperClient->accounts()->paginate([\n 'minimum_modified_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ]);\n\n foreach ($cpAccounts as $cpAccount) {\n // Only sync if previously imported.\n if ($this->hasAccount($cpAccount['id'])) {\n $this->importAccount($cpAccount);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncAccount(string $crmId): ?Account\n {\n $cpAccount = $this->copperClient->accounts()->find($crmId);\n\n if (empty($cpAccount)) {\n return null;\n }\n\n return $this->importAccount($cpAccount);\n }\n\n /**\n * @inheritdoc\n */\n private function importAccount($crmData): Account\n {\n $countryCode = null;\n if (empty($crmData['address']) === false && $crmData['address']['country']) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $name = $crmData['name'];\n\n $parsedNumber = null;\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n $parsedNumber = parsePhoneNumber($countryCode, $phoneNumber['number']);\n }\n\n $domain = null;\n if (empty($crmData['websites']) === false) {\n $domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);\n $domain = StringUtil::resolveDomain($domain);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($name, 0, 191),\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Account::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'country_code' => $countryCode,\n 'domain' => $domain,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->accounts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n public function syncOpportunities(array $parameters, ?string $strategy = null): int\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->copperClient,\n ]);\n $strategies = $strategyResolver->getStrategies($this->config, $strategy);\n\n $syncCount = 0;\n\n try {\n foreach ($strategies as $syncStrategy) {\n foreach ($syncStrategy->fetchOpportunities($parameters) as $opportunityData) {\n $this->importOpportunity($opportunityData);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n $this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => $exception->getMessage(),\n ]);\n }\n\n return $syncCount;\n }\n\n public function syncOpportunity(string $crmId): ?Opportunity\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->copperClient,\n ]);\n $strategy = $strategyResolver->resolve(\n $this->config,\n OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY\n );\n\n $parameters['crm_id'] = $crmId;\n\n $cpOpportunity = $strategy->fetchOpportunities($parameters);\n\n return $this->importOpportunity($cpOpportunity);\n }\n\n private function importOpportunity($crmData): ?Opportunity\n {\n $companyId = (string) $crmData['company_id'];\n\n if (empty($companyId)) {\n $this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => 'No company id',\n ]);\n\n return null;\n }\n\n $account = $this->config->accounts()->where('crm_provider_id', $companyId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($companyId);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', (string) $crmData['pipeline_id'])\n ->first();\n\n if ($businessProcess === null) {\n // It is possible for some deals to not be in a pipeline.\n $this->logger->warning(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => 'Missing pipeline',\n ]);\n\n return null;\n }\n\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', (string) $crmData['pipeline_stage_id'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n $this->logger->info('Stage not found, importing', [\n 'pipeline_id' => $crmData['pipeline_id'],\n 'stage_id' => $crmData['pipeline_stage_id'],\n ]);\n\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData['pipeline_stage_id']);\n }\n\n $recordType = $businessProcess->recordTypes()->first();\n $closeDate = null;\n $isClosed = $crmData['status'] !== self::OPPORTUNITY_STATUS_OPEN;\n\n if ($crmData['close_date']) {\n $closeDate = Carbon::parse($crmData['close_date'])->format('Y-m-d');\n }\n\n $data = [\n 'team_id' => $this->team->getId(),\n 'account_id' => $account->id,\n 'user_id' => $profile->user_id ?? null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($crmData['name'], 0, 128),\n 'value' => $crmData['monetary_value'],\n 'currency_code' => CurrencyFormatter::formatCode($crmData['monetary_unit']),\n 'close_date' => $closeDate,\n 'is_closed' => $isClosed,\n 'is_won' => $crmData['status'] === 'Won',\n 'stage_id' => $stage->id,\n 'record_type_id' => $recordType->id ?? null,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n /** @var Opportunity $opportunity */\n $opportunity = $this->config\n ->opportunities()\n ->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data)\n ;\n\n // import external fields into crm_field_data if present\n $dealInsightsFields = $this->getOpportunitySyncableFields();\n $this->importOpportunityCrmFieldData($crmData, $dealInsightsFields, $opportunity->id);\n\n return $opportunity;\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n * @param string[] $dealInsightsFields\n */\n public function importOpportunityCrmFieldData(\n array $opportunityData,\n array $dealInsightsFields,\n int $opportunityId\n ): void {\n foreach ($dealInsightsFields as $fieldName) {\n $field = $this->config->fields()->with('entities')\n ->where('crm_provider_id', $fieldName)\n ->where('object_type', Field::OBJECT_OPPORTUNITY)\n ->first();\n\n if (! $field instanceof Field) {\n $this->logger->warning('Field not found', [\n 'field' => $fieldName,\n 'opportunity_id' => $opportunityId,\n ]);\n\n continue;\n }\n\n $entity = $field->getEntities()->first();\n\n if (! $entity instanceof LayoutEntity) {\n continue;\n }\n\n $fieldValue = $this->extractFieldValue($opportunityData, $fieldName);\n $normalizedValue = $this->normalizeValue($field->getType(), (string) $fieldValue, true);\n\n $field->data()\n ->updateOrCreate([\n 'crm_layout_entity_id' => $entity->id,\n 'crm_field_id' => $field->id,\n 'object_type' => 'opportunity',\n 'object_id' => $opportunityId,\n ], ['value' => $normalizedValue])\n ;\n }\n }\n\n /**\n * @inheritdoc\n */\n public function syncContacts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n $cpContacts = $this->copperClient->contacts()->paginate([\n 'minimum_interaction_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ]);\n\n foreach ($cpContacts as $cpContact) {\n // Only sync if previously imported.\n if ($this->hasContact($cpContact['id'])) {\n $this->importContact($cpContact);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n throw $exception;\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncContact(string $crmId): ?Contact\n {\n $cpContact = $this->copperClient->contacts()->find($crmId);\n\n if (empty($cpContact)) {\n return null;\n }\n\n return $this->importContact($cpContact);\n }\n\n /**\n * @inheritdoc\n */\n private function importContact($crmData): Contact\n {\n $account = null;\n if ($crmData['company_id']) {\n $account = $this->team\n ->crm\n ->accounts()\n ->where('crm_provider_id', (string) $crmData['company_id'])\n ->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmData['company_id']);\n }\n }\n\n $countryCode = null;\n if (empty($crmData['address']) === false && $crmData['address']['country']) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $mobilePhone = $parsedNumber = null;\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n if ($phoneNumber['category'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);\n } else {\n $parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);\n }\n }\n\n $email = null;\n if (empty($crmData['emails']) === false) {\n $email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'account_id' => $account->id ?? null,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => $crmData['name'],\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'mobile_phone' => $mobilePhone ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'title' => $crmData['title'],\n 'country_code' => $countryCode,\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Contact::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n private function buildContactPhone(?string $countryCode, ?string $number): ?array\n {\n if ($number) {\n // Trim to our width and attempt to parse it.\n $number = mb_strimwidth($number, 0, 25);\n $parsedNumber = parsePhoneNumber($countryCode, $number);\n } else {\n $parsedNumber = [];\n }\n\n return $parsedNumber;\n }\n\n private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string\n {\n return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;\n }\n\n /**\n * @inheritdoc\n */\n public function syncOrganization(): void\n {\n $organization = $this->copperClient->organisation()->all();\n\n if ($this->config->crm_provider_id !== $organization['id']) {\n $this->config->update(['crm_provider_id' => $organization['id']]);\n }\n }\n\n private function syncCustomFields(): void\n {\n foreach ($this->getFieldTypes() as $fieldType) {\n $currentFields = $this->getFields($fieldType);\n\n foreach ($currentFields as $field) {\n /** @var Field $field */\n $field = $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => $field['name'],\n 'object_type' => $fieldType,\n ], [\n 'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),\n 'type' => $field['type'],\n ]);\n\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n }\n\n $this->config->save();\n }\n\n protected function getFieldTypes(): array\n {\n return [\n parent::OBJECT_TASK,\n parent::OBJECT_LEAD,\n parent::OBJECT_ACCOUNT,\n parent::OBJECT_CONTACT,\n parent::OBJECT_OPPORTUNITY,\n ];\n }\n\n /**\n * @inheritdoc\n */\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n $profiles = $this->copperClient->users()->all();\n\n foreach ($profiles as $profile) {\n $user = $this->userRepository->findByTeamAndEmailAddress($this->team, $profile['email'], onlyActive: true);\n\n // Only import profiles for users we have locally.\n if ($user) {\n $profile = $user->crmProfile()->updateOrCreate([\n 'crm_configuration_id' => $this->config->id,\n 'crm_provider_id' => $profile['id'],\n ]);\n\n if ($userToSearch && $userToSearch->id === $user->id) {\n return $profile;\n }\n }\n }\n\n return null;\n }\n\n /**\n * @inheritdoc\n */\n public function syncProfileFields(): void\n {\n $fieldTypes = [\n 'task',\n 'lead',\n 'account',\n 'contact',\n 'opportunity',\n ];\n\n foreach ($fieldTypes as $fieldType) {\n try {\n $currentFields = $this->getFields(ucfirst($fieldType));\n\n $newFields = array_column($currentFields, 'name');\n $changedFields = array_merge(\n array_diff($this->profile->getFieldsAsArray($fieldType), $newFields),\n array_diff($newFields, $this->profile->getFieldsAsArray($fieldType))\n );\n\n if (\\count($changedFields) > 0) {\n $fields = implode(',', $newFields);\n $this->logger->debug(\n ucfirst($fieldType)\n . ' fields changed from '\n . $this->profile->{$fieldType . '_fields'}\n . ' to: '\n . $fields\n );\n\n $this->profile->{$fieldType . '_fields'} = $fields;\n }\n } catch (\\Exception $exception) {\n $this->logger->error('No access to ' . $fieldType . ' object, skipping...');\n\n continue;\n }\n }\n\n $this->profile->save();\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n $scopeValues = array_map(fn ($scope) => is_string($scope) ? $scope : $scope->value, $scopes);\n $cacheKey = sprintf('copper-search-%d-%s-%s-%d-%d', $this->team->id, $name, implode('-', $scopeValues), $count, $offset);\n\n return Cache::remember($cacheKey, 300, function () use ($name, $scopes, $count, $offset) {\n // Try local search first\n $localResults = $this->searchLocally($name, $scopes, $count, $offset);\n\n // If no local results, fall back to remote API search\n if (empty($localResults)) {\n return $this->searchRemotely($name, $scopes, $count, $offset);\n }\n\n return $localResults;\n });\n }\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n $contact = null;\n $account = null;\n\n if ($crmAccountId) {\n $account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmAccountId);\n }\n }\n\n if ($crmContactId) {\n $contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();\n\n if ($contact === null) {\n $contact = $this->syncContact($crmContactId);\n }\n }\n\n if ($contact || $account) {\n if ($contact && $account === null) {\n $account = $contact->account;\n }\n\n if ($account === null) {\n return [];\n }\n\n $params = [\n 'company_ids' => [$account->crm_provider_id],\n 'status_ids' => [0], // The integer values are 0, 1, 2, 3, for \"Open\", \"Won\", \"Lost\", and \"Abandoned\".\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ];\n\n switch ($this->config->opportunity_assignment_rule) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['sort_by'] = 'date_modified';\n $params['sort_direction'] = 'desc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['sort_by'] = 'date_created';\n $params['sort_direction'] = 'desc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['sort_by'] = 'date_created';\n $params['sort_direction'] = 'asc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['sort_by'] = 'date_modified';\n $params['sort_direction'] = 'desc';\n $params['status_ids'] = [0, 1, 2, 3];\n }\n\n $cpOpportunities = $this->copperClient->opportunities()->search($params);\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n foreach ($cpOpportunities as $cpOpportunity) {\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', (string) $cpOpportunity['pipeline_id'])\n ->first();\n\n if ($businessProcess === null) {\n // Import it.\n $businessProcess = $this->importStages(\n [Stage::TYPE_OPPORTUNITY],\n $cpOpportunity['pipeline_stage_id']\n );\n }\n\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', (string) $cpOpportunity['pipeline_stage_id'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $cpOpportunity['pipeline_stage_id']);\n }\n\n $recordType = $businessProcess->recordTypes()->first();\n\n $record = [\n 'crmId' => $cpOpportunity['id'],\n 'name' => $cpOpportunity['name'],\n 'value' => currency_format($cpOpportunity['monetary_value'], $cpOpportunity['monetary_unit']),\n 'won' => $cpOpportunity['status'] === 'Won',\n 'stage' => [\n 'id' => $stage->id_string,\n 'name' => $stage->name,\n ],\n 'recordType' => [\n 'id' => $recordType->id_string,\n 'name' => $recordType->name,\n ],\n ];\n\n if ($ownerId && isset($cpOpportunity['assignee_id']) && $cpOpportunity['assignee_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = $cpTasks = [];\n\n switch ($objectType) {\n case 'lead':\n $cpTasks = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->relatedTasks($objectId)\n );\n\n break;\n\n case 'account':\n $cpTasks = $this->copperClient->accounts()->relatedTasks($objectId);\n\n break;\n case 'contact':\n if ($opportunityId) {\n $cpTasks = $this->copperClient->opportunities()->relatedTasks($opportunityId);\n } elseif ($objectType === 'contact') {\n $cpTasks = $this->copperClient->contacts()->relatedTasks($objectId);\n }\n\n break;\n }\n\n foreach ($cpTasks as $cpTask) {\n // We only get the ID itself returned, so pull out the full object.\n try {\n $cpTask = $this->copperClient->tasks()->find($cpTask['id']);\n } catch (Exception $exception) {\n $this->logger->error('[Copper] Error fetching task', [\n 'resource_id' => $cpTask['id'],\n 'error' => $exception->getMessage(),\n ]);\n\n continue;\n }\n\n // Only allow open tasks.\n if ($cpTask['status'] === 'Open') {\n $data[] = [\n 'crmId' => $cpTask['id'],\n 'subject' => $cpTask['name'],\n 'due' => $cpTask['due_date']\n ? Carbon::createFromTimestamp($cpTask['due_date'])->format('Y-m-d\\TH:i:sO')\n : null,\n 'type' => null,\n ];\n }\n }\n\n return $data;\n }\n\n /**\n * Try to find email address in CRM service\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $cpObjectType = 'contact';\n\n $cpObjects = $this->copperClient->contacts()->search([\n 'emails' => $email,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (empty($cpObjects)) {\n $cpObjectType = 'lead';\n $cpObjects = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'emails' => $email,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (empty($cpObjects)) {\n return null;\n }\n\n // Search returns an array of results, but we only want the first\n $cpObject = reset($cpObjects);\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n // Check if the user is internal.\n $teamMember = $this->team->users()->where('phone', $phone)->exists();\n\n // Skip the attendee if internal.\n if ($teamMember === false) {\n $cpObjectType = 'contact';\n $cpObject = $this->copperClient->contacts()->search([\n 'phone_number' => $phone,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (\\count($cpObject) === 0) {\n $cpObjectType = 'lead';\n $cpObject = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'phone_number' => $phone,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (empty($cpObject)) {\n return null;\n }\n\n $cpObject = reset($cpObject);\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n return null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $result = \\Cache::remember($this->team->id . $name, 60, function () use ($name, $userId) {\n $cpObjectType = 'contact';\n $cpObject = $this->copperClient->contacts()->search([\n 'name' => $name,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (\\count($cpObject) === 0) {\n $cpObjectType = 'lead';\n $cpObject = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'name' => $name,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (! empty($cpObject)) {\n $cpObject = reset($cpObject);\n }\n\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : false;\n });\n\n return is_array($result) ? $result : null;\n }\n\n private function convertCrmData(array $object, string $objectType, ?int $userId = null): array\n {\n $lead = null;\n $contact = null;\n $opportunity = null;\n $account = null;\n $stage = null;\n $countryCode = null;\n\n if ($objectType === 'lead') {\n $lead = $this->importLead($object);\n\n // Lead might not be imported if the Stage is null for example.\n if ($lead) {\n $countryCode = $lead->country_code;\n $stage = $lead->stage;\n }\n } else {\n $contact = $this->importContact($object);\n $account = $contact->account;\n\n if ($contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account) {\n $countryCode = $account->country_code;\n }\n\n try {\n $cpOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId,\n );\n\n if (! empty($cpOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($cpOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (\\Exception $e) {\n // Nothing to see here.\n }\n }\n\n return [\n $lead,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n public function saveActivity(Activity $activity): Activity\n {\n switch ($activity->type) {\n case Activity::TYPE_CONFERENCE:\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n $activity = $this->buildCallPayload($activity);\n\n break;\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $activity = $this->buildTextMessagePayload($activity);\n\n break;\n }\n\n return $activity;\n }\n\n private function convertActivityAssociations(Activity $activity): array\n {\n if ($activity->lead) {\n $type = 'lead';\n $id = $activity->lead->crm_provider_id;\n } elseif ($activity->contact) {\n $type = 'person';\n $id = $activity->contact->crm_provider_id;\n } elseif ($activity->opportunity) {\n $type = 'opportunity';\n $id = $activity->opportunity->crm_provider_id;\n } else {\n $type = 'company';\n $id = $activity->account->crm_provider_id;\n }\n\n return [\n 'type' => $type,\n 'id' => $id,\n ];\n }\n\n private function convertActivityType(PlaybookCategory $activityType): array\n {\n return [\n 'category' => 'user',\n 'id' => $this->getCrmType($activityType)->value,\n ];\n }\n\n /**\n * @throws CrmException\n */\n private function buildCallPayload(Activity $activity): Activity\n {\n try {\n if ($activity->crm_provider_id) {\n // The activity should be logged under the existing Task (not Activity).\n $newActivityType = $this->getCrmType($activity->category);\n if ($newActivityType === null) {\n $message = sprintf('[Copper] invalid CRM Custom Activity Type: %s', $activity->category);\n\n throw new CrmException($message, 400);\n }\n $this->copperClient->tasks()->update($activity->crm_provider_id, [\n 'status' => 'Completed',\n 'custom_activity_type_id' => $newActivityType->value,\n 'details' => $this->generateActivityDescription($activity),\n ]);\n } else {\n if ($this->getCrmType($activity->category) === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n if ($this->getCrmType($activity->category)->value === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n // Just create an activity.\n $cpActivity = $this->copperClient->activities()->create([\n 'user_id' => $this->profile->crm_provider_id,\n 'activity_date' => $activity->scheduled_start_time->timestamp,\n 'parent' => $this->convertActivityAssociations($activity),\n 'type' => $this->convertActivityType($activity->category),\n 'details' => $this->generateActivityDescription($activity),\n ]);\n\n $activity->crm_provider_id = $cpActivity['id'];\n $activity->save();\n }\n } catch (ClientException $exception) {\n //Log all errors to Sentry\n \\Sentry::captureException($exception);\n\n $response = $exception->getResponse();\n\n $responseBody = $response->getBody();\n $message = $responseBody;\n $errorCode = $response->getStatusCode();\n\n $jsonResponse = json_decode($responseBody, true);\n if (isset($jsonResponse[0]['message'])) {\n $message = $jsonResponse[0]['message'];\n }\n\n throw new CrmException($message, $errorCode);\n }\n\n return $activity;\n }\n\n private function buildTextMessagePayload(Activity $activity): Activity\n {\n if ($this->getCrmType($activity->category) === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n if ($this->getCrmType($activity->category)->value === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n $cpActivity = $this->copperClient->activities()->create([\n 'user_id' => $this->profile->crm_provider_id,\n 'activity_date' => $activity->created_at->timestamp,\n 'parent' => $this->convertActivityAssociations($activity),\n 'type' => $this->convertActivityType($activity->category),\n 'details' => $this->generateActivityDescription($activity),\n ]);\n\n $activity->crm_provider_id = $cpActivity['id'];\n $activity->save();\n\n return $activity;\n }\n\n private function generateActivityDescription(Activity $activity): string\n {\n $description = '';\n\n switch ($activity->type) {\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n case Activity::TYPE_CONFERENCE:\n\n $description = 'Jiminny Call Summary' . PHP_EOL . PHP_EOL;\n $description .= 'Call Duration: ' . $activity->duration_for_humans . PHP_EOL . PHP_EOL;\n\n // Tell them which number was dialed.\n if ($activity->to) {\n $description .= 'Dialed: ' . $activity->to->phone_number . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->hasReasonCodeBotKicked()) {\n $description .= 'Notetaker removed from this meeting' . PHP_EOL . PHP_EOL;\n // When we fix the state to be Activity::RECORDING_RECORDED as it should be this can change.\n } elseif ($activity->hasReasonCodeNotCompliant()) {\n $description .= 'Notetaker did not join due to recording consent not being provided by attendees' . PHP_EOL . PHP_EOL;\n } elseif ($activity->canReviewActivity()) {\n $playbackUrl = $activity->user->team->partner->getPlaybackUrl($activity);\n $description .= 'Review Activity:' . PHP_EOL . $playbackUrl . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->getCrmType() === Activity::TYPE_CONFERENCE) {\n $description .= 'Attendees:'\n . PHP_EOL\n . (new FilterJoinedParticipants())->toString($activity);\n }\n\n if (\\count($activity->notes) > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Notes: ' . PHP_EOL;\n\n foreach ($activity->notes as $note) {\n $nTime = (int) ceil($note->time);\n $time = ($nTime > 3600) ? gmdate('H:i:s', $nTime) : gmdate('i:s', $nTime);\n $description .= $time . ' ' . $note->note . PHP_EOL;\n }\n }\n\n // Get all private messages.\n $messages = $activity->messages()\n ->where('is_private', 1)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Coaching Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n // Get all public messages.\n $messages = $activity->messages()\n ->where('is_private', 0)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Customer Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n if ($activity->summary) {\n $description .= PHP_EOL . PHP_EOL . 'Summary: ' . PHP_EOL . $activity->summary;\n }\n\n break;\n\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $description = $activity->description;\n\n break;\n }\n\n return $description;\n }\n\n public function saveFollowupActivity(Activity $activity, array $fields): ?string\n {\n // This is the user provided activity subject field.\n if (empty($fields['type'])) {\n return null;\n }\n\n $reminder = null;\n if (empty($fields['reminder_date']) === false) {\n $formatReminder = Carbon::createFromFormat('Y-m-d\\TH:i:s\\Z', $fields['reminder_date']);\n $reminder = $formatReminder->getTimestamp();\n }\n\n $due = null;\n if (empty($fields['due_date']) === false) {\n $formatDue = Carbon::createFromFormat('Y-m-d\\TH:i:s\\Z', $fields['due_date']);\n $due = $formatDue->getTimestamp();\n }\n\n $data = [\n 'custom_activity_type_id' => $fields['type'],\n 'status' => 'Open',\n 'assignee_id' => $this->profile->crm_provider_id,\n 'due_date' => $due,\n 'details' => $fields['details'] ?? '',\n 'reminder_date' => $reminder,\n 'name' => $fields['name'] ?? 'Follow-up',\n 'related_resource' => $this->convertActivityAssociations($activity),\n 'custom_fields' => $this->fetchCustomFieldData($activity, Field::OBJECT_TASK),\n ];\n\n // We don't actually create a corresponding activity object on our side yet.\n return $this->copperClient->tasks()->create($data)['id'];\n }\n\n /**\n * Store transcripts as note.\n *\n * @throws \\Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, static::NOTE_BODY_MAX_LENGTH);\n\n $data = [\n 'user_id' => $this->profile->crm_provider_id,\n 'type' => [\n 'category' => 'user',\n 'id' => 0, // This creates a note.\n ],\n 'activity_date' => time(),\n 'details' => $transcripts,\n 'parent' => $this->convertActivityAssociations($activity),\n ];\n\n $cpActivity = $this->copperClient->activities()->create($data);\n\n // Store CRM Activity ID in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $cpActivity['id'];\n $transcription->save();\n }\n\n /**\n * @inheritdoc\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n if ($crmObject instanceof Lead) {\n $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->update($crmObject->crm_provider_id, [\n 'status_id' => $stage->crm_provider_id,\n ])\n );\n } else {\n $this->copperClient->opportunities()->update($crmObject->crm_provider_id, [\n 'pipeline_stage_id' => $stage->crm_provider_id,\n ]);\n }\n }\n\n public function prepareValueForUpdate(array $params): array\n {\n return [$params['fieldName'] => $params['fieldValue']];\n }\n\n /*\n * @inheritdoc\n */\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $preparedData = $data;\n\n if ($objectType === Field::OBJECT_OPPORTUNITY) {\n $preparedData = $this->prepareOpportunityFieldsForUpdate($data);\n }\n\n try {\n $this->copperClient\n ->createResourceFromObjectType($objectType)\n ->update($objectId, $preparedData)\n ;\n } catch (Exception $e) {\n $this->logger->error(self::RESOURCE_UPDATE_FAILED_ERROR_MESSAGE, [\n 'resource_id' => $objectId,\n 'data' => $preparedData,\n 'error' => $e->getMessage(),\n ]);\n\n throw new CrmException(self::RESOURCE_UPDATE_FAILED_ERROR_MESSAGE, $e->getCode(), $e);\n }\n }\n\n /**\n * @param array<string,string> $fieldData\n *\n * @throws CrmException\n *\n * @return array<string,array<int,array<string,bool|float|int|string|null>>|bool|float|int|string|null>\n */\n private function prepareOpportunityFieldsForUpdate(array $fieldData): array\n {\n $preparedData = [];\n $customFields = [];\n\n foreach ($fieldData as $fieldName => $fieldValue) {\n $field = $this->config\n ->fields()\n ->where('crm_provider_id', $fieldName)\n ->first();\n\n if (! $field instanceof Field) {\n throw new CrmException('Field not found');\n }\n\n $convertedValue = $this->fieldValueConverter->convertToCrm($field->getType(), $fieldValue);\n\n if ($this->isStandardField($fieldName)) {\n $preparedData[$fieldName] = $convertedValue;\n\n continue;\n }\n\n $customFields[] = [\n 'custom_field_definition_id' => $fieldName,\n 'value' => $convertedValue,\n ];\n }\n\n if (! empty($customFields)) {\n $preparedData['custom_fields'] = $customFields;\n }\n\n return $preparedData;\n }\n\n /*\n * @inheritdoc\n */\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n return $this->copperClient->createResourceFromObjectType($objectType)->find($objectId);\n }\n\n private function fetchCustomFieldData(Activity $activity, string $objectType): array\n {\n $payload = [];\n\n $fieldData = FieldData::where([\n 'object_id' => $activity->id,\n ])->whereHas('field', function ($query) use ($objectType) {\n $query->where('object_type', $objectType);\n })->get();\n\n foreach ($fieldData as $data) {\n // Add the field and value to the payload.\n $payload += [\n 'custom_field_definition_id' => $data->field->crm_provider_id,\n 'value' => $data->value,\n ];\n }\n\n return $payload;\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $baseUrl = 'https://app.prosperworks.com/companies/' . $this->config->crm_provider_id . '/app#/';\n switch ($objectType) {\n case 'lead':\n $url = $baseUrl . 'leads/' . $providerId;\n\n break;\n\n case 'account':\n $url = $baseUrl . 'organization/' . $providerId;\n\n break;\n\n case 'contact':\n $url = $baseUrl . 'contact/' . $providerId;\n\n break;\n\n case 'opportunity':\n $url = $baseUrl . 'deal/' . $providerId;\n\n break;\n\n default:\n case 'task':\n case 'activity':\n // Sadly we can't deeplink to these in Copper UI.\n $url = null;\n }\n\n return $url;\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! ($this->config->store_transcript)) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n return $this->transcriptionService\n ->findTranscriptionByActivity($activity)\n ->map(static function (array $transcriptionSegment): string {\n return $transcriptionSegment['formattedStartsAt'] . ' | ' . $transcriptionSegment['transcript'];\n })\n ->implode(PHP_EOL);\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n *\n * @return int|string|bool|float|null\n */\n private function extractFieldValue(array $opportunityData, string $fieldName)\n {\n $fieldValue = $this->isStandardField($fieldName)\n ? $opportunityData[$fieldName]\n : $this->resolveCustomFieldFromOpportunityData($opportunityData, $fieldName);\n\n if (is_array($fieldValue)) {\n $fieldValue = implode(', ', $fieldValue);\n }\n\n return $fieldValue;\n }\n\n private function isStandardField(string $fieldName): bool\n {\n return array_key_exists($fieldName, self::STANDARD_OPPORTUNITY_FIELDS);\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n *\n * @return string|int|float|bool|null|array<string, mixed>\n */\n private function resolveCustomFieldFromOpportunityData(array $opportunityData, string $fieldName)\n {\n $fieldData = array_filter(\n $opportunityData['custom_fields'],\n static fn ($field) => (string) $field['custom_field_definition_id'] === $fieldName\n );\n\n return array_pop($fieldData)['value'] ?? '';\n }\n\n private function isSupportedObjectType(string $objectType): bool\n {\n return $objectType !== self::UNSUPPORTED_OBJECT_TYPE;\n }\n\n private function syncStandardFields(): void\n {\n foreach (self::STANDARD_OPPORTUNITY_FIELDS as $fieldId => $fieldData) {\n $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => mb_strimwidth($fieldId, 0, 128),\n 'object_type' => Field::OBJECT_OPPORTUNITY,\n ], [\n 'label' => mb_strimwidth($fieldData['label'], 0, Field::LABEL_MAX_LENGTH),\n 'type' => $fieldData['type'],\n ]);\n }\n\n $this->importStages([Stage::TYPE_OPPORTUNITY]);\n }\n\n private function requestWithExceptionHandling(\\Closure $apiRequest): iterable\n {\n try {\n return $apiRequest();\n } catch (\\Exception $exception) {\n if ($exception->getCode() === 403) {\n // Object might not be supported\n return [];\n }\n\n \\Sentry::captureException($exception);\n\n return [];\n }\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n if ($this->copperClient === null) {\n return false;\n }\n\n $task = $this->copperClient->tasks()->find($crmProviderId);\n\n return ! empty($task);\n } catch (HttpNotFoundException) {\n // Task not found in CRM - this is expected and permanent\n $this->logger->info('[Copper] Task not found during verification', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n } catch (RequestFailedException $e) {\n // Handle 404 responses from Copper API\n if ($e->getCode() === 404) {\n $this->logger->info('[Copper] Task not found during verification (404)', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n\n // Re-throw other Copper exceptions for retry\n throw $e;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\n });\n }\n}","role_description":"text entry area","is_enabled":true,"is_focused":true,"is_selected":false,"is_expanded":false}]...
|
8957564869086018857
|
-7959665055215941403
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
11
72
1
4
Previous Highlighted Error
Next Highlighted Error
<?php
namespace Jiminny\Services\Crm\Copper;
use Carbon\Carbon;
use Exception;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Support\Facades\Cache;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\CopperInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Crm\LayoutEntity;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Repositories\UserRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Copper\Api\Client;
use Jiminny\Services\Crm\Copper\Api\ClientFactory;
use Jiminny\Services\Crm\Copper\Exception\RequestFailedException;
use Jiminny\Services\Crm\Helpers\FilterJoinedParticipants;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\Copper\Traits\SearchesCrmEntities;
use Jiminny\Utils\CurrencyFormatter;
use Jiminny\Utils\StringUtil;
class Service extends BaseService implements
CopperInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
RemoteEntityManipulationInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use SearchesCrmEntities;
private const int NOTE_BODY_MAX_LENGTH = 3000000;
private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day
private const array STANDARD_OPPORTUNITY_FIELDS = [
'monetary_value' => [
'label' => 'Value',
'available_on' => Field::OBJECT_OPPORTUNITY,
'type' => Field::TYPE_CURRENCY,
],
'pipeline_stage_id' => [
'label' => 'Stage',
'type' => Field::TYPE_PICKLIST,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
'close_date' => [
'label' => 'Close date',
'type' => Field::TYPE_DATE,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
'win_probability' => [
'label' => 'Win probability',
'type' => Field::TYPE_NUMBER,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
];
private const string UNSUPPORTED_OBJECT_TYPE = 'unsupported';
private const string OPPORTUNITY_STATUS_OPEN = 'Open';
private const string OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE = 'Opportunity import failed';
private const string RESOURCE_UPDATE_FAILED_ERROR_MESSAGE = 'Failed to update resource';
private FieldValueConverter $fieldValueConverter;
private ClientFactory $clientFactory;
private ?Client $copperClient = null;
public function __construct(
ClientFactory $clientFactory,
FieldValueConverter $fieldValueConverter,
private readonly UserRepository $userRepository,
private readonly ProspectPhotoPathService $prospectPhotoPathService,
private readonly CrmEntityRepository $crmEntityRepository
) {
parent::__construct();
$this->clientFactory = $clientFactory;
$this->fieldValueConverter = $fieldValueConverter;
}
public function getDisplayName(): string
{
return 'Copper';
}
/**
* Get the CRM entity repository (used by SearchesCrmEntities trait)
*/
protected function getCrmEntityRepository(): CrmEntityRepository
{
return $this->crmEntityRepository;
}
public function getMinimumApiVersion(): string
{
return Client::MIN_API_VERSION;
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
$owner = $user->team->owner;
return $owner->getSocialAccount(SocialAccount::PROVIDER_COPPER);
}
public function setUser(User $user): void
{
$this->configureSentryScope($user);
$this->team = $user->getTeam();
$this->teamService->setTeam($user->getTeam());
$this->setConfiguration($user->getTeam()->getCrmConfiguration());
// Reset state.
$this->profile = $user->getProfile();
if (! $this->profile instanceof Profile) {
// Try to fetch their profile, maybe it was not yet imported?
$this->profile = $this->getProfile($user);
}
}
public function setConfiguration(Configuration $configuration): void
{
$this->config = $configuration;
$this->copperClient = $this->clientFactory->create($configuration);
if ($this->team === null) {
$this->team = $configuration->getTeam();
}
}
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);
}
private function mapObjectType(string $objectType): string
{
$objectType = strtolower($objectType);
switch ($objectType) {
case Field::OBJECT_TASK:
case Field::OBJECT_OPPORTUNITY:
case Field::OBJECT_LEAD:
$mappedType = $objectType;
break;
case Field::OBJECT_ACCOUNT:
$mappedType = 'company';
break;
case Field::OBJECT_CONTACT:
$mappedType = 'person';
break;
default:
$mappedType = self::UNSUPPORTED_OBJECT_TYPE;
break;
}
return $mappedType;
}
/**
* @param string $crmObject The name of the CRM object. i.e. Opportunity or Contact
*/
protected function getFields(string $crmObject): array
{
$mappedObjectType = $this->mapObjectType($crmObject);
if (! $this->isSupportedObjectType($mappedObjectType)) {
return [];
}
$customFields = $this->copperClient->fields()->all();
$filteredFields = array_filter(
$customFields,
static fn ($field) => in_array($mappedObjectType, $field['available_on'], true)
);
return array_map(
fn (array $property) => [
'name' => $property['id'],
'label' => $property['name'],
'type' => $this->convertFieldType($property['data_type']),
],
$filteredFields
);
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
// Setup the activity field as the default Type.
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'type',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldFilters = FieldDefinitions::taskFollowupFieldsFilter();
foreach ($fieldFilters as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
public function syncFields(): void
{
$this->syncStandardFields();
$this->syncCustomFields();
}
public function syncField(Field $field): void
{
if ($field->getCrmProviderId() === 'type') {
/**
* This field is a special case, it is not a custom field and is not returned by the Copper API.
*
* The field is created manually during layout setup.
*
* @see getDefaultFields()
*
* There is a separate endpoint to get the activity types.
* @see importPicklistValues()
*/
return;
}
if ($field->getCrmProviderId() === 'pipeline_stage_id') {
// Not a custom type
return;
}
$crmField = $this->copperClient->fields()->find($field->getCrmProviderId());
$field->label = $crmField['name'];
$field->type = $this->convertFieldType($crmField['data_type']);
$field->save();
}
/**
* @param string $fieldType How the data should be input
*/
private function convertFieldType(string $fieldType): string
{
$fieldType = strtolower($fieldType);
switch ($fieldType) {
case 'dropdown':
$convertedType = Field::TYPE_PICKLIST;
break;
case 'string':
$convertedType = Field::TYPE_TEXT;
break;
case 'float':
case 'percentage':
$convertedType = Field::TYPE_NUMBER;
break;
case 'text':
$convertedType = Field::TYPE_TEXTAREA;
break;
case 'checkbox':
$convertedType = Field::TYPE_BOOLEAN;
break;
case Field::TYPE_DATE:
case Field::TYPE_CURRENCY:
case Field::TYPE_URL:
$convertedType = $fieldType;
break;
default:
$convertedType = Field::TYPE_UNSUPPORTED;
break;
}
return $convertedType;
}
/**
* @inheritdoc
*/
public function importPicklistValues(Field $field): array
{
$fieldValues = [];
if ($field->object_type === 'opportunity' && $field->crm_provider_id === 'pipeline_stage_id') {
return $this->importFieldValuesForDealInsights($field);
}
$values = [];
if ($field->object_type === Field::OBJECT_TASK && $field->crm_provider_id === 'type') {
$activityTypes = $this->copperClient->activityTypes()->all();
/**
* We ignore "system" activity types, disabled activity types and the "Note" activity type.
*/
$activityTypes = array_filter(
$activityTypes['user'],
fn (array $activityType) => ! $activityType['is_disabled'] && $activityType['id'] !== 0
);
// Import all activity values.
$i = 0;
foreach ($activityTypes as $activityType) {
$values[] = [
'value' => $activityType['id'],
'label' => mb_strimwidth($activityType['name'], 0, Field::LABEL_MAX_LENGTH),
'sequence' => $i++,
];
}
} else {
// We just check for the field in the custom definitions.
$crmField = $this->copperClient->fields()->find($field->crm_provider_id);
// Import all values.
foreach ($crmField['options'] as $option) {
$values[] = [
'value' => $option['id'],
'label' => mb_strimwidth($option['name'], 0, 191),
'sequence' => $option['rank'],
];
}
}
// Take the existing set of field values.
$fieldsToPurge = $field->values()->get()->pluck('value')->toArray();
foreach ($values as $value) {
// For all current values, upsert the field.
$value['value'] = substr($value['value'] ?? '', 0, 255);
$fieldValues[] = $field->values()->updateOrCreate([
'value' => $value['value'],
], $value);
// Remove this value from the ones we are going to purge.
$key = array_search($value['value'], $fieldsToPurge, false);
if ($key !== false) {
unset($fieldsToPurge[$key]);
}
}
// Delete the old values that are no longer used.
$field->values()->whereIn('value', $fieldsToPurge)->delete();
return $fieldValues;
}
/**
*
* @return FieldValue[]
*/
private function importFieldValuesForDealInsights(Field $field): array
{
$fieldValues = [];
$pipelines = $this->copperClient->pipelines()->all();
foreach ($pipelines as $pipeline) {
foreach ($pipeline['stages'] as $i => $dealStage) {
$fieldValues[] = $field->values()->updateOrCreate(
['value' => $dealStage['id']],
[
'label' => $dealStage['name'],
'sequence' => $i,
]
);
}
}
return $fieldValues;
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
if ($types === null) {
$types = [Stage::TYPE_LEAD, Stage::TYPE_OPPORTUNITY];
}
$missingStage = null;
foreach ($types as $type) {
if ($type === Stage::TYPE_LEAD) {
$statuses = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leadStatuses()->all()
);
if (count($statuses) > 0) {
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => BusinessProcess::TYPE_LEAD,
], [
'team_id' => $this->team->id,
'name' => BusinessProcess::TYPE_LEAD,
'type' => BusinessProcess::TYPE_LEAD,
'is_selectable' => true,
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => BusinessProcess::TYPE_LEAD,
], [
'team_id' => $this->team->id,
'name' => BusinessProcess::TYPE_LEAD,
'is_selectable' => true,
'business_process_id' => $businessProcess->id ?? null,
]);
$leadStatuses = [];
foreach ($statuses as $status) {
// Upsert all statuses for the team.
$status = $this->config->stages()->updateOrCreate([
'crm_provider_id' => $status['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($status['name'], 0, 50),
'label' => mb_strimwidth($status['name'], 0, 191),
'type' => Stage::TYPE_LEAD,
'sequence' => $status['order'],
'is_selectable' => true,
]);
if ($missingStageName && $missingStageName === $status['id']) {
$missingStage = $status;
}
$leadStatuses[] = $status['id'];
}
$businessProcess->stages()->sync($leadStatuses);
}
} else {
// We create a business process to contain the pipeline, and later store all stages against it.
foreach ($this->copperClient->pipelines()->all() as $pipeline) {
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $pipeline['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($pipeline['name'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => true,
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $pipeline['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($pipeline['name'], 0, 150),
'is_selectable' => true,
'business_process_id' => $businessProcess->id ?? null,
]);
$stages = [];
foreach ($pipeline['stages'] as $i => $dealStage) {
// Upsert all stages for the team.
$stage = $this->config->stages()->updateOrCreate([
'crm_provider_id' => $dealStage['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($dealStage['name'], 0, 50),
'label' => mb_strimwidth($dealStage['name'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $i,
'is_selectable' => true,
'probability' => $dealStage['win_probability'],
]);
if ($missingStageName && $missingStageName === $dealStage['id']) {
$missingStage = $stage;
}
$stages[] = $stage['id'];
}
$businessProcess->stages()->sync($stages);
}
}
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int
{
$syncCount = 0;
$cpLeads = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->paginate([
'minimum_modified_date' => $since->timestamp,
'sort_by' => 'date_modified',
])
);
foreach ($cpLeads as $cpLead) {
// Only sync if previously imported.
if ($this->hasLead($cpLead['id']) === false) {
$this->importLead($cpLead);
$syncCount++;
}
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncLead(string $crmId): ?Lead
{
$cpLead = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->find($crmId)
);
if (\count($cpLead) === 0) {
return null;
}
return $this->importLead($cpLead);
}
/**
* @inheritdoc
*/
private function importLead($crmData): ?Lead
{
$countryCode = null;
if (! empty($crmData['address']) && isset($crmData['address']['country'])) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$mobilePhone = $parsedNumber = null;
if (! empty($crmData['phone_numbers'])) {
foreach ($crmData['phone_numbers'] as $phoneNumber) {
if ($phoneNumber['category'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);
} else {
$parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);
}
}
}
$name = $crmData['name'];
if (empty($crmData['company_name'])) {
$company = 'Unknown';
} else {
$company = mb_strimwidth($crmData['company_name'], 0, 191);
}
$domain = null;
if (empty($crmData['websites']) === false) {
$domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);
$domain = StringUtil::resolveDomain($domain);
}
$email = null;
if (empty($crmData['email']) === false) {
$email = mb_strimwidth($crmData['email']['email'], 0, 80);
}
$stage = $this->config
->stages()
->where('crm_provider_id', (string) $crmData['status_id'])
->where('type', Stage::TYPE_LEAD)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_LEAD], $crmData['status_id']);
}
if (! $stage instanceof Stage) {
return null;
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($name, 0, 191),
'company' => $company,
'domain' => $domain,
'title' => $crmData['title'] ? mb_strimwidth($crmData['title'], 0, 128) : null,
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'mobile_phone' => $mobilePhone,
'stage_id' => $stage->id,
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Lead::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'country_code' => $countryCode,
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->leads()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
/**
* @inheritdoc
*/
public function syncAccounts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
$cpAccounts = $this->copperClient->accounts()->paginate([
'minimum_modified_date' => $since->timestamp,
'sort_by' => 'date_modified',
]);
foreach ($cpAccounts as $cpAccount) {
// Only sync if previously imported.
if ($this->hasAccount($cpAccount['id'])) {
$this->importAccount($cpAccount);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncAccount(string $crmId): ?Account
{
$cpAccount = $this->copperClient->accounts()->find($crmId);
if (empty($cpAccount)) {
return null;
}
return $this->importAccount($cpAccount);
}
/**
* @inheritdoc
*/
private function importAccount($crmData): Account
{
$countryCode = null;
if (empty($crmData['address']) === false && $crmData['address']['country']) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$name = $crmData['name'];
$parsedNumber = null;
foreach ($crmData['phone_numbers'] as $phoneNumber) {
$parsedNumber = parsePhoneNumber($countryCode, $phoneNumber['number']);
}
$domain = null;
if (empty($crmData['websites']) === false) {
$domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);
$domain = StringUtil::resolveDomain($domain);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($name, 0, 191),
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Account::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'country_code' => $countryCode,
'domain' => $domain,
'phone' => $parsedNumber['phone'] ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->accounts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
public function syncOpportunities(array $parameters, ?string $strategy = null): int
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->copperClient,
]);
$strategies = $strategyResolver->getStrategies($this->config, $strategy);
$syncCount = 0;
try {
foreach ($strategies as $syncStrategy) {
foreach ($syncStrategy->fetchOpportunities($parameters) as $opportunityData) {
$this->importOpportunity($opportunityData);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
$this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => $exception->getMessage(),
]);
}
return $syncCount;
}
public function syncOpportunity(string $crmId): ?Opportunity
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->copperClient,
]);
$strategy = $strategyResolver->resolve(
$this->config,
OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY
);
$parameters['crm_id'] = $crmId;
$cpOpportunity = $strategy->fetchOpportunities($parameters);
return $this->importOpportunity($cpOpportunity);
}
private function importOpportunity($crmData): ?Opportunity
{
$companyId = (string) $crmData['company_id'];
if (empty($companyId)) {
$this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => 'No company id',
]);
return null;
}
$account = $this->config->accounts()->where('crm_provider_id', $companyId)->first();
if ($account === null) {
$account = $this->syncAccount($companyId);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', (string) $crmData['pipeline_id'])
->first();
if ($businessProcess === null) {
// It is possible for some deals to not be in a pipeline.
$this->logger->warning(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => 'Missing pipeline',
]);
return null;
}
$stage = $businessProcess
->stages()
->where('crm_provider_id', (string) $crmData['pipeline_stage_id'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
$this->logger->info('Stage not found, importing', [
'pipeline_id' => $crmData['pipeline_id'],
'stage_id' => $crmData['pipeline_stage_id'],
]);
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData['pipeline_stage_id']);
}
$recordType = $businessProcess->recordTypes()->first();
$closeDate = null;
$isClosed = $crmData['status'] !== self::OPPORTUNITY_STATUS_OPEN;
if ($crmData['close_date']) {
$closeDate = Carbon::parse($crmData['close_date'])->format('Y-m-d');
}
$data = [
'team_id' => $this->team->getId(),
'account_id' => $account->id,
'user_id' => $profile->user_id ?? null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($crmData['name'], 0, 128),
'value' => $crmData['monetary_value'],
'currency_code' => CurrencyFormatter::formatCode($crmData['monetary_unit']),
'close_date' => $closeDate,
'is_closed' => $isClosed,
'is_won' => $crmData['status'] === 'Won',
'stage_id' => $stage->id,
'record_type_id' => $recordType->id ?? null,
'remotely_created_at' => $crmData['date_created'],
];
/** @var Opportunity $opportunity */
$opportunity = $this->config
->opportunities()
->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data)
;
// import external fields into crm_field_data if present
$dealInsightsFields = $this->getOpportunitySyncableFields();
$this->importOpportunityCrmFieldData($crmData, $dealInsightsFields, $opportunity->id);
return $opportunity;
}
/**
* @param array<string, mixed> $opportunityData
* @param string[] $dealInsightsFields
*/
public function importOpportunityCrmFieldData(
array $opportunityData,
array $dealInsightsFields,
int $opportunityId
): void {
foreach ($dealInsightsFields as $fieldName) {
$field = $this->config->fields()->with('entities')
->where('crm_provider_id', $fieldName)
->where('object_type', Field::OBJECT_OPPORTUNITY)
->first();
if (! $field instanceof Field) {
$this->logger->warning('Field not found', [
'field' => $fieldName,
'opportunity_id' => $opportunityId,
]);
continue;
}
$entity = $field->getEntities()->first();
if (! $entity instanceof LayoutEntity) {
continue;
}
$fieldValue = $this->extractFieldValue($opportunityData, $fieldName);
$normalizedValue = $this->normalizeValue($field->getType(), (string) $fieldValue, true);
$field->data()
->updateOrCreate([
'crm_layout_entity_id' => $entity->id,
'crm_field_id' => $field->id,
'object_type' => 'opportunity',
'object_id' => $opportunityId,
], ['value' => $normalizedValue])
;
}
}
/**
* @inheritdoc
*/
public function syncContacts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
$cpContacts = $this->copperClient->contacts()->paginate([
'minimum_interaction_date' => $since->timestamp,
'sort_by' => 'date_modified',
]);
foreach ($cpContacts as $cpContact) {
// Only sync if previously imported.
if ($this->hasContact($cpContact['id'])) {
$this->importContact($cpContact);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
throw $exception;
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncContact(string $crmId): ?Contact
{
$cpContact = $this->copperClient->contacts()->find($crmId);
if (empty($cpContact)) {
return null;
}
return $this->importContact($cpContact);
}
/**
* @inheritdoc
*/
private function importContact($crmData): Contact
{
$account = null;
if ($crmData['company_id']) {
$account = $this->team
->crm
->accounts()
->where('crm_provider_id', (string) $crmData['company_id'])
->first();
if ($account === null) {
$account = $this->syncAccount($crmData['company_id']);
}
}
$countryCode = null;
if (empty($crmData['address']) === false && $crmData['address']['country']) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$mobilePhone = $parsedNumber = null;
foreach ($crmData['phone_numbers'] as $phoneNumber) {
if ($phoneNumber['category'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);
} else {
$parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);
}
}
$email = null;
if (empty($crmData['emails']) === false) {
$email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'account_id' => $account->id ?? null,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => $crmData['name'],
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'mobile_phone' => $mobilePhone ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'title' => $crmData['title'],
'country_code' => $countryCode,
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Contact::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
private function buildContactPhone(?string $countryCode, ?string $number): ?array
{
if ($number) {
// Trim to our width and attempt to parse it.
$number = mb_strimwidth($number, 0, 25);
$parsedNumber = parsePhoneNumber($countryCode, $number);
} else {
$parsedNumber = [];
}
return $parsedNumber;
}
private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string
{
return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
$organization = $this->copperClient->organisation()->all();
if ($this->config->crm_provider_id !== $organization['id']) {
$this->config->update(['crm_provider_id' => $organization['id']]);
}
}
private function syncCustomFields(): void
{
foreach ($this->getFieldTypes() as $fieldType) {
$currentFields = $this->getFields($fieldType);
foreach ($currentFields as $field) {
/** @var Field $field */
$field = $this->config->fields()->updateOrCreate([
'crm_provider_id' => $field['name'],
'object_type' => $fieldType,
], [
'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),
'type' => $field['type'],
]);
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
}
$this->config->save();
}
protected function getFieldTypes(): array
{
return [
parent::OBJECT_TASK,
parent::OBJECT_LEAD,
parent::OBJECT_ACCOUNT,
parent::OBJECT_CONTACT,
parent::OBJECT_OPPORTUNITY,
];
}
/**
* @inheritdoc
*/
public function syncProfiles(?User $userToSearch = null): ?Profile
{
$profiles = $this->copperClient->users()->all();
foreach ($profiles as $profile) {
$user = $this->userRepository->findByTeamAndEmailAddress($this->team, $profile['email'], onlyActive: true);
// Only import profiles for users we have locally.
if ($user) {
$profile = $user->crmProfile()->updateOrCreate([
'crm_configuration_id' => $this->config->id,
'crm_provider_id' => $profile['id'],
]);
if ($userToSearch && $userToSearch->id === $user->id) {
return $profile;
}
}
}
return null;
}
/**
* @inheritdoc
*/
public function syncProfileFields(): void
{
$fieldTypes = [
'task',
'lead',
'account',
'contact',
'opportunity',
];
foreach ($fieldTypes as $fieldType) {
try {
$currentFields = $this->getFields(ucfirst($fieldType));
$newFields = array_column($currentFields, 'name');
$changedFields = array_merge(
array_diff($this->profile->getFieldsAsArray($fieldType), $newFields),
array_diff($newFields, $this->profile->getFieldsAsArray($fieldType))
);
if (\count($changedFields) > 0) {
$fields = implode(',', $newFields);
$this->logger->debug(
ucfirst($fieldType)
. ' fields changed from '
. $this->profile->{$fieldType . '_fields'}
. ' to: '
. $fields
);
$this->profile->{$fieldType . '_fields'} = $fields;
}
} catch (\Exception $exception) {
$this->logger->error('No access to ' . $fieldType . ' object, skipping...');
continue;
}
}
$this->profile->save();
}
/**
* @inheritdoc
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
$scopeValues = array_map(fn ($scope) => is_string($scope) ? $scope : $scope->value, $scopes);
$cacheKey = sprintf('copper-search-%d-%s-%s-%d-%d', $this->team->id, $name, implode('-', $scopeValues), $count, $offset);
return Cache::remember($cacheKey, 300, function () use ($name, $scopes, $count, $offset) {
// Try local search first
$localResults = $this->searchLocally($name, $scopes, $count, $offset);
// If no local results, fall back to remote API search
if (empty($localResults)) {
return $this->searchRemotely($name, $scopes, $count, $offset);
}
return $localResults;
});
}
/**
* @inheritdoc
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
$contact = null;
$account = null;
if ($crmAccountId) {
$account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();
if ($account === null) {
$account = $this->syncAccount($crmAccountId);
}
}
if ($crmContactId) {
$contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();
if ($contact === null) {
$contact = $this->syncContact($crmContactId);
}
}
if ($contact || $account) {
if ($contact && $account === null) {
$account = $contact->account;
}
if ($account === null) {
return [];
}
$params = [
'company_ids' => [$account->crm_provider_id],
'status_ids' => [0], // The integer values are 0, 1, 2, 3, for "Open", "Won", "Lost", and "Abandoned".
'sort_by' => 'date_modified',
'sort_direction' => 'desc',
];
switch ($this->config->opportunity_assignment_rule) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['sort_by'] = 'date_modified';
$params['sort_direction'] = 'desc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['sort_by'] = 'date_created';
$params['sort_direction'] = 'desc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['sort_by'] = 'date_created';
$params['sort_direction'] = 'asc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['sort_by'] = 'date_modified';
$params['sort_direction'] = 'desc';
$params['status_ids'] = [0, 1, 2, 3];
}
$cpOpportunities = $this->copperClient->opportunities()->search($params);
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
foreach ($cpOpportunities as $cpOpportunity) {
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', (string) $cpOpportunity['pipeline_id'])
->first();
if ($businessProcess === null) {
// Import it.
$businessProcess = $this->importStages(
[Stage::TYPE_OPPORTUNITY],
$cpOpportunity['pipeline_stage_id']
);
}
$stage = $businessProcess
->stages()
->where('crm_provider_id', (string) $cpOpportunity['pipeline_stage_id'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $cpOpportunity['pipeline_stage_id']);
}
$recordType = $businessProcess->recordTypes()->first();
$record = [
'crmId' => $cpOpportunity['id'],
'name' => $cpOpportunity['name'],
'value' => currency_format($cpOpportunity['monetary_value'], $cpOpportunity['monetary_unit']),
'won' => $cpOpportunity['status'] === 'Won',
'stage' => [
'id' => $stage->id_string,
'name' => $stage->name,
],
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
if ($ownerId && isset($cpOpportunity['assignee_id']) && $cpOpportunity['assignee_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
}
if (! empty($ownerData)) {
return $ownerData;
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array
{
$data = $cpTasks = [];
switch ($objectType) {
case 'lead':
$cpTasks = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->relatedTasks($objectId)
);
break;
case 'account':
$cpTasks = $this->copperClient->accounts()->relatedTasks($objectId);
break;
case 'contact':
if ($opportunityId) {
$cpTasks = $this->copperClient->opportunities()->relatedTasks($opportunityId);
} elseif ($objectType === 'contact') {
$cpTasks = $this->copperClient->contacts()->relatedTasks($objectId);
}
break;
}
foreach ($cpTasks as $cpTask) {
// We only get the ID itself returned, so pull out the full object.
try {
$cpTask = $this->copperClient->tasks()->find($cpTask['id']);
} catch (Exception $exception) {
$this->logger->error('[Copper] Error fetching task', [
'resource_id' => $cpTask['id'],
'error' => $exception->getMessage(),
]);
continue;
}
// Only allow open tasks.
if ($cpTask['status'] === 'Open') {
$data[] = [
'crmId' => $cpTask['id'],
'subject' => $cpTask['name'],
'due' => $cpTask['due_date']
? Carbon::createFromTimestamp($cpTask['due_date'])->format('Y-m-d\TH:i:sO')
: null,
'type' => null,
];
}
}
return $data;
}
/**
* Try to find email address in CRM service
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$cpObjectType = 'contact';
$cpObjects = $this->copperClient->contacts()->search([
'emails' => $email,
'sort_by' => 'date_modified',
'sort_direction' => 'desc',
]);
if (empty($cpObjects)) {
$cpObjectType = 'lead';
$cpObjects = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->search([
'emails' => ...
|
45357
|
NULL
|
NULL
|
NULL
|
|
45356
|
1626
|
8
|
2026-05-14T14:32:37.929047+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769157929_m2.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
ActivityFilesLaterJiminny... ~@ jiminny-x-integrat ActivityFilesLaterJiminny... ~@ jiminny-x-integrati& platform-inner-team© Channels# ai-chapter# alertsi backend# bugscontusion-cllnia# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the people of iimi..• Direct messages8. A...• A3 62P. Galya Dimitrova Mvasil VasilevA. Stefka Stoyanova%: Todor Stamatovf. Mario GeorgievP. Nikolay Ivanov2o James Graham "2. Stoyan Tanev. Steliyan Georgiev. Petko Kashinski*. Lukas Kovali...a: Apps® ToastS lira Gloud6 Huddle with Aneliya Angelova& R. Aneliya Angelova •• Messagest Add canvasur FilesAneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук,нали?пои останалите скМі тоябва оъчно ла се въвелат.Lukas Kovalik 2:47 PMтряова да се за всички, някьде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova @ 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725X Preview insackt[HubSpot] Optimise CRM rematctC OpenReady for QA- MediumAA Aneliya AngelovaAs of today at 4:00 PM RetreshOpen in Jira+ SummariseLukas Kovalik 4:02 PMzean-iurwiniareelYou joined the huddle LIVE 4:06 PMAneliva Angelova is here toolAneliya Angelova 4:44 PM11512582Lukas Kovalik O 5:16 PMcurl --location "httns:ani.hubani.com/crm/v3/obiects/contacts/search--header 'Content-Type: application/json'\--header "Authorization: BearerC|Kvma?iMx7OINOM8kOFwrAowAcAkUAhIR24?A05D?xiVrIYMILuP6SA01Kwcmhr=n.v2 hytorDniMvDalYck-CMalovolNOM9kOFwrAUAcrkcaws-ThwRARIRAOF-ATFSAOFRAO-ROIEBAQUBEggBAQEBAYICFIґ7Au8O2Nwal9YW2CbCCxYvwngmSgNldTFSAFoAYABoAHAAeAA'\--data "{ "limit", 13'Message Aneliva Angelova+ AaIđ 0Pm~ (Q SearchDate ModifiedYesterdav at 13.36Yesterday at 13:35Yesterday at 13.34Yesterday at 13:34Yesterday at 13:33resterday at 15.5sYesterdav at 13:37Yesterday at 13:32Yesterday at 13.31Yesterday at 13:30Yesterday at 13:30resterday at 15.4gYesterdav at 13:29Yesterday at 13:28Yesterday at 13:28Yesterday at 13:27Yesterday at 13:27resterday at 13.-40Yesterdav at 13:25Yesterday at 13:25Yesterday at 13:24Yesterday at 13:24Yesterday at 13:23Yesterday at 13.21Yesterdav at 13:21Yesterday at 13:20Yesterday at 13:20Yesterday at 13:19Yesterday at 13:19Yesterday at 13.18Vecterdav at 12:17Yesterday at 13:16Yesterdav at 13:16Yesterday at 13:15Yesterday at 13:14Yecterdav at 12:1/Yesterday at 13:13Yesterday at 13.13Yecterdav at 12:12Yesterday at 13:12Yesterday at 13:11Yesterday at 13:10Yesterday at 13:10Yesterday at 13.09Yecterdav at 12:091Yesterday at 13:08Yesterdav at 13:07MPEG-4 movie13 KBMPEG-4 movie16 KB1/ Kb29 KBMPEG-4 movieMPEG-4 movie6 KB12 KBMPE0"4 movie9 K:7 KBMPEG-4 movie8 KB37 KBMP2G-4 movie10 KBMPEG-4 movie7 KBMPEG"4 movie9K:8KBMPEG-4 movie72 KB14 K8|13 KRIMPEG-4 movieMPEG-4 movie9 KB18 KBMPEG-4 movie12 KEMPEG-4 movie10 KBMPEG-4 movie16 KB6 KB1MPEG-4 movie6 KBMPEG-4 movie12 KB23 KBMPEG-4 movie8 KEMPEG-4 movie6 KBMPEG-4 movie6 KBMPEG-4 movie11 K:MPEG-4 movie11 KBMPEG-4 movie34 KBMPEG-4 movie10 KPMPEG-4 movie7 KBMPEG-4 movie5 KBMPEG-4 movie11 KBIMPEG-4 movie26 KBMPEG-4 movie111 KB102 KBRR KRMPEG-4 movieMDEG-A movie59 KB98 KBMPEG-4 movie07 K:MPEG-A movie66 KB MPEG-4 movie44 KB93 KB79 KpMPEG-4 movieMPEG-4 movie58 KBMPEG-4 movie27 KP7 KBMPEG-4 movie12 KB32 K8MPEG-4 movieAl Notes: OffLeave• 0FavouritesE jiminny© Recents* ApplicationsiCloudiCloud Drive228 Sync folderQ DXP4800PLUS-B5FA@ Network|• CRMI• Orange• Red• Yellow• Green• Purple•) All lags..lohlDownloadsNameLoom.pkgAlfred copv.alfredoreterencesB KeychronAssist-1.0.2 (1).dmgA Keychron Assist-1.0.2.dmgmazanoke-images-yWJo.zioPhotos-3-001.zipD Transcript.pdf→mage U.loge1 Orioninstaller.dmaimage.jpg- image (2).1pc• ПО-22221726037035-004-001_ORGES.pdf• %D0%9F%D0%9E-22221726037035-004-001_archive.zipПO-22221726037035-004-001_archive (1).zip• repon 4).XmAltred copy2.altredoreterences05012026_0000000026574472_ SWIFT_OB70501260015890.pdf27022026_0000000026574472_SWIFT_OB72702260049200.pdf= 03042026 [CREDIT_CARD] SWIFT [CREDIT_CARD].001B reporti) xm=pdt.odipdf-1.pdfD pdf-2.pdf-pdf-5.pd1= ndf-1 ndipdf-3.pdfKoválik Family Tree.gedbitwarden export 20251031122528.isonKoválik Family Tree.zip*macOS Storage_Cleanup.mdal favicon icofirst_aid_notes_complete.docxrenortl2).esvconfig.ymlIteration run Search HS.postman_collection.jsonm licence bettertouchtoalMariusHosting Config.json1ooks-891a6503-bbb7-4b2b-9c3.csv•Alfredmazanoke-images-YWJ6ана Ковалик.jpg•искане даниел Ковалик..pa• Фактура Март Даниел Ковалик.jрс• Фактура Април Даниел Ковалик.jpg• Dhotac 2.001Q SearchKind00,4 MDinstdlle..dckage55.9 MBAlfred...ferences10,1 MBDisk Image10,1 MBDisk ImageIL MBLiP archive6,6 MBZIP archive2,5 MB PDF Document2,5 MBJreo lmage2.2 MBDisk Image2,2 MB PDF Document2 MBJPEG image1,9 MBJPEG imaqe192 KBPDF Document140 KbZIP archive148 KВ148 KB122 KB111 KB94 KBZIP archivelZIP archiveXML documentAlfred...ferencesPDF Document92 KBPDr DocumentK:91 KB91 KB30 KB29 KBPDF DocumentXML documentPDF Document28 KBPDF Document28 KR28 KB27 KB14 KB11 KB6 KB6KBPDE DocumentDocumentJSONICSV DocumentZIP archiveMarkdo…..ument5KRWindo...n image4 KB3 KBword ..cumentCSV Document2 KBYAML document1 KBcSV Document928 byteshttlicence183 bytesZero butesJSONAlfred.. ferencesZero bytesFolde1,9 MB1,8 MB17 MB1,7 MBColdorJPEG imageJPEG ImageJPEG imageJPEG imageColdo1 of 58 selected, 8.5 GB availab!i• Inu 14 Mаy 1/.32.31Date AddedIs Mdl ZUzo dl 19:4530 Jan 2026 at 12:3617 Mar 2026 at 20:2717 Mar 2026 at 20:26Z3 Aor 2020 al 13:0229 Jan 2026 at 15:2019 Dec 2025 at 10:1619 Dec 2025 at 12:238 Aor 2026 at 20:3519 Dec 2025 at 10:2919 Dec 2025 at 12:1819 Dec 2025 at 12:4026 Mar 2026 at 11:2410 May 2026 at 13:5326 Mar 2026 at 11:2426 Mar 2026 at 11:2426 Mar 2026 at 11:2310 May 2026 at 14:3730 Jan 2026 at 12:3713 Feb 2026 at 11:54Z3 Apr 2026 at 13.0823 Aor 2026 at 13:0810 May 2026 at 13:5410 May 2026 at 14:3710 May 2026 at 13:4910 May 2026 at 13:5010 May 2026 at 13:5110 Mav 2026 at 12:51110 May 2026 at 13:5019 Dec 2025 at 11:3431 Oct 2025 at 12:2525 Nov 2025 at 17:596 Mar 2026 at 11.2224 Anr 2026 at 16:5220 Oct 2025 at 11:0218 Mar 2026 at 15:29• Mav 2026 at 11:09129 Oct 2025 at 19:329 May 2026 at 10:0418 Mar 2026 at 11:5510 May 2026 at 13:5712 Jun 2025 at 19:0430 Jan 2026 at 12:3630 Jan 2026 at 12:3616 Oct 2025 aт 16:0123 Apr 2026 at 13:0223 Apr 2026 at 13:0223 Apr 2026 at 13:0222 Anr 2026 at 12:0223 Apr 2026 at 13:0229 Jan 2026 at 15:20...
|
NULL
|
-4849588242053115545
|
NULL
|
click
|
ocr
|
NULL
|
ActivityFilesLaterJiminny... ~@ jiminny-x-integrat ActivityFilesLaterJiminny... ~@ jiminny-x-integrati& platform-inner-team© Channels# ai-chapter# alertsi backend# bugscontusion-cllnia# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the people of iimi..• Direct messages8. A...• A3 62P. Galya Dimitrova Mvasil VasilevA. Stefka Stoyanova%: Todor Stamatovf. Mario GeorgievP. Nikolay Ivanov2o James Graham "2. Stoyan Tanev. Steliyan Georgiev. Petko Kashinski*. Lukas Kovali...a: Apps® ToastS lira Gloud6 Huddle with Aneliya Angelova& R. Aneliya Angelova •• Messagest Add canvasur FilesAneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук,нали?пои останалите скМі тоябва оъчно ла се въвелат.Lukas Kovalik 2:47 PMтряова да се за всички, някьде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova @ 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725X Preview insackt[HubSpot] Optimise CRM rematctC OpenReady for QA- MediumAA Aneliya AngelovaAs of today at 4:00 PM RetreshOpen in Jira+ SummariseLukas Kovalik 4:02 PMzean-iurwiniareelYou joined the huddle LIVE 4:06 PMAneliva Angelova is here toolAneliya Angelova 4:44 PM11512582Lukas Kovalik O 5:16 PMcurl --location "httns:ani.hubani.com/crm/v3/obiects/contacts/search--header 'Content-Type: application/json'\--header "Authorization: BearerC|Kvma?iMx7OINOM8kOFwrAowAcAkUAhIR24?A05D?xiVrIYMILuP6SA01Kwcmhr=n.v2 hytorDniMvDalYck-CMalovolNOM9kOFwrAUAcrkcaws-ThwRARIRAOF-ATFSAOFRAO-ROIEBAQUBEggBAQEBAYICFIґ7Au8O2Nwal9YW2CbCCxYvwngmSgNldTFSAFoAYABoAHAAeAA'\--data "{ "limit", 13'Message Aneliva Angelova+ AaIđ 0Pm~ (Q SearchDate ModifiedYesterdav at 13.36Yesterday at 13:35Yesterday at 13.34Yesterday at 13:34Yesterday at 13:33resterday at 15.5sYesterdav at 13:37Yesterday at 13:32Yesterday at 13.31Yesterday at 13:30Yesterday at 13:30resterday at 15.4gYesterdav at 13:29Yesterday at 13:28Yesterday at 13:28Yesterday at 13:27Yesterday at 13:27resterday at 13.-40Yesterdav at 13:25Yesterday at 13:25Yesterday at 13:24Yesterday at 13:24Yesterday at 13:23Yesterday at 13.21Yesterdav at 13:21Yesterday at 13:20Yesterday at 13:20Yesterday at 13:19Yesterday at 13:19Yesterday at 13.18Vecterdav at 12:17Yesterday at 13:16Yesterdav at 13:16Yesterday at 13:15Yesterday at 13:14Yecterdav at 12:1/Yesterday at 13:13Yesterday at 13.13Yecterdav at 12:12Yesterday at 13:12Yesterday at 13:11Yesterday at 13:10Yesterday at 13:10Yesterday at 13.09Yecterdav at 12:091Yesterday at 13:08Yesterdav at 13:07MPEG-4 movie13 KBMPEG-4 movie16 KB1/ Kb29 KBMPEG-4 movieMPEG-4 movie6 KB12 KBMPE0"4 movie9 K:7 KBMPEG-4 movie8 KB37 KBMP2G-4 movie10 KBMPEG-4 movie7 KBMPEG"4 movie9K:8KBMPEG-4 movie72 KB14 K8|13 KRIMPEG-4 movieMPEG-4 movie9 KB18 KBMPEG-4 movie12 KEMPEG-4 movie10 KBMPEG-4 movie16 KB6 KB1MPEG-4 movie6 KBMPEG-4 movie12 KB23 KBMPEG-4 movie8 KEMPEG-4 movie6 KBMPEG-4 movie6 KBMPEG-4 movie11 K:MPEG-4 movie11 KBMPEG-4 movie34 KBMPEG-4 movie10 KPMPEG-4 movie7 KBMPEG-4 movie5 KBMPEG-4 movie11 KBIMPEG-4 movie26 KBMPEG-4 movie111 KB102 KBRR KRMPEG-4 movieMDEG-A movie59 KB98 KBMPEG-4 movie07 K:MPEG-A movie66 KB MPEG-4 movie44 KB93 KB79 KpMPEG-4 movieMPEG-4 movie58 KBMPEG-4 movie27 KP7 KBMPEG-4 movie12 KB32 K8MPEG-4 movieAl Notes: OffLeave• 0FavouritesE jiminny© Recents* ApplicationsiCloudiCloud Drive228 Sync folderQ DXP4800PLUS-B5FA@ Network|• CRMI• Orange• Red• Yellow• Green• Purple•) All lags..lohlDownloadsNameLoom.pkgAlfred copv.alfredoreterencesB KeychronAssist-1.0.2 (1).dmgA Keychron Assist-1.0.2.dmgmazanoke-images-yWJo.zioPhotos-3-001.zipD Transcript.pdf→mage U.loge1 Orioninstaller.dmaimage.jpg- image (2).1pc• ПО-22221726037035-004-001_ORGES.pdf• %D0%9F%D0%9E-22221726037035-004-001_archive.zipПO-22221726037035-004-001_archive (1).zip• repon 4).XmAltred copy2.altredoreterences05012026_0000000026574472_ SWIFT_OB70501260015890.pdf27022026_0000000026574472_SWIFT_OB72702260049200.pdf= 03042026 [CREDIT_CARD] SWIFT [CREDIT_CARD].001B reporti) xm=pdt.odipdf-1.pdfD pdf-2.pdf-pdf-5.pd1= ndf-1 ndipdf-3.pdfKoválik Family Tree.gedbitwarden export 20251031122528.isonKoválik Family Tree.zip*macOS Storage_Cleanup.mdal favicon icofirst_aid_notes_complete.docxrenortl2).esvconfig.ymlIteration run Search HS.postman_collection.jsonm licence bettertouchtoalMariusHosting Config.json1ooks-891a6503-bbb7-4b2b-9c3.csv•Alfredmazanoke-images-YWJ6ана Ковалик.jpg•искане даниел Ковалик..pa• Фактура Март Даниел Ковалик.jрс• Фактура Април Даниел Ковалик.jpg• Dhotac 2.001Q SearchKind00,4 MDinstdlle..dckage55.9 MBAlfred...ferences10,1 MBDisk Image10,1 MBDisk ImageIL MBLiP archive6,6 MBZIP archive2,5 MB PDF Document2,5 MBJreo lmage2.2 MBDisk Image2,2 MB PDF Document2 MBJPEG image1,9 MBJPEG imaqe192 KBPDF Document140 KbZIP archive148 KВ148 KB122 KB111 KB94 KBZIP archivelZIP archiveXML documentAlfred...ferencesPDF Document92 KBPDr DocumentK:91 KB91 KB30 KB29 KBPDF DocumentXML documentPDF Document28 KBPDF Document28 KR28 KB27 KB14 KB11 KB6 KB6KBPDE DocumentDocumentJSONICSV DocumentZIP archiveMarkdo…..ument5KRWindo...n image4 KB3 KBword ..cumentCSV Document2 KBYAML document1 KBcSV Document928 byteshttlicence183 bytesZero butesJSONAlfred.. ferencesZero bytesFolde1,9 MB1,8 MB17 MB1,7 MBColdorJPEG imageJPEG ImageJPEG imageJPEG imageColdo1 of 58 selected, 8.5 GB availab!i• Inu 14 Mаy 1/.32.31Date AddedIs Mdl ZUzo dl 19:4530 Jan 2026 at 12:3617 Mar 2026 at 20:2717 Mar 2026 at 20:26Z3 Aor 2020 al 13:0229 Jan 2026 at 15:2019 Dec 2025 at 10:1619 Dec 2025 at 12:238 Aor 2026 at 20:3519 Dec 2025 at 10:2919 Dec 2025 at 12:1819 Dec 2025 at 12:4026 Mar 2026 at 11:2410 May 2026 at 13:5326 Mar 2026 at 11:2426 Mar 2026 at 11:2426 Mar 2026 at 11:2310 May 2026 at 14:3730 Jan 2026 at 12:3713 Feb 2026 at 11:54Z3 Apr 2026 at 13.0823 Aor 2026 at 13:0810 May 2026 at 13:5410 May 2026 at 14:3710 May 2026 at 13:4910 May 2026 at 13:5010 May 2026 at 13:5110 Mav 2026 at 12:51110 May 2026 at 13:5019 Dec 2025 at 11:3431 Oct 2025 at 12:2525 Nov 2025 at 17:596 Mar 2026 at 11.2224 Anr 2026 at 16:5220 Oct 2025 at 11:0218 Mar 2026 at 15:29• Mav 2026 at 11:09129 Oct 2025 at 19:329 May 2026 at 10:0418 Mar 2026 at 11:5510 May 2026 at 13:5712 Jun 2025 at 19:0430 Jan 2026 at 12:3630 Jan 2026 at 12:3616 Oct 2025 aт 16:0123 Apr 2026 at 13:0223 Apr 2026 at 13:0223 Apr 2026 at 13:0222 Anr 2026 at 12:0223 Apr 2026 at 13:0229 Jan 2026 at 15:20...
|
45354
|
NULL
|
NULL
|
NULL
|
|
45355
|
1625
|
14
|
2026-05-14T14:32:36.655804+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769156655_m1.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.054166667,"top":0.027777778,"width":0.08055556,"height":0.035555556},"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
PhpStormFileEditViewNavig Project: faVsco.js, menu
PhpStormFileEditViewNavigateCodeLaravelRefactorRunToolsGitWindowHelp•FV faVsco.jsv* #12066 on JY-20725-handle-HS-search-rate-limit k vabl19HandleHubspotRateLimitTest100% C8• Thu 14 May 17:32:36* :QProject v= custom.logAutomatedReportGenerated.phpTrackAutomatedReportGeneratedEvent.phpPlaybackController.php© FieldDefinitions.phpUserAutomatedReportsController.phpPlanhatService.phpAutomatedReportResult.phpSendReportJob.php=laravel.log© FieldValueConverter.php• DeleteCrmEntityTrait.phpDeleteAccountJob.php© ImportActivityTypes.phpT WriteCrmTrait.php© Service.php© DecorateActivity.phpSF [jiminny@localhost]© StandardFieldMetadata.php© Salesforce/Service.php© LogActivityTrait.phpPipedrive/Service.phpClose/Service.phpCopper/Service.php XA HS_local [jiminny@localho:Wv D Copper© PlainTextDecorateActivity.phpT ActivityPlaybookTrait.php© CrmHelperRepository.phpAccountController.php4 console [QAI PROD] X18> D Api› D ExceptionT IntegrationAppTrait.php.env.stagingE.env© DetachActivityObject.phpRematchActivityOnCrmObjectDetach.php4 console [PROD]> C OpportunitySyncStrategy© MatchActivityCrmData.php© Client.php© HubspotPaginationService.php© HandleHubspotRateLimit.phpA console (EU]> D ProspectSearchStrategy52class Service extends BaseService implementsA5 A 36DGojiminny v> CJ Traits© FieldDefinitions.php1662* Othrows CrmException084143 ×4 л© FieldValueConverter.php1663*/215|•m_layout_id =© Service.php1 usage2162,1661,66799,66> D CrmObjects1664private function buildCallPayload(Activity $activity): Activity217v DecorateActivity1665218© BaseDecorateActivity.php1666try{219id = 33;© PlainTextDecorateActivity.pl1667if (Sactivity->crm_provider_id) {=220-221> D Dummy1668// The activity should be logged under the existing Task (not Activity).v Helpers1669$newActivityType = $this->getChmType($activity->category);=222T ActivityPlaybookTrait.php1670if ($newActivityType === null) {=223© Arraylterator.php1671Smessage = sprintf( format: '[Copper] invalid CRM Custom Activity Type: %s', $activity->cat 224id THEN '(own• ConnectionStateTrait.php1672=225© CrmHelperRepository.php1673throw new CrmException(Smessage,code: 400):226© FilterJoinedParticipants.php1674— 227* OpportunitySyncableFieldsT1675$this->copperClient->tasks()->update($activity->crm_provider_id, [228v C Hubspot1676'status'= 'Completed',229• AccountSyncStrategy1677'custom_activity_type_id' => $newActivityType->value,= 230hubspat':> @ Actions|1678'details' => $this->generateActivityDescription($activity),• ContactSyncStrategy[23.16791):1232> ODTO1680j else {233 V= 11512582;› Fields1681if (Sthis-~getCrmType(SactivitX-scategocx)minulln234> • Journal1682$message = sprintf( format:'[Copper] Invalid CRM Activity Type: %s', $activity->category->-D Metadata1683v D OpportunitySyncStrategy1684throw new CrmException($message,code: 400);› D Concerns1685=A Unhonntl actlAndifiaNDur 1686Workspace associated with branch 'JY-20725-handle-HS-search-rate-limit' has been restored // Rollback // Configure... (today 16:17)W Windsurf Teams1669:47UTF-8Ca 4 spaces...
|
45353
|
NULL
|
NULL
|
NULL
|
|
45354
|
1626
|
7
|
2026-05-14T14:32:34.096934+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769154096_m2.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
33...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.2962101,"top":1.0,"width":0.03856383,"height":-0.019952059},"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":"#12066 on JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.33477393,"top":1.0,"width":0.122340426,"height":-0.019952059},"on_screen":true,"help_text":"Pull request #12066 exists for current branch JY-20725-handle-HS-search-rate-limit, but local branch is out of sync with remote","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.5731383,"top":1.0,"width":0.011303191,"height":-0.019952059},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.5884308,"top":1.0,"width":0.076130316,"height":-0.019952059},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.66456115,"top":1.0,"width":0.011303191,"height":-0.019952059},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.67586434,"top":1.0,"width":0.011303191,"height":-0.019952059},"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.6871675,"top":1.0,"width":0.011303191,"height":-0.019952059},"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.7150931,"top":1.0,"width":0.011303191,"height":-0.019952059},"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.72639626,"top":1.0,"width":0.011303191,"height":-0.019952059},"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.73769945,"top":1.0,"width":0.011303191,"height":-0.019952059},"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":"2","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"33","depth":4,"on_screen":true,"role_description":"text"}]...
|
-9194673704168071041
|
-7555842213617218742
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
2
33
ActivityFilesLaterJiminny... ~@ jiminny-x-integrati& platform-inner-team© Channels# ai-chapter# alertsi backend# bugscontusion-cllnia# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the people of iimi..• Direct messages8. A...• A3 62P. Galya Dimitrova Mvasil VasilevA. Stefka Stoyanova%: Todor Stamatovf. Mario GeorgievP. Nikolay Ivanov2o James Graham "2. Stoyan Tanev. Steliyan Georgiev. Petko Kashinski*. Lukas Kovali...a: Apps® ToastS lira Gloud6 Huddle with Aneliya Angelova& R. Aneliya Angelova •• Messagest Add canvasur FilesAneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук,нали?пои останалите скМі тоябва оъчно ла се въвелат.Lukas Kovalik 2:47 PMтряова да се за всички, някьде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova @ 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725X Preview insackt[HubSpot] Optimise CRM rematctC OpenReady for QA- MediumAA Aneliya AngelovaAs of today at 4:00 PM RetreshOpen in Jira+ SummariseLukas Kovalik 4:02 PMzean-iurwiniareelYou joined the huddle LIVE 4:06 PMAneliva Angelova is here toolAneliya Angelova 4:44 PM11512582Lukas Kovalik O 5:16 PMcurl --location "httns:ani.hubani.com/crm/v3/obiects/contacts/search--header 'Content-Type: application/json'\--header "Authorization: BearerC|Kvma?iMx7OINOM8kOFwrAowAcAkUAhIR24?A05D?xiVrIYMILuP6SA01Kwcmhr=n.v2 hytorDniMvDalYck-CMalovolNOM9kOFwrAUAcrkcaws-ThwRARIRAOF-ATFSAOFRAO-ROIEBAQUBEggBAQEBAYICFIґ7Au8O2Nwal9YW2CbCCxYvwngmSgNldTFSAFoAYABoAHAAeAA'\--data "{ "limit", 13'Message Aneliva Angelova+ AaIđ 0Pm~ (Q SearchDate ModifiedYesterdav at 13.36Yesterday at 13:35Yesterday at 13.34Yesterday at 13:34Yesterday at 13:33resterday at 15.5sYesterdav at 13:37Yesterday at 13:32Yesterday ar 13.31Yesterday at 13:30Yesterday at 13:30resterday at 15.4gYesterdav at 13:29Yesterday at 13:28Yesterday at 13:28Yesterday at 13:27Yesterday at 13:27resterday at 13-40Yesterdav at 13:25Yesterday at 13:25Yesterday at 13:24Yesterday at 13:24Yesterday at 13:23Yesterday at 13.21Yesterdav at 13:21Yesterday at 13:20Yesterday at 13:20Yesterday at 13:19Yesterday at 13:19Yesterday at 13.18Vecterdav at 12:17Yesterday at 13:16Yesterdav at 13:16Yesterday at 13:15Yesterday at 13:14Yecterdav at 12:1/Yesterday at 13:13Yesterday at 13.13Yecterdav at 12:12Yesterday at 13:12Yesterday at 13:11Yesterday at 13:10Yesterday at 13:10Yesterday at 13.09Yecterdav at 12:091Yesterday at 13:08Yesterdav at 13:07MPEG-4 movie13 KBMPEG-4 movie16 KB1/ Kb29 KBMPEG-4 movieMPEG-4 movie6 KB12 KBMPE0"4 movie9 K:7 KBMPEG-4 movie8 KB37 KBMP2G-4 movie10 KBMPEG-4 movie7 KBMPEG"4 movie9K:8KBMPEG-4 movie72 KB14 K8|13 KRIMPEG-4 movieMPEG-4 movie9 KB18 KBMPEG-4 movie12 KEMPEG-4 movie10 KBMPEG-4 movie16 KB6 KB1MPEG-4 movie6 KBMPEG-4 movie12 KB23 KBMPEG-4 movie8 KEMPEG-4 movie6 KBMPEG-4 movie6 KBMPEG-4 movie11 K:MPEG-4 movie11 KBMPEG-4 movie34 KBMPEG-4 movie10 KPMPEG-4 movie7 KBMPEG-4 movie5 KBMPEG-4 movie11 KBIMPEG-4 movie26 KBMPEG-4 movie111 KB102 KBRR KRMPEG-4 movieMDEG-A movie59 KB98 KBMPEG-4 movie07 K:MPEG-A movie66 KB MPEG-4 movie44 KB93 KB79 KpMPEG-4 movieMPEG-4 movie58 KBMPEG-4 movie27 KP7 KBMPEG-4 movie12 KB32 K8MPEG-4 movieAl Notes: OffLeave• 0FavouritesE jiminny© Recents* ApplicationsiCloudiCloud Drive228 Sync folderQ DXP4800PLUS-B5FA@ Network|• CRMI• Orange• Red• Yellow• Green• Purple•) All lags..lohlDownloadsNameLoom.pkgAlfred copv.alfredoreterencesB KeychronAssist-1.0.2 (1).dmgA Keychron Assist-1.0.2.dmgmazanoke-images-yWJo.zioPhotos-3-001.zipD Transcript.pdf→mage U.loge1 Orioninstaller.dmaimage.jpg- image (2).1pc• ПО-22221726037035-004-001_ORGES.pdf• %D0%9F%D0%9E-22221726037035-004-001_archive.zipПO-22221726037035-004-001_archive (1).zip• repon 4).XmAltred copy2.altredoreterences05012026_0000000026574472_ SWIFT_OB70501260015890.pdf27022026_0000000026574472_SWIFT_OB72702260049200.pdf= 03042026 [CREDIT_CARD] SWIFT [CREDIT_CARD].001B reporti) xm=pdt.odipdf-1.pdfD pdf-2.pdf-pdf-5.pd1= ndf-1 ndipdf-3.pdfKoválik Family Tree.gedbitwarden export 20251031122528.isonKoválik Family Tree.zip*macOS Storage_Cleanup.mdal favicon icofirst_aid_notes_complete.docxrenortl2).esvconfig.ymlIteration run Search HS.postman_collection.jsonm licence bettertouchtoalMariusHosting Config.json1ooks-891a6503-bbb7-4b2b-9c3.csv•Alfredmazanoke-images-YWJ6ана Ковалик.jpg•искане даниел Ковалик..pa• Фактура Март Даниел Ковалик.jрс• Фактура Април Даниел Ковалик.jpg• Dhotac 2.001Q SearchKind00,4 MDinstdlle..dckage55.9 MBAlfred...ferences10,1 MBDisk Image10,1 MBDisk ImageIL MBLiP archive6,6 MBZIP archive2,5 MB PDF Document2,5 MBJreo lmage2.2 MBDisk Image2,2 MB PDF Document2 MBJPEG image1,9 MBJPEG imaqe192 KBPDF Document140 KbZIP archive148 KВ148 KB122 KB111 KB94 KBZIP archivelZIP archiveXML documentAlfred...ferencesPDF Document92 KBPDr DocumentK:91 KB91 KB30 KB29 KBPDF DocumentXML documentPDF Document28 KBPDF Document28 KR28 KB27 KB14 KB11 KB6 KB6KBPDE DocumentDocumentJSONICSV DocumentZIP archiveMarkdo…..ument5KRWindo...n image4 KB3 KBword ..cumentCSV Document2 KBYAML document1 KBcSV Document928 byteshttlicence183 bytesZero butesJSONAlfred.. ferencesZero bytesFolde1,9 MB1,8 MB17 MB1,7 MBColdorJPEG imageJPEG ImageIPEG imadeJPEG imageColdo1 of 58 selected, 8.51 G8 availabld• Inu 14 Mаy 1/•32.32Date AddedIs Mdl ZUzo dl 19:4530 Jan 2026 at 12:3617 Mar 2026 at 20:2717 Mar 2026 at 20:26Z3 Aor 2020 al 13:0229 Jan 2026 at 15:2019 Dec 2025 at 10:1619 Dec 2025 at 12:238 Aor 2026 at 20:3519 Dec 2025 at 10:2919 Dec 2025 at 12:1819 Dec 2025 at 12:4026 Mar 2026 at 11:2410 May 2026 at 13:5326 Mar 2026 at 11:2426 Mar 2026 at 11:2426 Mar 2026 at 11:2310 May 2026 at 14:3730 Jan 2026 at 12:3713 Feb 2026 at 11:54Z3 Apr 2026 at 13.0823 Aor 2026 at 13:0810 May 2026 at 13:5410 May 2026 at 14:3710 May 2026 at 13:4910 May 2026 at 13:5010 May 2026 at 13:5110 Mav 2026 at 12:51110 May 2026 at 13:5019 Dec 2025 at 11:3431 Oct 2025 at 12:2525 Nov 2025 at 17:596 Mar 2026 at 11.2224 Anr 2026 at 16:5220 Oct 2025 at 11:0218 Mar 2026 at 15:29• Mav 2026 at 11:09129 Oct 2025 at 19:329 May 2026 at 10:0418 Mar 2026 at 11:5510 May 2026 at 13:5712 Jun 2025 at 19:0430 Jan 2026 at 12:3630 Jan 2026 at 12:3616 Oct 2025 aт 16:0123 Apr 2026 at 13:0223 Apr 2026 at 13:0223 Apr 2026 at 13:0222 Anr 2026 at 12:0223 Apr 2026 at 13:0229 Jan 2026 at 15:20...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
45352
|
1626
|
6
|
2026-05-14T14:32:28.831014+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769148831_m2.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.2962101,"top":1.0,"width":0.03856383,"height":-0.019952059},"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":"#12066 on JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.33477393,"top":1.0,"width":0.122340426,"height":-0.019952059},"on_screen":true,"help_text":"Pull request #12066 exists for current branch JY-20725-handle-HS-search-rate-limit, but local branch is out of sync with remote","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.5731383,"top":1.0,"width":0.011303191,"height":-0.019952059},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.5884308,"top":1.0,"width":0.076130316,"height":-0.019952059},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.66456115,"top":1.0,"width":0.011303191,"height":-0.019952059},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.67586434,"top":1.0,"width":0.011303191,"height":-0.019952059},"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.6871675,"top":1.0,"width":0.011303191,"height":-0.019952059},"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.7150931,"top":1.0,"width":0.011303191,"height":-0.019952059},"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.72639626,"top":1.0,"width":0.011303191,"height":-0.019952059},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
1160075880258684949
|
-8349599981661484599
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
ActivityFilesLaterJiminny... ~@ jiminny-x-integrati& platform-inner-team© Channels# ai-chapter# alertsi backend# bugscontusion-cllnia# curiosity_lab# engineering# general# jiminny-bg# platform-tickets# product_launches# random# releases# sofia-office# support# thank-yous# the people of iimi..• Direct messages8. A...• A3 62P. Galya Dimitrova Mvasil VasilevA. Stefka Stoyanova%: Todor Stamatovf. Mario GeorgievP. Nikolay Ivanov2o James Graham "2. Stoyan Tanev. Steliyan Georgiev. Petko Kashinski*. Lukas Kovali...a: Apps® ToastS lira Gloud6 Huddle with Aneliya Angelova& R. Aneliya Angelova •• Messagest Add canvasur FilesAneliya Angelova 2:30 PMЛукаш, само при Сейлсфорс и Хубспот се синкваха активити типовете, когато се направи плейбук,нали?пои останалите скМі тоябва оъчно ла се въвелат.Lukas Kovalik 2:47 PMтряова да се за всички, някьде не се ли попьлвапри зохо май беше hardcoded но май и там си връщаха две категорииAneliya Angelova @ 4:00 PMЛукаш имаш ли време да се чуем за тестването на https://jiminny.atlassian.net/browse/JY-20725X Preview insackt[HubSpot] Optimise CRM rematctC OpenReady for QA- MediumAA Aneliya AngelovaAs of today at 4:00 PM RetreshOpen in Jira+ SummariseLukas Kovalik 4:02 PMzean-iurwiniareelYou joined the huddle LIVE 4:06 PMAneliva Angelova is here toolAneliya Angelova 4:44 PM11512582Lukas Kovalik O 5:16 PMcurl --location "httns:ani.hubani.com/crm/v3/obiects/contacts/search--header 'Content-Type: application/json'\--header "Authorization: BearerC|Kvma?iMx7OINOM8kOFwrAowAcAkUAhIR24?A05D?xiVrIYMILuP6SA01Kwcmhr=n.v2 hytorDniMvDalYck-CMalovolNOM9kOFwrAUAcrkcaws-ThwRARIRAOF-ATFSAOFRAO-ROIEBAQUBEggBAQEBAYICFIґ7Au8O2Nwal9YW2CbCCxYvwngmSgNldTFSAFoAYABoAHAAeAA'\--data "{ "limit", 13'Message Aneliva Angelova+ AaIđ 0Pm~ (Q SearchDate ModifiedYesterdav at 13.36Yesterday at 13:35Yesterday at 13.34Yesterday at 13:34Yesterday at 13:33resterday at 15.5sYesterdav at 13:37Yesterday at 13:32Yesterday ar 13.31Yesterday at 13:30Yesterday at 13:30resterday at 15.4gYesterdav at 13:29Yesterday at 13:28Yesterday at 13:28Yesterday at 13:27Yesterday at 13:27resterday at 13-40Yesterdav at 13:25Yesterday at 13:25Yesterday at 13:24Yesterday at 13:24Yesterday at 13:23Yesterday at 13.21Yesterdav at 13:21Yesterday at 13:20Yesterday at 13:20Yesterday at 13:19Yesterday at 13:19Yesterday at 13.18Vecterdav at 12:17Yesterday at 13:16Yesterdav at 13:16Yesterday at 13:15Yesterday at 13:14Yecterdav at 12:1/Yesterday at 13:13Yesterday at 13.13Yecterdav at 12:12Yesterday at 13:12Yesterday at 13:11Yesterday at 13:10Yesterday at 13:10Yesterday at 13.09Yecterdav at 12:091Yesterday at 13:08Yesterdav at 13:07MPEG-4 movie13 KBMPEG-4 movie16 KB1/ Kb29 KBMPEG-4 movieMPEG-4 movie6 KB12 KBMPE0"4 movie9 K:7 KBMPEG-4 movie8 KB37 KBMP2G-4 movie10 KBMPEG-4 movie7 KBMPEG"4 movie9K:8KBMPEG-4 movie72 KB14 K8|13 KRIMPEG-4 movieMPEG-4 movie9 KB18 KBMPEG-4 movie12 KEMPEG-4 movie10 KBMPEG-4 movie16 KB6 KB1MPEG-4 movie6 KBMPEG-4 movie12 KB23 KBMPEG-4 movie8 KEMPEG-4 movie6 KBMPEG-4 movie6 KBMPEG-4 movie11 K:MPEG-4 movie11 KBMPEG-4 movie34 KBMPEG-4 movie10 KPMPEG-4 movie7 KBMPEG-4 movie5 KBMPEG-4 movie11 KBIMPEG-4 movie26 KBMPEG-4 movie111 KB102 KBRR KRMPEG-4 movieMDEG-A movie59 KB98 KBMPEG-4 movie07 K:MPEG-A movie66 KB MPEG-4 movie44 KB93 KB79 KpMPEG-4 movieMPEG-4 movie58 KBMPEG-4 movie27 KP7 KBMPEG-4 movie12 KB32 K8MPEG-4 movieAl Notes: OffLeave• 0FavouritesE jiminny© Recents* ApplicationsiCloudiCloud Drive228 Sync folderQ DXP4800PLUS-B5FA@ Network|• CRMI• Orange• Red• Yellow• Green• Purple•) All lags..lohlDownloadsNameLoom.pkgAlfred copv.alfredoreterencesB KeychronAssist-1.0.2 (1).dmgA Keychron Assist-1.0.2.dmgmazanoke-images-yWJo.zioPhotos-3-001.zipD Transcript.pdf→mage U.loge1 Orioninstaller.dmaimage.jpg- image (2).1pc• ПО-22221726037035-004-001_ORGES.pdf• %D0%9F%D0%9E-22221726037035-004-001_archive.zipПO-22221726037035-004-001_archive (1).zip• repon 4).XmAltred copy2.altredoreterences05012026_0000000026574472_ SWIFT_OB70501260015890.pdf27022026_0000000026574472_SWIFT_OB72702260049200.pdf= 03042026 [CREDIT_CARD] SWIFT [CREDIT_CARD].001B reporti) xm=pdt.odipdf-1.pdfD pdf-2.pdf-pdf-5.pd1= ndf-1 ndipdf-3.pdfKoválik Family Tree.gedbitwarden export 20251031122528.isonKoválik Family Tree.zip*macOS Storage_Cleanup.mdal favicon icofirst_aid_notes_complete.docxrenortl2).esvconfig.ymlIteration run Search HS.postman_collection.jsonm licence bettertouchtoalMariusHosting Config.json1ooks-891a6503-bbb7-4b2b-9c3.csv•Alfredmazanoke-images-YWJ6ана Ковалик.jpg•искане даниел Ковалик..pa• Фактура Март Даниел Ковалик.jрс• Фактура Април Даниел Ковалик.jpg• Dhotac 2.001Q SearchKind00,4 MDinstdlle..dckage55.9 MBAlfred...ferences10,1 MBDisk Image10,1 MBDisk ImageIL MBLiP archive6,6 MBZIP archive2,5 MB PDF Document2,5 MBJreo lmage2.2 MBDisk Image2,2 MB PDF Document2 MBJPEG image1,9 MBJPEG imaqe192 KBPDF Document140 KbZIP archive148 KВ148 KB122 KB111 KB94 KBZIP archivelZIP archiveXML documentAlfred...ferencesPDF Document92 KBPDr DocumentK:91 KB91 KB30 KB29 KBPDF DocumentXML documentPDF Document28 KBPDF Document28 KR28 KB27 KB14 KB11 KB6 KB6KBPDE DocumentDocumentJSONICSV DocumentZIP archiveMarkdo…..ument5KRWindo...n image4 KB3 KBword ..cumentCSV Document2 KBYAML document1 KBcSV Document928 byteshttlicence183 bytesZero butesJSONAlfred.. ferencesZero bytesFolde1,9 MB1,8 MB17 MB1,7 MBColdorJPEG imageJPEG ImageIPEG imadeJPEG imageColdo1 of 58 selected, 8.51 G8 availabld• Inu 14 Mаy 1/•32-20Date AddedIs Mdl ZUzo dl 19:4530 Jan 2026 at 12:3617 Mar 2026 at 20:2717 Mar 2026 at 20:26Z3 Aor 2020 al 13:0229 Jan 2026 at 15:2019 Dec 2025 at 10:1619 Dec 2025 at 12:238 Aor 2026 at 20:3519 Dec 2025 at 10:2919 Dec 2025 at 12:1819 Dec 2025 at 12:4026 Mar 2026 at 11:2410 May 2026 at 13:5326 Mar 2026 at 11:2426 Mar 2026 at 11:2426 Mar 2026 at 11:2310 May 2026 at 14:3730 Jan 2026 at 12:3713 Feb 2026 at 11:54Z3 Apr 2026 at 13.0823 Aor 2026 at 13:0810 May 2026 at 13:5410 May 2026 at 14:3710 May 2026 at 13:4910 May 2026 at 13:5010 May 2026 at 13:5110 Mav 2026 at 12:51110 May 2026 at 13:5019 Dec 2025 at 11:3431 Oct 2025 at 12:2525 Nov 2025 at 17:596 Mar 2026 at 11.2224 Anr 2026 at 16:5220 Oct 2025 at 11:0218 Mar 2026 at 15:29• Mav 2026 at 11:09129 Oct 2025 at 19:329 May 2026 at 10:0418 Mar 2026 at 11:5510 May 2026 at 13:5712 Jun 2025 at 19:0430 Jan 2026 at 12:3630 Jan 2026 at 12:3616 Oct 2025 aт 16:0123 Apr 2026 at 13:0223 Apr 2026 at 13:0223 Apr 2026 at 13:0222 Anr 2026 at 12:0223 Apr 2026 at 13:0229 Jan 2026 at 15:20...
|
45347
|
NULL
|
NULL
|
NULL
|
|
45351
|
1625
|
12
|
2026-05-14T14:32:28.831004+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769148831_m1.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.054166667,"top":0.027777778,"width":0.08055556,"height":0.035555556},"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":"#12066 on JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.13472222,"top":0.027777778,"width":0.25555557,"height":0.035555556},"on_screen":true,"help_text":"Pull request #12066 exists for current branch JY-20725-handle-HS-search-rate-limit, but local branch is out of sync with remote","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
7293744273990285589
|
-6961648536715800593
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
PhpStorm•FileFV faVsco.jsvEditViewNavigateCodeLaravelRefactorRunToolsGitWindowHelpabl100% C#12066 on JY-20725-handle-HS-search-rate-limit K vHandleHubspotRateLimitTestv* :8• Thu 14 May 17:32:28QProject v:=custom.logAutomatedReportGenerated.phpTrackAutomatedReportGeneratedEvent.phpPlaybackController.php© FieldDefinitions.phpUserAutomatedReportsController.phpPlanhatService.phpAutomatedReportResult.phpSendReportJob.php© FieldValueConverter.php• DeleteCrmEntityTrait.phpDeleteAccountJob.php© ImportActivityTypes.phpT WriteCrmTrait.phpDecorateActivity.php© Service.php© StandardFieldMetadata.php© Salesforce/Service.php© LogActivityTrait.phpPipedrive/Service.phpClose/Service.phpCopper/Service.php Xv D Copper© PlainTextDecorateActivity.phpT ActivityPlaybookTrait.php© CrmHelperRepository.phpAccountController.php18> D Api> D ExceptionT IntegrationAppTrait.php.env.stagingE.env© DetachActivityObject.phpRematchActivityOnCrmObjectDetach.php> C OpportunitySyncStrategy> D ProspectSearchStrategy> CJ Traits© MatchActivityCrmData.phpClient.php© HubspotPaginationService.phpclassService extendsBaseService implementsstring/nullHandleHubspotRateLimit.php© FieldDefinitions.php© FieldValueConverter.php© Service.php> D CrmObjects521517151815191520 € ›1557* }.*/public function matchByName(string $name, ?int $userId = null): ?array{...}v DecorateActivity3 usages© BaseDecorateActivity.php1558private function convertCrmData(array $object, string $objectType, ?int $userId = null): array{.© PlainTextDecorateActivity.pl1611> D Dummy1612 Cpublic function saveActivity(Activity $activity): Activityv Helpers1613T ActivityPlaybookTrait.php1614© Arraylterator.php1615• ConnectionStateTrait.php1616© CrmHelperRepository.php1617© FilterJoinedParticipants.php1618switch (Sactivity->type) {case Activity:: TYPE_CONFERENCE:case Activity:: TYPE_SOFTPHONE:case Activity: : TYPE_SOFTPHONE_INBOUND:Sactivity = $this->buildCallPayload(Sactivity):* OpportunitySyncableFieldsT1619v C Hubspot1620• AccountSyncStrategy1621> DJ Actions |1622• ContactSyncStrategy1623break;case Activity:: TYPE_SMS_INBOUND:case Activity: : TYPE_SMS_OUTBOUND:Sactivity = $this->buildTextMessagePayload($activity);> ODTO1624› Fields1625break:> • Journal1626D Metadata1627v D OpportunitySyncStrategy1628return Sactivity:> D Concerns1629A Lihonntl actlAndifiaNDurWorkspace associated with branch 'JY-20725-handle-HS-search-rate-limit' has been restored // Rollback // Configure... (today 16:17)Analyzing…=laravel.logSF [jiminny@localhost]A HS_local [jiminny@localho:W4 console [QAI PROD] X4 console [PROD]A console (EU]DGo jiminny084143 ×4 л215|•m_layout_id =2162,1661,66799,66217218219id = 33;220221222223224id THEN '(own225226227228229230hubspot':-231+ 232233V= 11512582;234W Windsurf Teams1612:21UTF-8Ca 4 spaces...
|
45350
|
NULL
|
NULL
|
NULL
|
|
45348
|
1625
|
9
|
2026-05-14T14:32:21.857625+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769141857_m1.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
PhpStormFileEditViewNavigateCodeLaravelRefactorRun PhpStormFileEditViewNavigateCodeLaravelRefactorRunToolsGitWindowHelp•FV faVsco.jsv* #12066 on JY-20725-handle-HS-search-rate-limit k vabl19HandleHubspotRateLimitTestv100% C8• Thu 14 May 17:32:21* :QProject v+,.х:=AutomatedReportGenerated.phpTrackAutomatedReportGeneratedEvent.phpPlaybackController.php© FieldDefinitions.phpUserAutomatedReportsController.phpPlanhatService.phpAutomatedReportResult.phpSendReportJob.php© FieldValueConverter.php• DeleteCrmEntityTrait.phpDeleteAccountJob.php© ImportActivityTypes.phpT WriteCrmTrait.php© Service.php© DecorateActivity.php© StandardFieldMetadata.php© Salesforce/Service.php© LogActivityTrait.phpPipedrive/Service.phpClose/Service.phpService.php Xv D Copper© PlainTextDecorateActivity.phpT ActivityPlaybookTrait.php© CrmHelperRepository.phpAccountController.php18> D Api> D ExceptionT IntegrationAppTrait.php.env.stagingE.env© DetachActivityObject.phpRematchActivityOnCrmObjectDetach.php> C OpportunitySyncStrategy> D ProspectSearchStrategy© MatchActivityCrmData.php<?phpClient.php© HubspotPaginationService.php© HandleHubspotRateLimit.php1> D Traits© FieldDefinitions.php3namespace Jiminny (Services \Crm\Copper;© FieldValueConverter.php© Service.phpuse> D CrmObjectsv DecorateActivity51© BaseDecorateActivity.php© PlainTextDecorateActivity.pl> D Dummyv HelpersT ActivityPlaybookTrait.php© Arraylterator.php• ConnectionStateTrait.php© CrmHelperRepository.php© FilterJoinedParticipants.php* OpportunitySyncableFieldsTv D Hubspot• AccountSyncStrategy525354555657585960616263class Service extends BaseService implementsCopperInterface,SyncCrmEntitiesInterface,SyncCrmMetadataInterface,RemoteEntityManipulationInterface,LayoutManagementInterface,SettingsInterface,MatchCrmEntitiesInterface,RemoteEntityLookupInterface,VerifyTaskExistsInterfaceuse SearchesCrmEntities;> OJ Actions• ContactSyncStrategy> ODTO> D Fields6465private const int NOTE_BODY_MAX_LENGTH = 3000000;> • JournalD Metadata6667private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 dayv D OpportunitySyncStrategy> D Concerns68pnivate const annay STANDARD_OPPORTUNITY_FTELDS =[A Lihonatl actlAndifioNDurWorkspace associated with branch 'JY-20725-handle-HS-search-rate-limit' has been restored // Rollback // Configure... (today 16:17)=custom.log=laravel.logSF [jiminny@localhost]A HS_local [jiminny@localho:4 console [QAI PROD] X4 console [PROD]A console (EU]D V234Go jiminny08 4143 ×4 ^•m_layout_id =2,1661,66799,66id = 33;id THEN •(ownhubspot':-= 11512582;W Windsurf Teams52:7UTF-8Ca 4 spaces...
|
NULL
|
-8418106964736389457
|
NULL
|
click
|
ocr
|
NULL
|
PhpStormFileEditViewNavigateCodeLaravelRefactorRun PhpStormFileEditViewNavigateCodeLaravelRefactorRunToolsGitWindowHelp•FV faVsco.jsv* #12066 on JY-20725-handle-HS-search-rate-limit k vabl19HandleHubspotRateLimitTestv100% C8• Thu 14 May 17:32:21* :QProject v+,.х:=AutomatedReportGenerated.phpTrackAutomatedReportGeneratedEvent.phpPlaybackController.php© FieldDefinitions.phpUserAutomatedReportsController.phpPlanhatService.phpAutomatedReportResult.phpSendReportJob.php© FieldValueConverter.php• DeleteCrmEntityTrait.phpDeleteAccountJob.php© ImportActivityTypes.phpT WriteCrmTrait.php© Service.php© DecorateActivity.php© StandardFieldMetadata.php© Salesforce/Service.php© LogActivityTrait.phpPipedrive/Service.phpClose/Service.phpService.php Xv D Copper© PlainTextDecorateActivity.phpT ActivityPlaybookTrait.php© CrmHelperRepository.phpAccountController.php18> D Api> D ExceptionT IntegrationAppTrait.php.env.stagingE.env© DetachActivityObject.phpRematchActivityOnCrmObjectDetach.php> C OpportunitySyncStrategy> D ProspectSearchStrategy© MatchActivityCrmData.php<?phpClient.php© HubspotPaginationService.php© HandleHubspotRateLimit.php1> D Traits© FieldDefinitions.php3namespace Jiminny (Services \Crm\Copper;© FieldValueConverter.php© Service.phpuse> D CrmObjectsv DecorateActivity51© BaseDecorateActivity.php© PlainTextDecorateActivity.pl> D Dummyv HelpersT ActivityPlaybookTrait.php© Arraylterator.php• ConnectionStateTrait.php© CrmHelperRepository.php© FilterJoinedParticipants.php* OpportunitySyncableFieldsTv D Hubspot• AccountSyncStrategy525354555657585960616263class Service extends BaseService implementsCopperInterface,SyncCrmEntitiesInterface,SyncCrmMetadataInterface,RemoteEntityManipulationInterface,LayoutManagementInterface,SettingsInterface,MatchCrmEntitiesInterface,RemoteEntityLookupInterface,VerifyTaskExistsInterfaceuse SearchesCrmEntities;> OJ Actions• ContactSyncStrategy> ODTO> D Fields6465private const int NOTE_BODY_MAX_LENGTH = 3000000;> • JournalD Metadata6667private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 dayv D OpportunitySyncStrategy> D Concerns68pnivate const annay STANDARD_OPPORTUNITY_FTELDS =[A Lihonatl actlAndifioNDurWorkspace associated with branch 'JY-20725-handle-HS-search-rate-limit' has been restored // Rollback // Configure... (today 16:17)=custom.log=laravel.logSF [jiminny@localhost]A HS_local [jiminny@localho:4 console [QAI PROD] X4 console [PROD]A console (EU]D V234Go jiminny08 4143 ×4 ^•m_layout_id =2,1661,66799,66id = 33;id THEN •(ownhubspot':-= 11512582;W Windsurf Teams52:7UTF-8Ca 4 spaces...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
45347
|
1626
|
5
|
2026-05-14T14:32:22.121934+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778769142121_m2.jpg...
|
PhpStorm
|
faVsco.js – Copper/Service.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Crm\Copper;
use Carbon\Carbon;
use Exception;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Support\Facades\Cache;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\CopperInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Crm\LayoutEntity;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Repositories\UserRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Copper\Api\Client;
use Jiminny\Services\Crm\Copper\Api\ClientFactory;
use Jiminny\Services\Crm\Copper\Exception\RequestFailedException;
use Jiminny\Services\Crm\Helpers\FilterJoinedParticipants;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\Copper\Traits\SearchesCrmEntities;
use Jiminny\Utils\CurrencyFormatter;
use Jiminny\Utils\StringUtil;
class Service extends BaseService implements
CopperInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
RemoteEntityManipulationInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use SearchesCrmEntities;
private const int NOTE_BODY_MAX_LENGTH = 3000000;
private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day
private const array STANDARD_OPPORTUNITY_FIELDS = [
'monetary_value' => [
'label' => 'Value',
'available_on' => Field::OBJECT_OPPORTUNITY,
'type' => Field::TYPE_CURRENCY,
],
'pipeline_stage_id' => [
'label' => 'Stage',
'type' => Field::TYPE_PICKLIST,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
'close_date' => [
'label' => 'Close date',
'type' => Field::TYPE_DATE,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
'win_probability' => [
'label' => 'Win probability',
'type' => Field::TYPE_NUMBER,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
];
private const string UNSUPPORTED_OBJECT_TYPE = 'unsupported';
private const string OPPORTUNITY_STATUS_OPEN = 'Open';
private const string OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE = 'Opportunity import failed';
private const string RESOURCE_UPDATE_FAILED_ERROR_MESSAGE = 'Failed to update resource';
private FieldValueConverter $fieldValueConverter;
private ClientFactory $clientFactory;
private ?Client $copperClient = null;
public function __construct(
ClientFactory $clientFactory,
FieldValueConverter $fieldValueConverter,
private readonly UserRepository $userRepository,
private readonly ProspectPhotoPathService $prospectPhotoPathService,
private readonly CrmEntityRepository $crmEntityRepository
) {
parent::__construct();
$this->clientFactory = $clientFactory;
$this->fieldValueConverter = $fieldValueConverter;
}
public function getDisplayName(): string
{
return 'Copper';
}
/**
* Get the CRM entity repository (used by SearchesCrmEntities trait)
*/
protected function getCrmEntityRepository(): CrmEntityRepository
{
return $this->crmEntityRepository;
}
public function getMinimumApiVersion(): string
{
return Client::MIN_API_VERSION;
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
$owner = $user->team->owner;
return $owner->getSocialAccount(SocialAccount::PROVIDER_COPPER);
}
public function setUser(User $user): void
{
$this->configureSentryScope($user);
$this->team = $user->getTeam();
$this->teamService->setTeam($user->getTeam());
$this->setConfiguration($user->getTeam()->getCrmConfiguration());
// Reset state.
$this->profile = $user->getProfile();
if (! $this->profile instanceof Profile) {
// Try to fetch their profile, maybe it was not yet imported?
$this->profile = $this->getProfile($user);
}
}
public function setConfiguration(Configuration $configuration): void
{
$this->config = $configuration;
$this->copperClient = $this->clientFactory->create($configuration);
if ($this->team === null) {
$this->team = $configuration->getTeam();
}
}
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);
}
private function mapObjectType(string $objectType): string
{
$objectType = strtolower($objectType);
switch ($objectType) {
case Field::OBJECT_TASK:
case Field::OBJECT_OPPORTUNITY:
case Field::OBJECT_LEAD:
$mappedType = $objectType;
break;
case Field::OBJECT_ACCOUNT:
$mappedType = 'company';
break;
case Field::OBJECT_CONTACT:
$mappedType = 'person';
break;
default:
$mappedType = self::UNSUPPORTED_OBJECT_TYPE;
break;
}
return $mappedType;
}
/**
* @param string $crmObject The name of the CRM object. i.e. Opportunity or Contact
*/
protected function getFields(string $crmObject): array
{
$mappedObjectType = $this->mapObjectType($crmObject);
if (! $this->isSupportedObjectType($mappedObjectType)) {
return [];
}
$customFields = $this->copperClient->fields()->all();
$filteredFields = array_filter(
$customFields,
static fn ($field) => in_array($mappedObjectType, $field['available_on'], true)
);
return array_map(
fn (array $property) => [
'name' => $property['id'],
'label' => $property['name'],
'type' => $this->convertFieldType($property['data_type']),
],
$filteredFields
);
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
// Setup the activity field as the default Type.
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'type',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldFilters = FieldDefinitions::taskFollowupFieldsFilter();
foreach ($fieldFilters as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
public function syncFields(): void
{
$this->syncStandardFields();
$this->syncCustomFields();
}
public function syncField(Field $field): void
{
if ($field->getCrmProviderId() === 'type') {
/**
* This field is a special case, it is not a custom field and is not returned by the Copper API.
*
* The field is created manually during layout setup.
*
* @see getDefaultFields()
*
* There is a separate endpoint to get the activity types.
* @see importPicklistValues()
*/
return;
}
if ($field->getCrmProviderId() === 'pipeline_stage_id') {
// Not a custom type
return;
}
$crmField = $this->copperClient->fields()->find($field->getCrmProviderId());
$field->label = $crmField['name'];
$field->type = $this->convertFieldType($crmField['data_type']);
$field->save();
}
/**
* @param string $fieldType How the data should be input
*/
private function convertFieldType(string $fieldType): string
{
$fieldType = strtolower($fieldType);
switch ($fieldType) {
case 'dropdown':
$convertedType = Field::TYPE_PICKLIST;
break;
case 'string':
$convertedType = Field::TYPE_TEXT;
break;
case 'float':
case 'percentage':
$convertedType = Field::TYPE_NUMBER;
break;
case 'text':
$convertedType = Field::TYPE_TEXTAREA;
break;
case 'checkbox':
$convertedType = Field::TYPE_BOOLEAN;
break;
case Field::TYPE_DATE:
case Field::TYPE_CURRENCY:
case Field::TYPE_URL:
$convertedType = $fieldType;
break;
default:
$convertedType = Field::TYPE_UNSUPPORTED;
break;
}
return $convertedType;
}
/**
* @inheritdoc
*/
public function importPicklistValues(Field $field): array
{
$fieldValues = [];
if ($field->object_type === 'opportunity' && $field->crm_provider_id === 'pipeline_stage_id') {
return $this->importFieldValuesForDealInsights($field);
}
$values = [];
if ($field->object_type === Field::OBJECT_TASK && $field->crm_provider_id === 'type') {
$activityTypes = $this->copperClient->activityTypes()->all();
/**
* We ignore "system" activity types, disabled activity types and the "Note" activity type.
*/
$activityTypes = array_filter(
$activityTypes['user'],
fn (array $activityType) => ! $activityType['is_disabled'] && $activityType['id'] !== 0
);
// Import all activity values.
$i = 0;
foreach ($activityTypes as $activityType) {
$values[] = [
'value' => $activityType['id'],
'label' => mb_strimwidth($activityType['name'], 0, Field::LABEL_MAX_LENGTH),
'sequence' => $i++,
];
}
} else {
// We just check for the field in the custom definitions.
$crmField = $this->copperClient->fields()->find($field->crm_provider_id);
// Import all values.
foreach ($crmField['options'] as $option) {
$values[] = [
'value' => $option['id'],
'label' => mb_strimwidth($option['name'], 0, 191),
'sequence' => $option['rank'],
];
}
}
// Take the existing set of field values.
$fieldsToPurge = $field->values()->get()->pluck('value')->toArray();
foreach ($values as $value) {
// For all current values, upsert the field.
$value['value'] = substr($value['value'] ?? '', 0, 255);
$fieldValues[] = $field->values()->updateOrCreate([
'value' => $value['value'],
], $value);
// Remove this value from the ones we are going to purge.
$key = array_search($value['value'], $fieldsToPurge, false);
if ($key !== false) {
unset($fieldsToPurge[$key]);
}
}
// Delete the old values that are no longer used.
$field->values()->whereIn('value', $fieldsToPurge)->delete();
return $fieldValues;
}
/**
*
* @return FieldValue[]
*/
private function importFieldValuesForDealInsights(Field $field): array
{
$fieldValues = [];
$pipelines = $this->copperClient->pipelines()->all();
foreach ($pipelines as $pipeline) {
foreach ($pipeline['stages'] as $i => $dealStage) {
$fieldValues[] = $field->values()->updateOrCreate(
['value' => $dealStage['id']],
[
'label' => $dealStage['name'],
'sequence' => $i,
]
);
}
}
return $fieldValues;
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
if ($types === null) {
$types = [Stage::TYPE_LEAD, Stage::TYPE_OPPORTUNITY];
}
$missingStage = null;
foreach ($types as $type) {
if ($type === Stage::TYPE_LEAD) {
$statuses = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leadStatuses()->all()
);
if (count($statuses) > 0) {
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => BusinessProcess::TYPE_LEAD,
], [
'team_id' => $this->team->id,
'name' => BusinessProcess::TYPE_LEAD,
'type' => BusinessProcess::TYPE_LEAD,
'is_selectable' => true,
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => BusinessProcess::TYPE_LEAD,
], [
'team_id' => $this->team->id,
'name' => BusinessProcess::TYPE_LEAD,
'is_selectable' => true,
'business_process_id' => $businessProcess->id ?? null,
]);
$leadStatuses = [];
foreach ($statuses as $status) {
// Upsert all statuses for the team.
$status = $this->config->stages()->updateOrCreate([
'crm_provider_id' => $status['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($status['name'], 0, 50),
'label' => mb_strimwidth($status['name'], 0, 191),
'type' => Stage::TYPE_LEAD,
'sequence' => $status['order'],
'is_selectable' => true,
]);
if ($missingStageName && $missingStageName === $status['id']) {
$missingStage = $status;
}
$leadStatuses[] = $status['id'];
}
$businessProcess->stages()->sync($leadStatuses);
}
} else {
// We create a business process to contain the pipeline, and later store all stages against it.
foreach ($this->copperClient->pipelines()->all() as $pipeline) {
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $pipeline['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($pipeline['name'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => true,
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $pipeline['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($pipeline['name'], 0, 150),
'is_selectable' => true,
'business_process_id' => $businessProcess->id ?? null,
]);
$stages = [];
foreach ($pipeline['stages'] as $i => $dealStage) {
// Upsert all stages for the team.
$stage = $this->config->stages()->updateOrCreate([
'crm_provider_id' => $dealStage['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($dealStage['name'], 0, 50),
'label' => mb_strimwidth($dealStage['name'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $i,
'is_selectable' => true,
'probability' => $dealStage['win_probability'],
]);
if ($missingStageName && $missingStageName === $dealStage['id']) {
$missingStage = $stage;
}
$stages[] = $stage['id'];
}
$businessProcess->stages()->sync($stages);
}
}
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int
{
$syncCount = 0;
$cpLeads = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->paginate([
'minimum_modified_date' => $since->timestamp,
'sort_by' => 'date_modified',
])
);
foreach ($cpLeads as $cpLead) {
// Only sync if previously imported.
if ($this->hasLead($cpLead['id']) === false) {
$this->importLead($cpLead);
$syncCount++;
}
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncLead(string $crmId): ?Lead
{
$cpLead = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->find($crmId)
);
if (\count($cpLead) === 0) {
return null;
}
return $this->importLead($cpLead);
}
/**
* @inheritdoc
*/
private function importLead($crmData): ?Lead
{
$countryCode = null;
if (! empty($crmData['address']) && isset($crmData['address']['country'])) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$mobilePhone = $parsedNumber = null;
if (! empty($crmData['phone_numbers'])) {
foreach ($crmData['phone_numbers'] as $phoneNumber) {
if ($phoneNumber['category'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);
} else {
$parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);
}
}
}
$name = $crmData['name'];
if (empty($crmData['company_name'])) {
$company = 'Unknown';
} else {
$company = mb_strimwidth($crmData['company_name'], 0, 191);
}
$domain = null;
if (empty($crmData['websites']) === false) {
$domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);
$domain = StringUtil::resolveDomain($domain);
}
$email = null;
if (empty($crmData['email']) === false) {
$email = mb_strimwidth($crmData['email']['email'], 0, 80);
}
$stage = $this->config
->stages()
->where('crm_provider_id', (string) $crmData['status_id'])
->where('type', Stage::TYPE_LEAD)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_LEAD], $crmData['status_id']);
}
if (! $stage instanceof Stage) {
return null;
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($name, 0, 191),
'company' => $company,
'domain' => $domain,
'title' => $crmData['title'] ? mb_strimwidth($crmData['title'], 0, 128) : null,
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'mobile_phone' => $mobilePhone,
'stage_id' => $stage->id,
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Lead::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'country_code' => $countryCode,
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->leads()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
/**
* @inheritdoc
*/
public function syncAccounts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
$cpAccounts = $this->copperClient->accounts()->paginate([
'minimum_modified_date' => $since->timestamp,
'sort_by' => 'date_modified',
]);
foreach ($cpAccounts as $cpAccount) {
// Only sync if previously imported.
if ($this->hasAccount($cpAccount['id'])) {
$this->importAccount($cpAccount);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncAccount(string $crmId): ?Account
{
$cpAccount = $this->copperClient->accounts()->find($crmId);
if (empty($cpAccount)) {
return null;
}
return $this->importAccount($cpAccount);
}
/**
* @inheritdoc
*/
private function importAccount($crmData): Account
{
$countryCode = null;
if (empty($crmData['address']) === false && $crmData['address']['country']) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$name = $crmData['name'];
$parsedNumber = null;
foreach ($crmData['phone_numbers'] as $phoneNumber) {
$parsedNumber = parsePhoneNumber($countryCode, $phoneNumber['number']);
}
$domain = null;
if (empty($crmData['websites']) === false) {
$domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);
$domain = StringUtil::resolveDomain($domain);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($name, 0, 191),
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Account::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'country_code' => $countryCode,
'domain' => $domain,
'phone' => $parsedNumber['phone'] ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->accounts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
public function syncOpportunities(array $parameters, ?string $strategy = null): int
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->copperClient,
]);
$strategies = $strategyResolver->getStrategies($this->config, $strategy);
$syncCount = 0;
try {
foreach ($strategies as $syncStrategy) {
foreach ($syncStrategy->fetchOpportunities($parameters) as $opportunityData) {
$this->importOpportunity($opportunityData);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
$this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => $exception->getMessage(),
]);
}
return $syncCount;
}
public function syncOpportunity(string $crmId): ?Opportunity
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->copperClient,
]);
$strategy = $strategyResolver->resolve(
$this->config,
OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY
);
$parameters['crm_id'] = $crmId;
$cpOpportunity = $strategy->fetchOpportunities($parameters);
return $this->importOpportunity($cpOpportunity);
}
private function importOpportunity($crmData): ?Opportunity
{
$companyId = (string) $crmData['company_id'];
if (empty($companyId)) {
$this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => 'No company id',
]);
return null;
}
$account = $this->config->accounts()->where('crm_provider_id', $companyId)->first();
if ($account === null) {
$account = $this->syncAccount($companyId);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', (string) $crmData['pipeline_id'])
->first();
if ($businessProcess === null) {
// It is possible for some deals to not be in a pipeline.
$this->logger->warning(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => 'Missing pipeline',
]);
return null;
}
$stage = $businessProcess
->stages()
->where('crm_provider_id', (string) $crmData['pipeline_stage_id'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
$this->logger->info('Stage not found, importing', [
'pipeline_id' => $crmData['pipeline_id'],
'stage_id' => $crmData['pipeline_stage_id'],
]);
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData['pipeline_stage_id']);
}
$recordType = $businessProcess->recordTypes()->first();
$closeDate = null;
$isClosed = $crmData['status'] !== self::OPPORTUNITY_STATUS_OPEN;
if ($crmData['close_date']) {
$closeDate = Carbon::parse($crmData['close_date'])->format('Y-m-d');
}
$data = [
'team_id' => $this->team->getId(),
'account_id' => $account->id,
'user_id' => $profile->user_id ?? null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($crmData['name'], 0, 128),
'value' => $crmData['monetary_value'],
'currency_code' => CurrencyFormatter::formatCode($crmData['monetary_unit']),
'close_date' => $closeDate,
'is_closed' => $isClosed,
'is_won' => $crmData['status'] === 'Won',
'stage_id' => $stage->id,
'record_type_id' => $recordType->id ?? null,
'remotely_created_at' => $crmData['date_created'],
];
/** @var Opportunity $opportunity */
$opportunity = $this->config
->opportunities()
->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data)
;
// import external fields into crm_field_data if present
$dealInsightsFields = $this->getOpportunitySyncableFields();
$this->importOpportunityCrmFieldData($crmData, $dealInsightsFields, $opportunity->id);
return $opportunity;
}
/**
* @param array<string, mixed> $opportunityData
* @param string[] $dealInsightsFields
*/
public function importOpportunityCrmFieldData(
array $opportunityData,
array $dealInsightsFields,
int $opportunityId
): void {
foreach ($dealInsightsFields as $fieldName) {
$field = $this->config->fields()->with('entities')
->where('crm_provider_id', $fieldName)
->where('object_type', Field::OBJECT_OPPORTUNITY)
->first();
if (! $field instanceof Field) {
$this->logger->warning('Field not found', [
'field' => $fieldName,
'opportunity_id' => $opportunityId,
]);
continue;
}
$entity = $field->getEntities()->first();
if (! $entity instanceof LayoutEntity) {
continue;
}
$fieldValue = $this->extractFieldValue($opportunityData, $fieldName);
$normalizedValue = $this->normalizeValue($field->getType(), (string) $fieldValue, true);
$field->data()
->updateOrCreate([
'crm_layout_entity_id' => $entity->id,
'crm_field_id' => $field->id,
'object_type' => 'opportunity',
'object_id' => $opportunityId,
], ['value' => $normalizedValue])
;
}
}
/**
* @inheritdoc
*/
public function syncContacts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
$cpContacts = $this->copperClient->contacts()->paginate([
'minimum_interaction_date' => $since->timestamp,
'sort_by' => 'date_modified',
]);
foreach ($cpContacts as $cpContact) {
// Only sync if previously imported.
if ($this->hasContact($cpContact['id'])) {
$this->importContact($cpContact);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
throw $exception;
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncContact(string $crmId): ?Contact
{
$cpContact = $this->copperClient->contacts()->find($crmId);
if (empty($cpContact)) {
return null;
}
return $this->importContact($cpContact);
}
/**
* @inheritdoc
*/
private function importContact($crmData): Contact
{
$account = null;
if ($crmData['company_id']) {
$account = $this->team
->crm
->accounts()
->where('crm_provider_id', (string) $crmData['company_id'])
->first();
if ($account === null) {
$account = $this->syncAccount($crmData['company_id']);
}
}
$countryCode = null;
if (empty($crmData['address']) === false && $crmData['address']['country']) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$mobilePhone = $parsedNumber = null;
foreach ($crmData['phone_numbers'] as $phoneNumber) {
if ($phoneNumber['category'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);
} else {
$parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);
}
}
$email = null;
if (empty($crmData['emails']) === false) {
$email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'account_id' => $account->id ?? null,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => $crmData['name'],
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'mobile_phone' => $mobilePhone ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'title' => $crmData['title'],
'country_code' => $countryCode,
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Contact::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
private function buildContactPhone(?string $countryCode, ?string $number): ?array
{
if ($number) {
// Trim to our width and attempt to parse it.
$number = mb_strimwidth($number, 0, 25);
$parsedNumber = parsePhoneNumber($countryCode, $number);
} else {
$parsedNumber = [];
}
return $parsedNumber;
}
private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string
{
return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
$organization = $this->copperClient->organisation()->all();
if ($this->config->crm_provider_id !== $organization['id']) {
$this->config->update(['crm_provider_id' => $organization['id']]);
}
}
private function syncCustomFields(): void
{
foreach ($this->getFieldTypes() as $fieldType) {
$currentFields = $this->getFields($fieldType);
foreach ($currentFields as $field) {
/** @var Field $field */
$field = $this->config->fields()->updateOrCreate([
'crm_provider_id' => $field['name'],
'object_type' => $fieldType,
], [
'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),
'type' => $field['type'],
]);
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
}
$this->config->save();
}
protected function getFieldTypes(): array
{
return [
parent::OBJECT_TASK,
parent::OBJECT_LEAD,
parent::OBJECT_ACCOUNT,
parent::OBJECT_CONTACT,
parent::OBJECT_OPPORTUNITY,
];
}
/**
* @inheritdoc
*/
public function syncProfiles(?User $userToSearch = null): ?Profile
{
$profiles = $this->copperClient->users()->all();
foreach ($profiles as $profile) {
$user = $this->userRepository->findByTeamAndEmailAddress($this->team, $profile['email'], onlyActive: true);
// Only import profiles for users we have locally.
if ($user) {
$profile = $user->crmProfile()->updateOrCreate([
'crm_configuration_id' => $this->config->id,
'crm_provider_id' => $profile['id'],
]);
if ($userToSearch && $userToSearch->id === $user->id) {
return $profile;
}
}
}
return null;
}
/**
* @inheritdoc
*/
public function syncProfileFields(): void
{
$fieldTypes = [
'task',
'lead',
'account',
'contact',
'opportunity',
];
foreach ($fieldTypes as $fieldType) {
try {
$currentFields = $this->getFields(ucfirst($fieldType));
$newFields = array_column($currentFields, 'name');
$changedFields = array_merge(
array_diff($this->profile->getFieldsAsArray($fieldType), $newFields),
array_diff($newFields, $this->profile->getFieldsAsArray($fieldType))
);
if (\count($changedFields) > 0) {
$fields = implode(',', $newFields);
$this->logger->debug(
ucfirst($fieldType)
. ' fields changed from '
. $this->profile->{$fieldType . '_fields'}
. ' to: '
. $fields
);
$this->profile->{$fieldType . '_fields'} = $fields;
}
} catch (\Exception $exception) {
$this->logger->error('No access to ' . $fieldType . ' object, skipping...');
continue;
}
}
$this->profile->save();
}
/**
* @inheritdoc
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
$scopeValues = array_map(fn ($scope) => is_string($scope) ? $scope : $scope->value, $scopes);
$cacheKey = sprintf('copper-search-%d-%s-%s-%d-%d', $this->team->id, $name, implode('-', $scopeValues), $count, $offset);
return Cache::remember($cacheKey, 300, function () use ($name, $scopes, $count, $offset) {
// Try local search first
$localResults = $this->searchLocally($name, $scopes, $count, $offset);
// If no local results, fall back to remote API search
if (empty($localResults)) {
return $this->searchRemotely($name, $scopes, $count, $offset);
}
return $localResults;
});
}
/**
* @inheritdoc
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
$contact = null;
$account = null;
if ($crmAccountId) {
$account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();
if ($account === null) {
$account = $this->syncAccount($crmAccountId);
}
}
if ($crmContactId) {
$contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();
if ($contact === null) {
$contact = $this->syncContact($crmContactId);
}
}
if ($contact || $account) {
if ($contact && $account === null) {
$account = $contact->account;
}
if ($account === null) {
return [];
}
$params = [
'company_ids' => [$account->crm_provider_id],
'status_ids' => [0], // The integer values are 0, 1, 2, 3, for "Open", "Won", "Lost", and "Abandoned".
'sort_by' => 'date_modified',
'sort_direction' => 'desc',
];
switch ($this->config->opportunity_assignment_rule) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['sort_by'] = 'date_modified';
$params['sort_direction'] = 'desc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['sort_by'] = 'date_created';
$params['sort_direction'] = 'desc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['sort_by'] = 'date_created';
$params['sort_direction'] = 'asc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['sort_by'] = 'date_modified';
$params['sort_direction'] = 'desc';
$params['status_ids'] = [0, 1, 2, 3];
}
$cpOpportunities = $this->copperClient->opportunities()->search($params);
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
foreach ($cpOpportunities as $cpOpportunity) {
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', (string) $cpOpportunity['pipeline_id'])
->first();
if ($businessProcess === null) {
// Import it.
$businessProcess = $this->importStages(
[Stage::TYPE_OPPORTUNITY],
$cpOpportunity['pipeline_stage_id']
);
}
$stage = $businessProcess
->stages()
->where('crm_provider_id', (string) $cpOpportunity['pipeline_stage_id'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $cpOpportunity['pipeline_stage_id']);
}
$recordType = $businessProcess->recordTypes()->first();
$record = [
'crmId' => $cpOpportunity['id'],
'name' => $cpOpportunity['name'],
'value' => currency_format($cpOpportunity['monetary_value'], $cpOpportunity['monetary_unit']),
'won' => $cpOpportunity['status'] === 'Won',
'stage' => [
'id' => $stage->id_string,
'name' => $stage->name,
],
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
if ($ownerId && isset($cpOpportunity['assignee_id']) && $cpOpportunity['assignee_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
}
if (! empty($ownerData)) {
return $ownerData;
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array
{
$data = $cpTasks = [];
switch ($objectType) {
case 'lead':
$cpTasks = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->relatedTasks($objectId)
);
break;
case 'account':
$cpTasks = $this->copperClient->accounts()->relatedTasks($objectId);
break;
case 'contact':
if ($opportunityId) {
$cpTasks = $this->copperClient->opportunities()->relatedTasks($opportunityId);
} elseif ($objectType === 'contact') {
$cpTasks = $this->copperClient->contacts()->relatedTasks($objectId);
}
break;
}
foreach ($cpTasks as $cpTask) {
// We only get the ID itself returned, so pull out the full object.
try {
$cpTask = $this->copperClient->tasks()->find($cpTask['id']);
} catch (Exception $exception) {
$this->logger->error('[Copper] Error fetching task', [
'resource_id' => $cpTask['id'],
'error' => $exception->getMessage(),
]);
continue;
}
// Only allow open tasks.
if ($cpTask['status'] === 'Open') {
$data[] = [
'crmId' => $cpTask['id'],
'subject' => $cpTask['name'],
'due' => $cpTask['due_date']
? Carbon::createFromTimestamp($cpTask['due_date'])->format('Y-m-d\TH:i:sO')
: null,
'type' => null,
];
}
}
return $data;
}
/**
* Try to find email address in CRM service
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$cpObjectType = 'contact';
$cpObjects = $this->copperClient->contacts()->search([
'emails' => $email,
'sort_by' => 'date_modified',
'sort_direction' => 'desc',
]);
if (empty($cpObjects)) {
$cpObjectType = 'lead';
$cpObjects = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->search([
'emails' => $email,
'sort_by' => 'date_...
|
[{"role":"AXButton","text" [{"role":"AXButton","text":"Project: faVsco.js, menu","depth":5,"bounds":{"left":0.2962101,"top":1.0,"width":0.03856383,"height":-0.019952059},"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":"#12066 on JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.33477393,"top":1.0,"width":0.122340426,"height":-0.019952059},"on_screen":true,"help_text":"Pull request #12066 exists for current branch JY-20725-handle-HS-search-rate-limit, but local branch is out of sync with remote","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.5731383,"top":1.0,"width":0.011303191,"height":-0.019952059},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.5884308,"top":1.0,"width":0.076130316,"height":-0.019952059},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.66456115,"top":1.0,"width":0.011303191,"height":-0.019952059},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.67586434,"top":1.0,"width":0.011303191,"height":-0.019952059},"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.6871675,"top":1.0,"width":0.011303191,"height":-0.019952059},"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.7150931,"top":1.0,"width":0.011303191,"height":-0.019952059},"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.72639626,"top":1.0,"width":0.011303191,"height":-0.019952059},"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.73769945,"top":1.0,"width":0.011303191,"height":-0.019952059},"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":"Analyzing…","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Services\\Crm\\Copper;\n\nuse Carbon\\Carbon;\nuse Exception;\nuse GuzzleHttp\\Exception\\ClientException;\nuse Illuminate\\Support\\Facades\\Cache;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\CopperInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Crm\\LayoutEntity;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Copper\\Api\\Client;\nuse Jiminny\\Services\\Crm\\Copper\\Api\\ClientFactory;\nuse Jiminny\\Services\\Crm\\Copper\\Exception\\RequestFailedException;\nuse Jiminny\\Services\\Crm\\Helpers\\FilterJoinedParticipants;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Services\\Crm\\Copper\\Traits\\SearchesCrmEntities;\nuse Jiminny\\Utils\\CurrencyFormatter;\nuse Jiminny\\Utils\\StringUtil;\n\nclass Service extends BaseService implements\n CopperInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n RemoteEntityManipulationInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n VerifyTaskExistsInterface\n{\n use SearchesCrmEntities;\n private const int NOTE_BODY_MAX_LENGTH = 3000000;\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n private const array STANDARD_OPPORTUNITY_FIELDS = [\n 'monetary_value' => [\n 'label' => 'Value',\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n 'type' => Field::TYPE_CURRENCY,\n ],\n 'pipeline_stage_id' => [\n 'label' => 'Stage',\n 'type' => Field::TYPE_PICKLIST,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n 'close_date' => [\n 'label' => 'Close date',\n 'type' => Field::TYPE_DATE,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n 'win_probability' => [\n 'label' => 'Win probability',\n 'type' => Field::TYPE_NUMBER,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n ];\n private const string UNSUPPORTED_OBJECT_TYPE = 'unsupported';\n private const string OPPORTUNITY_STATUS_OPEN = 'Open';\n private const string OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE = 'Opportunity import failed';\n private const string RESOURCE_UPDATE_FAILED_ERROR_MESSAGE = 'Failed to update resource';\n\n private FieldValueConverter $fieldValueConverter;\n private ClientFactory $clientFactory;\n private ?Client $copperClient = null;\n\n public function __construct(\n ClientFactory $clientFactory,\n FieldValueConverter $fieldValueConverter,\n private readonly UserRepository $userRepository,\n private readonly ProspectPhotoPathService $prospectPhotoPathService,\n private readonly CrmEntityRepository $crmEntityRepository\n ) {\n parent::__construct();\n\n $this->clientFactory = $clientFactory;\n $this->fieldValueConverter = $fieldValueConverter;\n }\n\n public function getDisplayName(): string\n {\n return 'Copper';\n }\n\n /**\n * Get the CRM entity repository (used by SearchesCrmEntities trait)\n */\n protected function getCrmEntityRepository(): CrmEntityRepository\n {\n return $this->crmEntityRepository;\n }\n\n public function getMinimumApiVersion(): string\n {\n return Client::MIN_API_VERSION;\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n $owner = $user->team->owner;\n\n return $owner->getSocialAccount(SocialAccount::PROVIDER_COPPER);\n }\n\n public function setUser(User $user): void\n {\n $this->configureSentryScope($user);\n\n $this->team = $user->getTeam();\n $this->teamService->setTeam($user->getTeam());\n $this->setConfiguration($user->getTeam()->getCrmConfiguration());\n\n // Reset state.\n $this->profile = $user->getProfile();\n\n if (! $this->profile instanceof Profile) {\n // Try to fetch their profile, maybe it was not yet imported?\n $this->profile = $this->getProfile($user);\n }\n }\n\n public function setConfiguration(Configuration $configuration): void\n {\n $this->config = $configuration;\n $this->copperClient = $this->clientFactory->create($configuration);\n\n if ($this->team === null) {\n $this->team = $configuration->getTeam();\n }\n }\n\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);\n }\n\n private function mapObjectType(string $objectType): string\n {\n $objectType = strtolower($objectType);\n\n switch ($objectType) {\n case Field::OBJECT_TASK:\n case Field::OBJECT_OPPORTUNITY:\n case Field::OBJECT_LEAD:\n $mappedType = $objectType;\n\n break;\n case Field::OBJECT_ACCOUNT:\n $mappedType = 'company';\n\n break;\n case Field::OBJECT_CONTACT:\n $mappedType = 'person';\n\n break;\n default:\n $mappedType = self::UNSUPPORTED_OBJECT_TYPE;\n\n break;\n }\n\n return $mappedType;\n }\n\n /**\n * @param string $crmObject The name of the CRM object. i.e. Opportunity or Contact\n */\n protected function getFields(string $crmObject): array\n {\n $mappedObjectType = $this->mapObjectType($crmObject);\n\n if (! $this->isSupportedObjectType($mappedObjectType)) {\n return [];\n }\n\n $customFields = $this->copperClient->fields()->all();\n\n $filteredFields = array_filter(\n $customFields,\n static fn ($field) => in_array($mappedObjectType, $field['available_on'], true)\n );\n\n return array_map(\n fn (array $property) => [\n 'name' => $property['id'],\n 'label' => $property['name'],\n 'type' => $this->convertFieldType($property['data_type']),\n ],\n $filteredFields\n );\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n // Setup the activity field as the default Type.\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'type',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n $fieldFilters = FieldDefinitions::taskFollowupFieldsFilter();\n\n foreach ($fieldFilters as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n public function syncFields(): void\n {\n $this->syncStandardFields();\n $this->syncCustomFields();\n }\n\n public function syncField(Field $field): void\n {\n if ($field->getCrmProviderId() === 'type') {\n /**\n * This field is a special case, it is not a custom field and is not returned by the Copper API.\n *\n * The field is created manually during layout setup.\n *\n * @see getDefaultFields()\n *\n * There is a separate endpoint to get the activity types.\n * @see importPicklistValues()\n */\n return;\n }\n\n if ($field->getCrmProviderId() === 'pipeline_stage_id') {\n // Not a custom type\n return;\n }\n\n $crmField = $this->copperClient->fields()->find($field->getCrmProviderId());\n $field->label = $crmField['name'];\n $field->type = $this->convertFieldType($crmField['data_type']);\n\n $field->save();\n }\n\n /**\n * @param string $fieldType How the data should be input\n */\n private function convertFieldType(string $fieldType): string\n {\n $fieldType = strtolower($fieldType);\n\n switch ($fieldType) {\n case 'dropdown':\n $convertedType = Field::TYPE_PICKLIST;\n\n break;\n case 'string':\n $convertedType = Field::TYPE_TEXT;\n\n break;\n case 'float':\n case 'percentage':\n $convertedType = Field::TYPE_NUMBER;\n\n break;\n case 'text':\n $convertedType = Field::TYPE_TEXTAREA;\n\n break;\n case 'checkbox':\n $convertedType = Field::TYPE_BOOLEAN;\n\n break;\n case Field::TYPE_DATE:\n case Field::TYPE_CURRENCY:\n case Field::TYPE_URL:\n $convertedType = $fieldType;\n\n break;\n default:\n $convertedType = Field::TYPE_UNSUPPORTED;\n\n break;\n }\n\n return $convertedType;\n }\n\n /**\n * @inheritdoc\n */\n public function importPicklistValues(Field $field): array\n {\n $fieldValues = [];\n\n if ($field->object_type === 'opportunity' && $field->crm_provider_id === 'pipeline_stage_id') {\n return $this->importFieldValuesForDealInsights($field);\n }\n\n $values = [];\n\n if ($field->object_type === Field::OBJECT_TASK && $field->crm_provider_id === 'type') {\n $activityTypes = $this->copperClient->activityTypes()->all();\n\n /**\n * We ignore \"system\" activity types, disabled activity types and the \"Note\" activity type.\n */\n $activityTypes = array_filter(\n $activityTypes['user'],\n fn (array $activityType) => ! $activityType['is_disabled'] && $activityType['id'] !== 0\n );\n\n // Import all activity values.\n $i = 0;\n foreach ($activityTypes as $activityType) {\n $values[] = [\n 'value' => $activityType['id'],\n 'label' => mb_strimwidth($activityType['name'], 0, Field::LABEL_MAX_LENGTH),\n 'sequence' => $i++,\n ];\n }\n } else {\n // We just check for the field in the custom definitions.\n $crmField = $this->copperClient->fields()->find($field->crm_provider_id);\n\n // Import all values.\n foreach ($crmField['options'] as $option) {\n $values[] = [\n 'value' => $option['id'],\n 'label' => mb_strimwidth($option['name'], 0, 191),\n 'sequence' => $option['rank'],\n ];\n }\n }\n\n // Take the existing set of field values.\n $fieldsToPurge = $field->values()->get()->pluck('value')->toArray();\n\n foreach ($values as $value) {\n // For all current values, upsert the field.\n $value['value'] = substr($value['value'] ?? '', 0, 255);\n $fieldValues[] = $field->values()->updateOrCreate([\n 'value' => $value['value'],\n ], $value);\n\n // Remove this value from the ones we are going to purge.\n $key = array_search($value['value'], $fieldsToPurge, false);\n if ($key !== false) {\n unset($fieldsToPurge[$key]);\n }\n }\n\n // Delete the old values that are no longer used.\n $field->values()->whereIn('value', $fieldsToPurge)->delete();\n\n return $fieldValues;\n }\n\n /**\n *\n * @return FieldValue[]\n */\n private function importFieldValuesForDealInsights(Field $field): array\n {\n $fieldValues = [];\n $pipelines = $this->copperClient->pipelines()->all();\n\n foreach ($pipelines as $pipeline) {\n foreach ($pipeline['stages'] as $i => $dealStage) {\n $fieldValues[] = $field->values()->updateOrCreate(\n ['value' => $dealStage['id']],\n [\n 'label' => $dealStage['name'],\n 'sequence' => $i,\n ]\n );\n }\n }\n\n return $fieldValues;\n }\n\n /**\n * @inheritdoc\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n if ($types === null) {\n $types = [Stage::TYPE_LEAD, Stage::TYPE_OPPORTUNITY];\n }\n $missingStage = null;\n\n foreach ($types as $type) {\n if ($type === Stage::TYPE_LEAD) {\n $statuses = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leadStatuses()->all()\n );\n\n if (count($statuses) > 0) {\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => BusinessProcess::TYPE_LEAD,\n ], [\n 'team_id' => $this->team->id,\n 'name' => BusinessProcess::TYPE_LEAD,\n 'type' => BusinessProcess::TYPE_LEAD,\n 'is_selectable' => true,\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => BusinessProcess::TYPE_LEAD,\n ], [\n 'team_id' => $this->team->id,\n 'name' => BusinessProcess::TYPE_LEAD,\n 'is_selectable' => true,\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n $leadStatuses = [];\n foreach ($statuses as $status) {\n // Upsert all statuses for the team.\n $status = $this->config->stages()->updateOrCreate([\n 'crm_provider_id' => $status['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($status['name'], 0, 50),\n 'label' => mb_strimwidth($status['name'], 0, 191),\n 'type' => Stage::TYPE_LEAD,\n 'sequence' => $status['order'],\n 'is_selectable' => true,\n ]);\n\n if ($missingStageName && $missingStageName === $status['id']) {\n $missingStage = $status;\n }\n\n $leadStatuses[] = $status['id'];\n }\n\n $businessProcess->stages()->sync($leadStatuses);\n }\n } else {\n // We create a business process to contain the pipeline, and later store all stages against it.\n foreach ($this->copperClient->pipelines()->all() as $pipeline) {\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => $pipeline['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($pipeline['name'], 0, 150),\n 'type' => BusinessProcess::TYPE_OPPORTUNITY,\n 'is_selectable' => true,\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => $pipeline['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($pipeline['name'], 0, 150),\n 'is_selectable' => true,\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n $stages = [];\n\n foreach ($pipeline['stages'] as $i => $dealStage) {\n // Upsert all stages for the team.\n $stage = $this->config->stages()->updateOrCreate([\n 'crm_provider_id' => $dealStage['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($dealStage['name'], 0, 50),\n 'label' => mb_strimwidth($dealStage['name'], 0, 191),\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'sequence' => $i,\n 'is_selectable' => true,\n 'probability' => $dealStage['win_probability'],\n ]);\n\n if ($missingStageName && $missingStageName === $dealStage['id']) {\n $missingStage = $stage;\n }\n\n $stages[] = $stage['id'];\n }\n\n $businessProcess->stages()->sync($stages);\n }\n }\n }\n\n return $missingStage;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int\n {\n $syncCount = 0;\n\n $cpLeads = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->paginate([\n 'minimum_modified_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ])\n );\n\n foreach ($cpLeads as $cpLead) {\n // Only sync if previously imported.\n if ($this->hasLead($cpLead['id']) === false) {\n $this->importLead($cpLead);\n $syncCount++;\n }\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLead(string $crmId): ?Lead\n {\n $cpLead = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->find($crmId)\n );\n\n if (\\count($cpLead) === 0) {\n return null;\n }\n\n return $this->importLead($cpLead);\n }\n\n /**\n * @inheritdoc\n */\n private function importLead($crmData): ?Lead\n {\n $countryCode = null;\n if (! empty($crmData['address']) && isset($crmData['address']['country'])) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $mobilePhone = $parsedNumber = null;\n if (! empty($crmData['phone_numbers'])) {\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n if ($phoneNumber['category'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);\n } else {\n $parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);\n }\n }\n }\n\n $name = $crmData['name'];\n\n if (empty($crmData['company_name'])) {\n $company = 'Unknown';\n } else {\n $company = mb_strimwidth($crmData['company_name'], 0, 191);\n }\n\n $domain = null;\n if (empty($crmData['websites']) === false) {\n $domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);\n $domain = StringUtil::resolveDomain($domain);\n }\n\n $email = null;\n if (empty($crmData['email']) === false) {\n $email = mb_strimwidth($crmData['email']['email'], 0, 80);\n }\n\n $stage = $this->config\n ->stages()\n ->where('crm_provider_id', (string) $crmData['status_id'])\n ->where('type', Stage::TYPE_LEAD)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_LEAD], $crmData['status_id']);\n }\n\n if (! $stage instanceof Stage) {\n return null;\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($name, 0, 191),\n 'company' => $company,\n 'domain' => $domain,\n 'title' => $crmData['title'] ? mb_strimwidth($crmData['title'], 0, 128) : null,\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'mobile_phone' => $mobilePhone,\n 'stage_id' => $stage->id,\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Lead::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'country_code' => $countryCode,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->leads()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n /**\n * @inheritdoc\n */\n public function syncAccounts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n $cpAccounts = $this->copperClient->accounts()->paginate([\n 'minimum_modified_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ]);\n\n foreach ($cpAccounts as $cpAccount) {\n // Only sync if previously imported.\n if ($this->hasAccount($cpAccount['id'])) {\n $this->importAccount($cpAccount);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncAccount(string $crmId): ?Account\n {\n $cpAccount = $this->copperClient->accounts()->find($crmId);\n\n if (empty($cpAccount)) {\n return null;\n }\n\n return $this->importAccount($cpAccount);\n }\n\n /**\n * @inheritdoc\n */\n private function importAccount($crmData): Account\n {\n $countryCode = null;\n if (empty($crmData['address']) === false && $crmData['address']['country']) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $name = $crmData['name'];\n\n $parsedNumber = null;\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n $parsedNumber = parsePhoneNumber($countryCode, $phoneNumber['number']);\n }\n\n $domain = null;\n if (empty($crmData['websites']) === false) {\n $domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);\n $domain = StringUtil::resolveDomain($domain);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($name, 0, 191),\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Account::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'country_code' => $countryCode,\n 'domain' => $domain,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->accounts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n public function syncOpportunities(array $parameters, ?string $strategy = null): int\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->copperClient,\n ]);\n $strategies = $strategyResolver->getStrategies($this->config, $strategy);\n\n $syncCount = 0;\n\n try {\n foreach ($strategies as $syncStrategy) {\n foreach ($syncStrategy->fetchOpportunities($parameters) as $opportunityData) {\n $this->importOpportunity($opportunityData);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n $this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => $exception->getMessage(),\n ]);\n }\n\n return $syncCount;\n }\n\n public function syncOpportunity(string $crmId): ?Opportunity\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->copperClient,\n ]);\n $strategy = $strategyResolver->resolve(\n $this->config,\n OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY\n );\n\n $parameters['crm_id'] = $crmId;\n\n $cpOpportunity = $strategy->fetchOpportunities($parameters);\n\n return $this->importOpportunity($cpOpportunity);\n }\n\n private function importOpportunity($crmData): ?Opportunity\n {\n $companyId = (string) $crmData['company_id'];\n\n if (empty($companyId)) {\n $this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => 'No company id',\n ]);\n\n return null;\n }\n\n $account = $this->config->accounts()->where('crm_provider_id', $companyId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($companyId);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', (string) $crmData['pipeline_id'])\n ->first();\n\n if ($businessProcess === null) {\n // It is possible for some deals to not be in a pipeline.\n $this->logger->warning(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => 'Missing pipeline',\n ]);\n\n return null;\n }\n\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', (string) $crmData['pipeline_stage_id'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n $this->logger->info('Stage not found, importing', [\n 'pipeline_id' => $crmData['pipeline_id'],\n 'stage_id' => $crmData['pipeline_stage_id'],\n ]);\n\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData['pipeline_stage_id']);\n }\n\n $recordType = $businessProcess->recordTypes()->first();\n $closeDate = null;\n $isClosed = $crmData['status'] !== self::OPPORTUNITY_STATUS_OPEN;\n\n if ($crmData['close_date']) {\n $closeDate = Carbon::parse($crmData['close_date'])->format('Y-m-d');\n }\n\n $data = [\n 'team_id' => $this->team->getId(),\n 'account_id' => $account->id,\n 'user_id' => $profile->user_id ?? null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($crmData['name'], 0, 128),\n 'value' => $crmData['monetary_value'],\n 'currency_code' => CurrencyFormatter::formatCode($crmData['monetary_unit']),\n 'close_date' => $closeDate,\n 'is_closed' => $isClosed,\n 'is_won' => $crmData['status'] === 'Won',\n 'stage_id' => $stage->id,\n 'record_type_id' => $recordType->id ?? null,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n /** @var Opportunity $opportunity */\n $opportunity = $this->config\n ->opportunities()\n ->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data)\n ;\n\n // import external fields into crm_field_data if present\n $dealInsightsFields = $this->getOpportunitySyncableFields();\n $this->importOpportunityCrmFieldData($crmData, $dealInsightsFields, $opportunity->id);\n\n return $opportunity;\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n * @param string[] $dealInsightsFields\n */\n public function importOpportunityCrmFieldData(\n array $opportunityData,\n array $dealInsightsFields,\n int $opportunityId\n ): void {\n foreach ($dealInsightsFields as $fieldName) {\n $field = $this->config->fields()->with('entities')\n ->where('crm_provider_id', $fieldName)\n ->where('object_type', Field::OBJECT_OPPORTUNITY)\n ->first();\n\n if (! $field instanceof Field) {\n $this->logger->warning('Field not found', [\n 'field' => $fieldName,\n 'opportunity_id' => $opportunityId,\n ]);\n\n continue;\n }\n\n $entity = $field->getEntities()->first();\n\n if (! $entity instanceof LayoutEntity) {\n continue;\n }\n\n $fieldValue = $this->extractFieldValue($opportunityData, $fieldName);\n $normalizedValue = $this->normalizeValue($field->getType(), (string) $fieldValue, true);\n\n $field->data()\n ->updateOrCreate([\n 'crm_layout_entity_id' => $entity->id,\n 'crm_field_id' => $field->id,\n 'object_type' => 'opportunity',\n 'object_id' => $opportunityId,\n ], ['value' => $normalizedValue])\n ;\n }\n }\n\n /**\n * @inheritdoc\n */\n public function syncContacts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n $cpContacts = $this->copperClient->contacts()->paginate([\n 'minimum_interaction_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ]);\n\n foreach ($cpContacts as $cpContact) {\n // Only sync if previously imported.\n if ($this->hasContact($cpContact['id'])) {\n $this->importContact($cpContact);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n throw $exception;\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncContact(string $crmId): ?Contact\n {\n $cpContact = $this->copperClient->contacts()->find($crmId);\n\n if (empty($cpContact)) {\n return null;\n }\n\n return $this->importContact($cpContact);\n }\n\n /**\n * @inheritdoc\n */\n private function importContact($crmData): Contact\n {\n $account = null;\n if ($crmData['company_id']) {\n $account = $this->team\n ->crm\n ->accounts()\n ->where('crm_provider_id', (string) $crmData['company_id'])\n ->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmData['company_id']);\n }\n }\n\n $countryCode = null;\n if (empty($crmData['address']) === false && $crmData['address']['country']) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $mobilePhone = $parsedNumber = null;\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n if ($phoneNumber['category'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);\n } else {\n $parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);\n }\n }\n\n $email = null;\n if (empty($crmData['emails']) === false) {\n $email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'account_id' => $account->id ?? null,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => $crmData['name'],\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'mobile_phone' => $mobilePhone ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'title' => $crmData['title'],\n 'country_code' => $countryCode,\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Contact::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n private function buildContactPhone(?string $countryCode, ?string $number): ?array\n {\n if ($number) {\n // Trim to our width and attempt to parse it.\n $number = mb_strimwidth($number, 0, 25);\n $parsedNumber = parsePhoneNumber($countryCode, $number);\n } else {\n $parsedNumber = [];\n }\n\n return $parsedNumber;\n }\n\n private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string\n {\n return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;\n }\n\n /**\n * @inheritdoc\n */\n public function syncOrganization(): void\n {\n $organization = $this->copperClient->organisation()->all();\n\n if ($this->config->crm_provider_id !== $organization['id']) {\n $this->config->update(['crm_provider_id' => $organization['id']]);\n }\n }\n\n private function syncCustomFields(): void\n {\n foreach ($this->getFieldTypes() as $fieldType) {\n $currentFields = $this->getFields($fieldType);\n\n foreach ($currentFields as $field) {\n /** @var Field $field */\n $field = $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => $field['name'],\n 'object_type' => $fieldType,\n ], [\n 'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),\n 'type' => $field['type'],\n ]);\n\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n }\n\n $this->config->save();\n }\n\n protected function getFieldTypes(): array\n {\n return [\n parent::OBJECT_TASK,\n parent::OBJECT_LEAD,\n parent::OBJECT_ACCOUNT,\n parent::OBJECT_CONTACT,\n parent::OBJECT_OPPORTUNITY,\n ];\n }\n\n /**\n * @inheritdoc\n */\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n $profiles = $this->copperClient->users()->all();\n\n foreach ($profiles as $profile) {\n $user = $this->userRepository->findByTeamAndEmailAddress($this->team, $profile['email'], onlyActive: true);\n\n // Only import profiles for users we have locally.\n if ($user) {\n $profile = $user->crmProfile()->updateOrCreate([\n 'crm_configuration_id' => $this->config->id,\n 'crm_provider_id' => $profile['id'],\n ]);\n\n if ($userToSearch && $userToSearch->id === $user->id) {\n return $profile;\n }\n }\n }\n\n return null;\n }\n\n /**\n * @inheritdoc\n */\n public function syncProfileFields(): void\n {\n $fieldTypes = [\n 'task',\n 'lead',\n 'account',\n 'contact',\n 'opportunity',\n ];\n\n foreach ($fieldTypes as $fieldType) {\n try {\n $currentFields = $this->getFields(ucfirst($fieldType));\n\n $newFields = array_column($currentFields, 'name');\n $changedFields = array_merge(\n array_diff($this->profile->getFieldsAsArray($fieldType), $newFields),\n array_diff($newFields, $this->profile->getFieldsAsArray($fieldType))\n );\n\n if (\\count($changedFields) > 0) {\n $fields = implode(',', $newFields);\n $this->logger->debug(\n ucfirst($fieldType)\n . ' fields changed from '\n . $this->profile->{$fieldType . '_fields'}\n . ' to: '\n . $fields\n );\n\n $this->profile->{$fieldType . '_fields'} = $fields;\n }\n } catch (\\Exception $exception) {\n $this->logger->error('No access to ' . $fieldType . ' object, skipping...');\n\n continue;\n }\n }\n\n $this->profile->save();\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n $scopeValues = array_map(fn ($scope) => is_string($scope) ? $scope : $scope->value, $scopes);\n $cacheKey = sprintf('copper-search-%d-%s-%s-%d-%d', $this->team->id, $name, implode('-', $scopeValues), $count, $offset);\n\n return Cache::remember($cacheKey, 300, function () use ($name, $scopes, $count, $offset) {\n // Try local search first\n $localResults = $this->searchLocally($name, $scopes, $count, $offset);\n\n // If no local results, fall back to remote API search\n if (empty($localResults)) {\n return $this->searchRemotely($name, $scopes, $count, $offset);\n }\n\n return $localResults;\n });\n }\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n $contact = null;\n $account = null;\n\n if ($crmAccountId) {\n $account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmAccountId);\n }\n }\n\n if ($crmContactId) {\n $contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();\n\n if ($contact === null) {\n $contact = $this->syncContact($crmContactId);\n }\n }\n\n if ($contact || $account) {\n if ($contact && $account === null) {\n $account = $contact->account;\n }\n\n if ($account === null) {\n return [];\n }\n\n $params = [\n 'company_ids' => [$account->crm_provider_id],\n 'status_ids' => [0], // The integer values are 0, 1, 2, 3, for \"Open\", \"Won\", \"Lost\", and \"Abandoned\".\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ];\n\n switch ($this->config->opportunity_assignment_rule) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['sort_by'] = 'date_modified';\n $params['sort_direction'] = 'desc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['sort_by'] = 'date_created';\n $params['sort_direction'] = 'desc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['sort_by'] = 'date_created';\n $params['sort_direction'] = 'asc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['sort_by'] = 'date_modified';\n $params['sort_direction'] = 'desc';\n $params['status_ids'] = [0, 1, 2, 3];\n }\n\n $cpOpportunities = $this->copperClient->opportunities()->search($params);\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n foreach ($cpOpportunities as $cpOpportunity) {\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', (string) $cpOpportunity['pipeline_id'])\n ->first();\n\n if ($businessProcess === null) {\n // Import it.\n $businessProcess = $this->importStages(\n [Stage::TYPE_OPPORTUNITY],\n $cpOpportunity['pipeline_stage_id']\n );\n }\n\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', (string) $cpOpportunity['pipeline_stage_id'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $cpOpportunity['pipeline_stage_id']);\n }\n\n $recordType = $businessProcess->recordTypes()->first();\n\n $record = [\n 'crmId' => $cpOpportunity['id'],\n 'name' => $cpOpportunity['name'],\n 'value' => currency_format($cpOpportunity['monetary_value'], $cpOpportunity['monetary_unit']),\n 'won' => $cpOpportunity['status'] === 'Won',\n 'stage' => [\n 'id' => $stage->id_string,\n 'name' => $stage->name,\n ],\n 'recordType' => [\n 'id' => $recordType->id_string,\n 'name' => $recordType->name,\n ],\n ];\n\n if ($ownerId && isset($cpOpportunity['assignee_id']) && $cpOpportunity['assignee_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = $cpTasks = [];\n\n switch ($objectType) {\n case 'lead':\n $cpTasks = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->relatedTasks($objectId)\n );\n\n break;\n\n case 'account':\n $cpTasks = $this->copperClient->accounts()->relatedTasks($objectId);\n\n break;\n case 'contact':\n if ($opportunityId) {\n $cpTasks = $this->copperClient->opportunities()->relatedTasks($opportunityId);\n } elseif ($objectType === 'contact') {\n $cpTasks = $this->copperClient->contacts()->relatedTasks($objectId);\n }\n\n break;\n }\n\n foreach ($cpTasks as $cpTask) {\n // We only get the ID itself returned, so pull out the full object.\n try {\n $cpTask = $this->copperClient->tasks()->find($cpTask['id']);\n } catch (Exception $exception) {\n $this->logger->error('[Copper] Error fetching task', [\n 'resource_id' => $cpTask['id'],\n 'error' => $exception->getMessage(),\n ]);\n\n continue;\n }\n\n // Only allow open tasks.\n if ($cpTask['status'] === 'Open') {\n $data[] = [\n 'crmId' => $cpTask['id'],\n 'subject' => $cpTask['name'],\n 'due' => $cpTask['due_date']\n ? Carbon::createFromTimestamp($cpTask['due_date'])->format('Y-m-d\\TH:i:sO')\n : null,\n 'type' => null,\n ];\n }\n }\n\n return $data;\n }\n\n /**\n * Try to find email address in CRM service\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $cpObjectType = 'contact';\n\n $cpObjects = $this->copperClient->contacts()->search([\n 'emails' => $email,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (empty($cpObjects)) {\n $cpObjectType = 'lead';\n $cpObjects = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'emails' => $email,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (empty($cpObjects)) {\n return null;\n }\n\n // Search returns an array of results, but we only want the first\n $cpObject = reset($cpObjects);\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n // Check if the user is internal.\n $teamMember = $this->team->users()->where('phone', $phone)->exists();\n\n // Skip the attendee if internal.\n if ($teamMember === false) {\n $cpObjectType = 'contact';\n $cpObject = $this->copperClient->contacts()->search([\n 'phone_number' => $phone,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (\\count($cpObject) === 0) {\n $cpObjectType = 'lead';\n $cpObject = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'phone_number' => $phone,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (empty($cpObject)) {\n return null;\n }\n\n $cpObject = reset($cpObject);\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n return null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $result = \\Cache::remember($this->team->id . $name, 60, function () use ($name, $userId) {\n $cpObjectType = 'contact';\n $cpObject = $this->copperClient->contacts()->search([\n 'name' => $name,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (\\count($cpObject) === 0) {\n $cpObjectType = 'lead';\n $cpObject = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'name' => $name,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (! empty($cpObject)) {\n $cpObject = reset($cpObject);\n }\n\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : false;\n });\n\n return is_array($result) ? $result : null;\n }\n\n private function convertCrmData(array $object, string $objectType, ?int $userId = null): array\n {\n $lead = null;\n $contact = null;\n $opportunity = null;\n $account = null;\n $stage = null;\n $countryCode = null;\n\n if ($objectType === 'lead') {\n $lead = $this->importLead($object);\n\n // Lead might not be imported if the Stage is null for example.\n if ($lead) {\n $countryCode = $lead->country_code;\n $stage = $lead->stage;\n }\n } else {\n $contact = $this->importContact($object);\n $account = $contact->account;\n\n if ($contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account) {\n $countryCode = $account->country_code;\n }\n\n try {\n $cpOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId,\n );\n\n if (! empty($cpOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($cpOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (\\Exception $e) {\n // Nothing to see here.\n }\n }\n\n return [\n $lead,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n public function saveActivity(Activity $activity): Activity\n {\n switch ($activity->type) {\n case Activity::TYPE_CONFERENCE:\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n $activity = $this->buildCallPayload($activity);\n\n break;\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $activity = $this->buildTextMessagePayload($activity);\n\n break;\n }\n\n return $activity;\n }\n\n private function convertActivityAssociations(Activity $activity): array\n {\n if ($activity->lead) {\n $type = 'lead';\n $id = $activity->lead->crm_provider_id;\n } elseif ($activity->contact) {\n $type = 'person';\n $id = $activity->contact->crm_provider_id;\n } elseif ($activity->opportunity) {\n $type = 'opportunity';\n $id = $activity->opportunity->crm_provider_id;\n } else {\n $type = 'company';\n $id = $activity->account->crm_provider_id;\n }\n\n return [\n 'type' => $type,\n 'id' => $id,\n ];\n }\n\n private function convertActivityType(PlaybookCategory $activityType): array\n {\n return [\n 'category' => 'user',\n 'id' => $this->getCrmType($activityType)->value,\n ];\n }\n\n /**\n * @throws CrmException\n */\n private function buildCallPayload(Activity $activity): Activity\n {\n try {\n if ($activity->crm_provider_id) {\n // The activity should be logged under the existing Task (not Activity).\n $newActivityType = $this->getCrmType($activity->category);\n if ($newActivityType === null) {\n $message = sprintf('[Copper] invalid CRM Custom Activity Type: %s', $activity->category);\n\n throw new CrmException($message, 400);\n }\n $this->copperClient->tasks()->update($activity->crm_provider_id, [\n 'status' => 'Completed',\n 'custom_activity_type_id' => $newActivityType->value,\n 'details' => $this->generateActivityDescription($activity),\n ]);\n } else {\n if ($this->getCrmType($activity->category) === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n if ($this->getCrmType($activity->category)->value === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n // Just create an activity.\n $cpActivity = $this->copperClient->activities()->create([\n 'user_id' => $this->profile->crm_provider_id,\n 'activity_date' => $activity->scheduled_start_time->timestamp,\n 'parent' => $this->convertActivityAssociations($activity),\n 'type' => $this->convertActivityType($activity->category),\n 'details' => $this->generateActivityDescription($activity),\n ]);\n\n $activity->crm_provider_id = $cpActivity['id'];\n $activity->save();\n }\n } catch (ClientException $exception) {\n //Log all errors to Sentry\n \\Sentry::captureException($exception);\n\n $response = $exception->getResponse();\n\n $responseBody = $response->getBody();\n $message = $responseBody;\n $errorCode = $response->getStatusCode();\n\n $jsonResponse = json_decode($responseBody, true);\n if (isset($jsonResponse[0]['message'])) {\n $message = $jsonResponse[0]['message'];\n }\n\n throw new CrmException($message, $errorCode);\n }\n\n return $activity;\n }\n\n private function buildTextMessagePayload(Activity $activity): Activity\n {\n if ($this->getCrmType($activity->category) === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n if ($this->getCrmType($activity->category)->value === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n $cpActivity = $this->copperClient->activities()->create([\n 'user_id' => $this->profile->crm_provider_id,\n 'activity_date' => $activity->created_at->timestamp,\n 'parent' => $this->convertActivityAssociations($activity),\n 'type' => $this->convertActivityType($activity->category),\n 'details' => $this->generateActivityDescription($activity),\n ]);\n\n $activity->crm_provider_id = $cpActivity['id'];\n $activity->save();\n\n return $activity;\n }\n\n private function generateActivityDescription(Activity $activity): string\n {\n $description = '';\n\n switch ($activity->type) {\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n case Activity::TYPE_CONFERENCE:\n\n $description = 'Jiminny Call Summary' . PHP_EOL . PHP_EOL;\n $description .= 'Call Duration: ' . $activity->duration_for_humans . PHP_EOL . PHP_EOL;\n\n // Tell them which number was dialed.\n if ($activity->to) {\n $description .= 'Dialed: ' . $activity->to->phone_number . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->hasReasonCodeBotKicked()) {\n $description .= 'Notetaker removed from this meeting' . PHP_EOL . PHP_EOL;\n // When we fix the state to be Activity::RECORDING_RECORDED as it should be this can change.\n } elseif ($activity->hasReasonCodeNotCompliant()) {\n $description .= 'Notetaker did not join due to recording consent not being provided by attendees' . PHP_EOL . PHP_EOL;\n } elseif ($activity->canReviewActivity()) {\n $playbackUrl = $activity->user->team->partner->getPlaybackUrl($activity);\n $description .= 'Review Activity:' . PHP_EOL . $playbackUrl . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->getCrmType() === Activity::TYPE_CONFERENCE) {\n $description .= 'Attendees:'\n . PHP_EOL\n . (new FilterJoinedParticipants())->toString($activity);\n }\n\n if (\\count($activity->notes) > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Notes: ' . PHP_EOL;\n\n foreach ($activity->notes as $note) {\n $nTime = (int) ceil($note->time);\n $time = ($nTime > 3600) ? gmdate('H:i:s', $nTime) : gmdate('i:s', $nTime);\n $description .= $time . ' ' . $note->note . PHP_EOL;\n }\n }\n\n // Get all private messages.\n $messages = $activity->messages()\n ->where('is_private', 1)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Coaching Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n // Get all public messages.\n $messages = $activity->messages()\n ->where('is_private', 0)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Customer Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n if ($activity->summary) {\n $description .= PHP_EOL . PHP_EOL . 'Summary: ' . PHP_EOL . $activity->summary;\n }\n\n break;\n\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $description = $activity->description;\n\n break;\n }\n\n return $description;\n }\n\n public function saveFollowupActivity(Activity $activity, array $fields): ?string\n {\n // This is the user provided activity subject field.\n if (empty($fields['type'])) {\n return null;\n }\n\n $reminder = null;\n if (empty($fields['reminder_date']) === false) {\n $formatReminder = Carbon::createFromFormat('Y-m-d\\TH:i:s\\Z', $fields['reminder_date']);\n $reminder = $formatReminder->getTimestamp();\n }\n\n $due = null;\n if (empty($fields['due_date']) === false) {\n $formatDue = Carbon::createFromFormat('Y-m-d\\TH:i:s\\Z', $fields['due_date']);\n $due = $formatDue->getTimestamp();\n }\n\n $data = [\n 'custom_activity_type_id' => $fields['type'],\n 'status' => 'Open',\n 'assignee_id' => $this->profile->crm_provider_id,\n 'due_date' => $due,\n 'details' => $fields['details'] ?? '',\n 'reminder_date' => $reminder,\n 'name' => $fields['name'] ?? 'Follow-up',\n 'related_resource' => $this->convertActivityAssociations($activity),\n 'custom_fields' => $this->fetchCustomFieldData($activity, Field::OBJECT_TASK),\n ];\n\n // We don't actually create a corresponding activity object on our side yet.\n return $this->copperClient->tasks()->create($data)['id'];\n }\n\n /**\n * Store transcripts as note.\n *\n * @throws \\Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, static::NOTE_BODY_MAX_LENGTH);\n\n $data = [\n 'user_id' => $this->profile->crm_provider_id,\n 'type' => [\n 'category' => 'user',\n 'id' => 0, // This creates a note.\n ],\n 'activity_date' => time(),\n 'details' => $transcripts,\n 'parent' => $this->convertActivityAssociations($activity),\n ];\n\n $cpActivity = $this->copperClient->activities()->create($data);\n\n // Store CRM Activity ID in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $cpActivity['id'];\n $transcription->save();\n }\n\n /**\n * @inheritdoc\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n if ($crmObject instanceof Lead) {\n $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->update($crmObject->crm_provider_id, [\n 'status_id' => $stage->crm_provider_id,\n ])\n );\n } else {\n $this->copperClient->opportunities()->update($crmObject->crm_provider_id, [\n 'pipeline_stage_id' => $stage->crm_provider_id,\n ]);\n }\n }\n\n public function prepareValueForUpdate(array $params): array\n {\n return [$params['fieldName'] => $params['fieldValue']];\n }\n\n /*\n * @inheritdoc\n */\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $preparedData = $data;\n\n if ($objectType === Field::OBJECT_OPPORTUNITY) {\n $preparedData = $this->prepareOpportunityFieldsForUpdate($data);\n }\n\n try {\n $this->copperClient\n ->createResourceFromObjectType($objectType)\n ->update($objectId, $preparedData)\n ;\n } catch (Exception $e) {\n $this->logger->error(self::RESOURCE_UPDATE_FAILED_ERROR_MESSAGE, [\n 'resource_id' => $objectId,\n 'data' => $preparedData,\n 'error' => $e->getMessage(),\n ]);\n\n throw new CrmException(self::RESOURCE_UPDATE_FAILED_ERROR_MESSAGE, $e->getCode(), $e);\n }\n }\n\n /**\n * @param array<string,string> $fieldData\n *\n * @throws CrmException\n *\n * @return array<string,array<int,array<string,bool|float|int|string|null>>|bool|float|int|string|null>\n */\n private function prepareOpportunityFieldsForUpdate(array $fieldData): array\n {\n $preparedData = [];\n $customFields = [];\n\n foreach ($fieldData as $fieldName => $fieldValue) {\n $field = $this->config\n ->fields()\n ->where('crm_provider_id', $fieldName)\n ->first();\n\n if (! $field instanceof Field) {\n throw new CrmException('Field not found');\n }\n\n $convertedValue = $this->fieldValueConverter->convertToCrm($field->getType(), $fieldValue);\n\n if ($this->isStandardField($fieldName)) {\n $preparedData[$fieldName] = $convertedValue;\n\n continue;\n }\n\n $customFields[] = [\n 'custom_field_definition_id' => $fieldName,\n 'value' => $convertedValue,\n ];\n }\n\n if (! empty($customFields)) {\n $preparedData['custom_fields'] = $customFields;\n }\n\n return $preparedData;\n }\n\n /*\n * @inheritdoc\n */\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n return $this->copperClient->createResourceFromObjectType($objectType)->find($objectId);\n }\n\n private function fetchCustomFieldData(Activity $activity, string $objectType): array\n {\n $payload = [];\n\n $fieldData = FieldData::where([\n 'object_id' => $activity->id,\n ])->whereHas('field', function ($query) use ($objectType) {\n $query->where('object_type', $objectType);\n })->get();\n\n foreach ($fieldData as $data) {\n // Add the field and value to the payload.\n $payload += [\n 'custom_field_definition_id' => $data->field->crm_provider_id,\n 'value' => $data->value,\n ];\n }\n\n return $payload;\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $baseUrl = 'https://app.prosperworks.com/companies/' . $this->config->crm_provider_id . '/app#/';\n switch ($objectType) {\n case 'lead':\n $url = $baseUrl . 'leads/' . $providerId;\n\n break;\n\n case 'account':\n $url = $baseUrl . 'organization/' . $providerId;\n\n break;\n\n case 'contact':\n $url = $baseUrl . 'contact/' . $providerId;\n\n break;\n\n case 'opportunity':\n $url = $baseUrl . 'deal/' . $providerId;\n\n break;\n\n default:\n case 'task':\n case 'activity':\n // Sadly we can't deeplink to these in Copper UI.\n $url = null;\n }\n\n return $url;\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! ($this->config->store_transcript)) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n return $this->transcriptionService\n ->findTranscriptionByActivity($activity)\n ->map(static function (array $transcriptionSegment): string {\n return $transcriptionSegment['formattedStartsAt'] . ' | ' . $transcriptionSegment['transcript'];\n })\n ->implode(PHP_EOL);\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n *\n * @return int|string|bool|float|null\n */\n private function extractFieldValue(array $opportunityData, string $fieldName)\n {\n $fieldValue = $this->isStandardField($fieldName)\n ? $opportunityData[$fieldName]\n : $this->resolveCustomFieldFromOpportunityData($opportunityData, $fieldName);\n\n if (is_array($fieldValue)) {\n $fieldValue = implode(', ', $fieldValue);\n }\n\n return $fieldValue;\n }\n\n private function isStandardField(string $fieldName): bool\n {\n return array_key_exists($fieldName, self::STANDARD_OPPORTUNITY_FIELDS);\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n *\n * @return string|int|float|bool|null|array<string, mixed>\n */\n private function resolveCustomFieldFromOpportunityData(array $opportunityData, string $fieldName)\n {\n $fieldData = array_filter(\n $opportunityData['custom_fields'],\n static fn ($field) => (string) $field['custom_field_definition_id'] === $fieldName\n );\n\n return array_pop($fieldData)['value'] ?? '';\n }\n\n private function isSupportedObjectType(string $objectType): bool\n {\n return $objectType !== self::UNSUPPORTED_OBJECT_TYPE;\n }\n\n private function syncStandardFields(): void\n {\n foreach (self::STANDARD_OPPORTUNITY_FIELDS as $fieldId => $fieldData) {\n $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => mb_strimwidth($fieldId, 0, 128),\n 'object_type' => Field::OBJECT_OPPORTUNITY,\n ], [\n 'label' => mb_strimwidth($fieldData['label'], 0, Field::LABEL_MAX_LENGTH),\n 'type' => $fieldData['type'],\n ]);\n }\n\n $this->importStages([Stage::TYPE_OPPORTUNITY]);\n }\n\n private function requestWithExceptionHandling(\\Closure $apiRequest): iterable\n {\n try {\n return $apiRequest();\n } catch (\\Exception $exception) {\n if ($exception->getCode() === 403) {\n // Object might not be supported\n return [];\n }\n\n \\Sentry::captureException($exception);\n\n return [];\n }\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n if ($this->copperClient === null) {\n return false;\n }\n\n $task = $this->copperClient->tasks()->find($crmProviderId);\n\n return ! empty($task);\n } catch (HttpNotFoundException) {\n // Task not found in CRM - this is expected and permanent\n $this->logger->info('[Copper] Task not found during verification', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n } catch (RequestFailedException $e) {\n // Handle 404 responses from Copper API\n if ($e->getCode() === 404) {\n $this->logger->info('[Copper] Task not found during verification (404)', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n\n // Re-throw other Copper exceptions for retry\n throw $e;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\n });\n }\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Services\\Crm\\Copper;\n\nuse Carbon\\Carbon;\nuse Exception;\nuse GuzzleHttp\\Exception\\ClientException;\nuse Illuminate\\Support\\Facades\\Cache;\nuse Jiminny\\Contracts\\Services\\Crm\\LayoutManagementInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\MatchCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\Provider\\CopperInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityLookupInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\RemoteEntityManipulationInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SettingsInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmEntitiesInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\SyncCrmMetadataInterface;\nuse Jiminny\\Contracts\\Services\\Crm\\VerifyTaskExistsInterface;\nuse Jiminny\\Exceptions\\CrmException;\nuse Jiminny\\Exceptions\\HttpNotFoundException;\nuse Jiminny\\Models\\Account;\nuse Jiminny\\Models\\Activity;\nuse Jiminny\\Models\\Contact;\nuse Jiminny\\Models\\Crm\\BusinessProcess;\nuse Jiminny\\Models\\Crm\\Configuration;\nuse Jiminny\\Models\\Crm\\Field;\nuse Jiminny\\Models\\Crm\\FieldData;\nuse Jiminny\\Models\\Crm\\FieldValue;\nuse Jiminny\\Models\\Crm\\LayoutEntity;\nuse Jiminny\\Models\\Crm\\Profile;\nuse Jiminny\\Models\\Lead;\nuse Jiminny\\Models\\Opportunity;\nuse Jiminny\\Models\\Playbook;\nuse Jiminny\\Models\\PlaybookCategory;\nuse Jiminny\\Models\\SocialAccount;\nuse Jiminny\\Models\\Stage;\nuse Jiminny\\Models\\User;\nuse Jiminny\\Repositories\\Crm\\CrmEntityRepository;\nuse Jiminny\\Repositories\\Crm\\FieldRepository;\nuse Jiminny\\Repositories\\Crm\\ProfileRepository;\nuse Jiminny\\Repositories\\UserRepository;\nuse Jiminny\\Services\\Avatar\\ProspectPhotoPathService;\nuse Jiminny\\Services\\Crm\\BaseService;\nuse Jiminny\\Services\\Crm\\Copper\\Api\\Client;\nuse Jiminny\\Services\\Crm\\Copper\\Api\\ClientFactory;\nuse Jiminny\\Services\\Crm\\Copper\\Exception\\RequestFailedException;\nuse Jiminny\\Services\\Crm\\Helpers\\FilterJoinedParticipants;\nuse Jiminny\\Services\\Crm\\OpportunitySyncStrategyResolver;\nuse Jiminny\\Services\\Crm\\Copper\\Traits\\SearchesCrmEntities;\nuse Jiminny\\Utils\\CurrencyFormatter;\nuse Jiminny\\Utils\\StringUtil;\n\nclass Service extends BaseService implements\n CopperInterface,\n SyncCrmEntitiesInterface,\n SyncCrmMetadataInterface,\n RemoteEntityManipulationInterface,\n LayoutManagementInterface,\n SettingsInterface,\n MatchCrmEntitiesInterface,\n RemoteEntityLookupInterface,\n VerifyTaskExistsInterface\n{\n use SearchesCrmEntities;\n private const int NOTE_BODY_MAX_LENGTH = 3000000;\n\n private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day\n\n private const array STANDARD_OPPORTUNITY_FIELDS = [\n 'monetary_value' => [\n 'label' => 'Value',\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n 'type' => Field::TYPE_CURRENCY,\n ],\n 'pipeline_stage_id' => [\n 'label' => 'Stage',\n 'type' => Field::TYPE_PICKLIST,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n 'close_date' => [\n 'label' => 'Close date',\n 'type' => Field::TYPE_DATE,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n 'win_probability' => [\n 'label' => 'Win probability',\n 'type' => Field::TYPE_NUMBER,\n 'available_on' => Field::OBJECT_OPPORTUNITY,\n ],\n ];\n private const string UNSUPPORTED_OBJECT_TYPE = 'unsupported';\n private const string OPPORTUNITY_STATUS_OPEN = 'Open';\n private const string OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE = 'Opportunity import failed';\n private const string RESOURCE_UPDATE_FAILED_ERROR_MESSAGE = 'Failed to update resource';\n\n private FieldValueConverter $fieldValueConverter;\n private ClientFactory $clientFactory;\n private ?Client $copperClient = null;\n\n public function __construct(\n ClientFactory $clientFactory,\n FieldValueConverter $fieldValueConverter,\n private readonly UserRepository $userRepository,\n private readonly ProspectPhotoPathService $prospectPhotoPathService,\n private readonly CrmEntityRepository $crmEntityRepository\n ) {\n parent::__construct();\n\n $this->clientFactory = $clientFactory;\n $this->fieldValueConverter = $fieldValueConverter;\n }\n\n public function getDisplayName(): string\n {\n return 'Copper';\n }\n\n /**\n * Get the CRM entity repository (used by SearchesCrmEntities trait)\n */\n protected function getCrmEntityRepository(): CrmEntityRepository\n {\n return $this->crmEntityRepository;\n }\n\n public function getMinimumApiVersion(): string\n {\n return Client::MIN_API_VERSION;\n }\n\n protected function getOAuthAccount(User $user): ?SocialAccount\n {\n // In this case, the Account Owner is always the connection for any API operations.\n $owner = $user->team->owner;\n\n return $owner->getSocialAccount(SocialAccount::PROVIDER_COPPER);\n }\n\n public function setUser(User $user): void\n {\n $this->configureSentryScope($user);\n\n $this->team = $user->getTeam();\n $this->teamService->setTeam($user->getTeam());\n $this->setConfiguration($user->getTeam()->getCrmConfiguration());\n\n // Reset state.\n $this->profile = $user->getProfile();\n\n if (! $this->profile instanceof Profile) {\n // Try to fetch their profile, maybe it was not yet imported?\n $this->profile = $this->getProfile($user);\n }\n }\n\n public function setConfiguration(Configuration $configuration): void\n {\n $this->config = $configuration;\n $this->copperClient = $this->clientFactory->create($configuration);\n\n if ($this->team === null) {\n $this->team = $configuration->getTeam();\n }\n }\n\n public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string\n {\n return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);\n }\n\n private function mapObjectType(string $objectType): string\n {\n $objectType = strtolower($objectType);\n\n switch ($objectType) {\n case Field::OBJECT_TASK:\n case Field::OBJECT_OPPORTUNITY:\n case Field::OBJECT_LEAD:\n $mappedType = $objectType;\n\n break;\n case Field::OBJECT_ACCOUNT:\n $mappedType = 'company';\n\n break;\n case Field::OBJECT_CONTACT:\n $mappedType = 'person';\n\n break;\n default:\n $mappedType = self::UNSUPPORTED_OBJECT_TYPE;\n\n break;\n }\n\n return $mappedType;\n }\n\n /**\n * @param string $crmObject The name of the CRM object. i.e. Opportunity or Contact\n */\n protected function getFields(string $crmObject): array\n {\n $mappedObjectType = $this->mapObjectType($crmObject);\n\n if (! $this->isSupportedObjectType($mappedObjectType)) {\n return [];\n }\n\n $customFields = $this->copperClient->fields()->all();\n\n $filteredFields = array_filter(\n $customFields,\n static fn ($field) => in_array($mappedObjectType, $field['available_on'], true)\n );\n\n return array_map(\n fn (array $property) => [\n 'name' => $property['id'],\n 'label' => $property['name'],\n 'type' => $this->convertFieldType($property['data_type']),\n ],\n $filteredFields\n );\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultFields(string $activityType): array\n {\n $fields = [];\n\n if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {\n $defaultFields = FieldDefinitions::defaultTaskFields();\n\n // This lazy creates these fields if not already setup.\n foreach ($defaultFields as $defaultField) {\n $fields[] = $this->config->fields()->firstOrCreate($defaultField);\n }\n }\n\n return $fields;\n }\n\n /**\n * @inheritdoc\n */\n public function getDefaultActivityField(string $activityType): Field\n {\n // Setup the activity field as the default Type.\n $activityField = $this->config->fields()->where([\n 'crm_provider_id' => 'type',\n 'object_type' => $activityType,\n ])->first();\n\n return $activityField;\n }\n\n /**\n * @inheritdoc\n */\n public function getSupportedPlaybookTypes(): array\n {\n return [Playbook::ACTIVITY_TYPE_TASK];\n }\n\n public function getDealInsightsFields(): array\n {\n return FieldDefinitions::dealInsightsFields();\n }\n\n protected function getDefaultFollowupLayoutFields(string $activityType): array\n {\n $fields = [];\n $fieldRepo = app(FieldRepository::class);\n $fieldFilters = FieldDefinitions::taskFollowupFieldsFilter();\n\n foreach ($fieldFilters as $data) {\n $field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);\n\n // Only add the field if it is created, which it should be.\n if ($field) {\n $fields[] = $field;\n }\n }\n\n return $fields;\n }\n\n public function syncFields(): void\n {\n $this->syncStandardFields();\n $this->syncCustomFields();\n }\n\n public function syncField(Field $field): void\n {\n if ($field->getCrmProviderId() === 'type') {\n /**\n * This field is a special case, it is not a custom field and is not returned by the Copper API.\n *\n * The field is created manually during layout setup.\n *\n * @see getDefaultFields()\n *\n * There is a separate endpoint to get the activity types.\n * @see importPicklistValues()\n */\n return;\n }\n\n if ($field->getCrmProviderId() === 'pipeline_stage_id') {\n // Not a custom type\n return;\n }\n\n $crmField = $this->copperClient->fields()->find($field->getCrmProviderId());\n $field->label = $crmField['name'];\n $field->type = $this->convertFieldType($crmField['data_type']);\n\n $field->save();\n }\n\n /**\n * @param string $fieldType How the data should be input\n */\n private function convertFieldType(string $fieldType): string\n {\n $fieldType = strtolower($fieldType);\n\n switch ($fieldType) {\n case 'dropdown':\n $convertedType = Field::TYPE_PICKLIST;\n\n break;\n case 'string':\n $convertedType = Field::TYPE_TEXT;\n\n break;\n case 'float':\n case 'percentage':\n $convertedType = Field::TYPE_NUMBER;\n\n break;\n case 'text':\n $convertedType = Field::TYPE_TEXTAREA;\n\n break;\n case 'checkbox':\n $convertedType = Field::TYPE_BOOLEAN;\n\n break;\n case Field::TYPE_DATE:\n case Field::TYPE_CURRENCY:\n case Field::TYPE_URL:\n $convertedType = $fieldType;\n\n break;\n default:\n $convertedType = Field::TYPE_UNSUPPORTED;\n\n break;\n }\n\n return $convertedType;\n }\n\n /**\n * @inheritdoc\n */\n public function importPicklistValues(Field $field): array\n {\n $fieldValues = [];\n\n if ($field->object_type === 'opportunity' && $field->crm_provider_id === 'pipeline_stage_id') {\n return $this->importFieldValuesForDealInsights($field);\n }\n\n $values = [];\n\n if ($field->object_type === Field::OBJECT_TASK && $field->crm_provider_id === 'type') {\n $activityTypes = $this->copperClient->activityTypes()->all();\n\n /**\n * We ignore \"system\" activity types, disabled activity types and the \"Note\" activity type.\n */\n $activityTypes = array_filter(\n $activityTypes['user'],\n fn (array $activityType) => ! $activityType['is_disabled'] && $activityType['id'] !== 0\n );\n\n // Import all activity values.\n $i = 0;\n foreach ($activityTypes as $activityType) {\n $values[] = [\n 'value' => $activityType['id'],\n 'label' => mb_strimwidth($activityType['name'], 0, Field::LABEL_MAX_LENGTH),\n 'sequence' => $i++,\n ];\n }\n } else {\n // We just check for the field in the custom definitions.\n $crmField = $this->copperClient->fields()->find($field->crm_provider_id);\n\n // Import all values.\n foreach ($crmField['options'] as $option) {\n $values[] = [\n 'value' => $option['id'],\n 'label' => mb_strimwidth($option['name'], 0, 191),\n 'sequence' => $option['rank'],\n ];\n }\n }\n\n // Take the existing set of field values.\n $fieldsToPurge = $field->values()->get()->pluck('value')->toArray();\n\n foreach ($values as $value) {\n // For all current values, upsert the field.\n $value['value'] = substr($value['value'] ?? '', 0, 255);\n $fieldValues[] = $field->values()->updateOrCreate([\n 'value' => $value['value'],\n ], $value);\n\n // Remove this value from the ones we are going to purge.\n $key = array_search($value['value'], $fieldsToPurge, false);\n if ($key !== false) {\n unset($fieldsToPurge[$key]);\n }\n }\n\n // Delete the old values that are no longer used.\n $field->values()->whereIn('value', $fieldsToPurge)->delete();\n\n return $fieldValues;\n }\n\n /**\n *\n * @return FieldValue[]\n */\n private function importFieldValuesForDealInsights(Field $field): array\n {\n $fieldValues = [];\n $pipelines = $this->copperClient->pipelines()->all();\n\n foreach ($pipelines as $pipeline) {\n foreach ($pipeline['stages'] as $i => $dealStage) {\n $fieldValues[] = $field->values()->updateOrCreate(\n ['value' => $dealStage['id']],\n [\n 'label' => $dealStage['name'],\n 'sequence' => $i,\n ]\n );\n }\n }\n\n return $fieldValues;\n }\n\n /**\n * @inheritdoc\n */\n public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage\n {\n if ($types === null) {\n $types = [Stage::TYPE_LEAD, Stage::TYPE_OPPORTUNITY];\n }\n $missingStage = null;\n\n foreach ($types as $type) {\n if ($type === Stage::TYPE_LEAD) {\n $statuses = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leadStatuses()->all()\n );\n\n if (count($statuses) > 0) {\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => BusinessProcess::TYPE_LEAD,\n ], [\n 'team_id' => $this->team->id,\n 'name' => BusinessProcess::TYPE_LEAD,\n 'type' => BusinessProcess::TYPE_LEAD,\n 'is_selectable' => true,\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => BusinessProcess::TYPE_LEAD,\n ], [\n 'team_id' => $this->team->id,\n 'name' => BusinessProcess::TYPE_LEAD,\n 'is_selectable' => true,\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n $leadStatuses = [];\n foreach ($statuses as $status) {\n // Upsert all statuses for the team.\n $status = $this->config->stages()->updateOrCreate([\n 'crm_provider_id' => $status['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($status['name'], 0, 50),\n 'label' => mb_strimwidth($status['name'], 0, 191),\n 'type' => Stage::TYPE_LEAD,\n 'sequence' => $status['order'],\n 'is_selectable' => true,\n ]);\n\n if ($missingStageName && $missingStageName === $status['id']) {\n $missingStage = $status;\n }\n\n $leadStatuses[] = $status['id'];\n }\n\n $businessProcess->stages()->sync($leadStatuses);\n }\n } else {\n // We create a business process to contain the pipeline, and later store all stages against it.\n foreach ($this->copperClient->pipelines()->all() as $pipeline) {\n $businessProcess = $this->config->businessProcesses()->updateOrCreate([\n 'crm_provider_id' => $pipeline['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($pipeline['name'], 0, 150),\n 'type' => BusinessProcess::TYPE_OPPORTUNITY,\n 'is_selectable' => true,\n ]);\n\n // A record type is really a clone of the business process, used to store which record uses which pipeline.\n $this->config->recordTypes()->updateOrCreate([\n 'crm_provider_id' => $pipeline['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($pipeline['name'], 0, 150),\n 'is_selectable' => true,\n 'business_process_id' => $businessProcess->id ?? null,\n ]);\n\n $stages = [];\n\n foreach ($pipeline['stages'] as $i => $dealStage) {\n // Upsert all stages for the team.\n $stage = $this->config->stages()->updateOrCreate([\n 'crm_provider_id' => $dealStage['id'],\n ], [\n 'team_id' => $this->team->id,\n 'name' => mb_strimwidth($dealStage['name'], 0, 50),\n 'label' => mb_strimwidth($dealStage['name'], 0, 191),\n 'type' => Stage::TYPE_OPPORTUNITY,\n 'sequence' => $i,\n 'is_selectable' => true,\n 'probability' => $dealStage['win_probability'],\n ]);\n\n if ($missingStageName && $missingStageName === $dealStage['id']) {\n $missingStage = $stage;\n }\n\n $stages[] = $stage['id'];\n }\n\n $businessProcess->stages()->sync($stages);\n }\n }\n }\n\n return $missingStage;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int\n {\n $syncCount = 0;\n\n $cpLeads = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->paginate([\n 'minimum_modified_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ])\n );\n\n foreach ($cpLeads as $cpLead) {\n // Only sync if previously imported.\n if ($this->hasLead($cpLead['id']) === false) {\n $this->importLead($cpLead);\n $syncCount++;\n }\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncLead(string $crmId): ?Lead\n {\n $cpLead = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->find($crmId)\n );\n\n if (\\count($cpLead) === 0) {\n return null;\n }\n\n return $this->importLead($cpLead);\n }\n\n /**\n * @inheritdoc\n */\n private function importLead($crmData): ?Lead\n {\n $countryCode = null;\n if (! empty($crmData['address']) && isset($crmData['address']['country'])) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $mobilePhone = $parsedNumber = null;\n if (! empty($crmData['phone_numbers'])) {\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n if ($phoneNumber['category'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);\n } else {\n $parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);\n }\n }\n }\n\n $name = $crmData['name'];\n\n if (empty($crmData['company_name'])) {\n $company = 'Unknown';\n } else {\n $company = mb_strimwidth($crmData['company_name'], 0, 191);\n }\n\n $domain = null;\n if (empty($crmData['websites']) === false) {\n $domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);\n $domain = StringUtil::resolveDomain($domain);\n }\n\n $email = null;\n if (empty($crmData['email']) === false) {\n $email = mb_strimwidth($crmData['email']['email'], 0, 80);\n }\n\n $stage = $this->config\n ->stages()\n ->where('crm_provider_id', (string) $crmData['status_id'])\n ->where('type', Stage::TYPE_LEAD)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_LEAD], $crmData['status_id']);\n }\n\n if (! $stage instanceof Stage) {\n return null;\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($name, 0, 191),\n 'company' => $company,\n 'domain' => $domain,\n 'title' => $crmData['title'] ? mb_strimwidth($crmData['title'], 0, 128) : null,\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'mobile_phone' => $mobilePhone,\n 'stage_id' => $stage->id,\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Lead::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'country_code' => $countryCode,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->leads()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n /**\n * @inheritdoc\n */\n public function syncAccounts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n $cpAccounts = $this->copperClient->accounts()->paginate([\n 'minimum_modified_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ]);\n\n foreach ($cpAccounts as $cpAccount) {\n // Only sync if previously imported.\n if ($this->hasAccount($cpAccount['id'])) {\n $this->importAccount($cpAccount);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncAccount(string $crmId): ?Account\n {\n $cpAccount = $this->copperClient->accounts()->find($crmId);\n\n if (empty($cpAccount)) {\n return null;\n }\n\n return $this->importAccount($cpAccount);\n }\n\n /**\n * @inheritdoc\n */\n private function importAccount($crmData): Account\n {\n $countryCode = null;\n if (empty($crmData['address']) === false && $crmData['address']['country']) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $name = $crmData['name'];\n\n $parsedNumber = null;\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n $parsedNumber = parsePhoneNumber($countryCode, $phoneNumber['number']);\n }\n\n $domain = null;\n if (empty($crmData['websites']) === false) {\n $domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);\n $domain = StringUtil::resolveDomain($domain);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($name, 0, 191),\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Account::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'country_code' => $countryCode,\n 'domain' => $domain,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->accounts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n public function syncOpportunities(array $parameters, ?string $strategy = null): int\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->copperClient,\n ]);\n $strategies = $strategyResolver->getStrategies($this->config, $strategy);\n\n $syncCount = 0;\n\n try {\n foreach ($strategies as $syncStrategy) {\n foreach ($syncStrategy->fetchOpportunities($parameters) as $opportunityData) {\n $this->importOpportunity($opportunityData);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n $this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => $exception->getMessage(),\n ]);\n }\n\n return $syncCount;\n }\n\n public function syncOpportunity(string $crmId): ?Opportunity\n {\n $strategyResolver = app(OpportunitySyncStrategyResolver::class, [\n 'client' => $this->copperClient,\n ]);\n $strategy = $strategyResolver->resolve(\n $this->config,\n OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY\n );\n\n $parameters['crm_id'] = $crmId;\n\n $cpOpportunity = $strategy->fetchOpportunities($parameters);\n\n return $this->importOpportunity($cpOpportunity);\n }\n\n private function importOpportunity($crmData): ?Opportunity\n {\n $companyId = (string) $crmData['company_id'];\n\n if (empty($companyId)) {\n $this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => 'No company id',\n ]);\n\n return null;\n }\n\n $account = $this->config->accounts()->where('crm_provider_id', $companyId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($companyId);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', (string) $crmData['pipeline_id'])\n ->first();\n\n if ($businessProcess === null) {\n // It is possible for some deals to not be in a pipeline.\n $this->logger->warning(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [\n 'error' => 'Missing pipeline',\n ]);\n\n return null;\n }\n\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', (string) $crmData['pipeline_stage_id'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n $this->logger->info('Stage not found, importing', [\n 'pipeline_id' => $crmData['pipeline_id'],\n 'stage_id' => $crmData['pipeline_stage_id'],\n ]);\n\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData['pipeline_stage_id']);\n }\n\n $recordType = $businessProcess->recordTypes()->first();\n $closeDate = null;\n $isClosed = $crmData['status'] !== self::OPPORTUNITY_STATUS_OPEN;\n\n if ($crmData['close_date']) {\n $closeDate = Carbon::parse($crmData['close_date'])->format('Y-m-d');\n }\n\n $data = [\n 'team_id' => $this->team->getId(),\n 'account_id' => $account->id,\n 'user_id' => $profile->user_id ?? null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => mb_strimwidth($crmData['name'], 0, 128),\n 'value' => $crmData['monetary_value'],\n 'currency_code' => CurrencyFormatter::formatCode($crmData['monetary_unit']),\n 'close_date' => $closeDate,\n 'is_closed' => $isClosed,\n 'is_won' => $crmData['status'] === 'Won',\n 'stage_id' => $stage->id,\n 'record_type_id' => $recordType->id ?? null,\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n /** @var Opportunity $opportunity */\n $opportunity = $this->config\n ->opportunities()\n ->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data)\n ;\n\n // import external fields into crm_field_data if present\n $dealInsightsFields = $this->getOpportunitySyncableFields();\n $this->importOpportunityCrmFieldData($crmData, $dealInsightsFields, $opportunity->id);\n\n return $opportunity;\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n * @param string[] $dealInsightsFields\n */\n public function importOpportunityCrmFieldData(\n array $opportunityData,\n array $dealInsightsFields,\n int $opportunityId\n ): void {\n foreach ($dealInsightsFields as $fieldName) {\n $field = $this->config->fields()->with('entities')\n ->where('crm_provider_id', $fieldName)\n ->where('object_type', Field::OBJECT_OPPORTUNITY)\n ->first();\n\n if (! $field instanceof Field) {\n $this->logger->warning('Field not found', [\n 'field' => $fieldName,\n 'opportunity_id' => $opportunityId,\n ]);\n\n continue;\n }\n\n $entity = $field->getEntities()->first();\n\n if (! $entity instanceof LayoutEntity) {\n continue;\n }\n\n $fieldValue = $this->extractFieldValue($opportunityData, $fieldName);\n $normalizedValue = $this->normalizeValue($field->getType(), (string) $fieldValue, true);\n\n $field->data()\n ->updateOrCreate([\n 'crm_layout_entity_id' => $entity->id,\n 'crm_field_id' => $field->id,\n 'object_type' => 'opportunity',\n 'object_id' => $opportunityId,\n ], ['value' => $normalizedValue])\n ;\n }\n }\n\n /**\n * @inheritdoc\n */\n public function syncContacts(Carbon $since, ?Carbon $to = null): int\n {\n $syncCount = 0;\n\n try {\n $cpContacts = $this->copperClient->contacts()->paginate([\n 'minimum_interaction_date' => $since->timestamp,\n 'sort_by' => 'date_modified',\n ]);\n\n foreach ($cpContacts as $cpContact) {\n // Only sync if previously imported.\n if ($this->hasContact($cpContact['id'])) {\n $this->importContact($cpContact);\n $syncCount++;\n }\n }\n } catch (\\Exception $exception) {\n // Do nothing for now.\n throw $exception;\n }\n\n return $syncCount;\n }\n\n /**\n * @inheritdoc\n */\n public function syncContact(string $crmId): ?Contact\n {\n $cpContact = $this->copperClient->contacts()->find($crmId);\n\n if (empty($cpContact)) {\n return null;\n }\n\n return $this->importContact($cpContact);\n }\n\n /**\n * @inheritdoc\n */\n private function importContact($crmData): Contact\n {\n $account = null;\n if ($crmData['company_id']) {\n $account = $this->team\n ->crm\n ->accounts()\n ->where('crm_provider_id', (string) $crmData['company_id'])\n ->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmData['company_id']);\n }\n }\n\n $countryCode = null;\n if (empty($crmData['address']) === false && $crmData['address']['country']) {\n $countryCode = $this->convertCountryNameToCode($crmData['address']['country']);\n }\n\n $mobilePhone = $parsedNumber = null;\n foreach ($crmData['phone_numbers'] as $phoneNumber) {\n if ($phoneNumber['category'] === 'mobile') {\n $mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);\n } else {\n $parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);\n }\n }\n\n $email = null;\n if (empty($crmData['emails']) === false) {\n $email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);\n }\n\n $profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();\n\n $data = [\n 'team_id' => $this->team->id,\n 'account_id' => $account->id ?? null,\n 'user_id' => $profile ? $profile->user_id : null,\n 'owner_id' => $crmData['assignee_id'],\n 'name' => $crmData['name'],\n 'email' => $email,\n 'phone' => $parsedNumber['phone'] ?? null,\n 'mobile_phone' => $mobilePhone ?? null,\n 'ext' => $parsedNumber['ext'] ?? null,\n 'title' => $crmData['title'],\n 'country_code' => $countryCode,\n 'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(\n crmConfiguration: $this->config,\n crmProviderId: $crmData['id'],\n modelType: Contact::class,\n fileName: $crmData['id'],\n avatarText: $crmData['name']\n ),\n 'remotely_created_at' => $crmData['date_created'],\n ];\n\n return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);\n }\n\n private function buildContactPhone(?string $countryCode, ?string $number): ?array\n {\n if ($number) {\n // Trim to our width and attempt to parse it.\n $number = mb_strimwidth($number, 0, 25);\n $parsedNumber = parsePhoneNumber($countryCode, $number);\n } else {\n $parsedNumber = [];\n }\n\n return $parsedNumber;\n }\n\n private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string\n {\n return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;\n }\n\n /**\n * @inheritdoc\n */\n public function syncOrganization(): void\n {\n $organization = $this->copperClient->organisation()->all();\n\n if ($this->config->crm_provider_id !== $organization['id']) {\n $this->config->update(['crm_provider_id' => $organization['id']]);\n }\n }\n\n private function syncCustomFields(): void\n {\n foreach ($this->getFieldTypes() as $fieldType) {\n $currentFields = $this->getFields($fieldType);\n\n foreach ($currentFields as $field) {\n /** @var Field $field */\n $field = $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => $field['name'],\n 'object_type' => $fieldType,\n ], [\n 'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),\n 'type' => $field['type'],\n ]);\n\n if ($field->getType() === Field::TYPE_PICKLIST) {\n $this->importPicklistValues($field);\n }\n }\n }\n\n $this->config->save();\n }\n\n protected function getFieldTypes(): array\n {\n return [\n parent::OBJECT_TASK,\n parent::OBJECT_LEAD,\n parent::OBJECT_ACCOUNT,\n parent::OBJECT_CONTACT,\n parent::OBJECT_OPPORTUNITY,\n ];\n }\n\n /**\n * @inheritdoc\n */\n public function syncProfiles(?User $userToSearch = null): ?Profile\n {\n $profiles = $this->copperClient->users()->all();\n\n foreach ($profiles as $profile) {\n $user = $this->userRepository->findByTeamAndEmailAddress($this->team, $profile['email'], onlyActive: true);\n\n // Only import profiles for users we have locally.\n if ($user) {\n $profile = $user->crmProfile()->updateOrCreate([\n 'crm_configuration_id' => $this->config->id,\n 'crm_provider_id' => $profile['id'],\n ]);\n\n if ($userToSearch && $userToSearch->id === $user->id) {\n return $profile;\n }\n }\n }\n\n return null;\n }\n\n /**\n * @inheritdoc\n */\n public function syncProfileFields(): void\n {\n $fieldTypes = [\n 'task',\n 'lead',\n 'account',\n 'contact',\n 'opportunity',\n ];\n\n foreach ($fieldTypes as $fieldType) {\n try {\n $currentFields = $this->getFields(ucfirst($fieldType));\n\n $newFields = array_column($currentFields, 'name');\n $changedFields = array_merge(\n array_diff($this->profile->getFieldsAsArray($fieldType), $newFields),\n array_diff($newFields, $this->profile->getFieldsAsArray($fieldType))\n );\n\n if (\\count($changedFields) > 0) {\n $fields = implode(',', $newFields);\n $this->logger->debug(\n ucfirst($fieldType)\n . ' fields changed from '\n . $this->profile->{$fieldType . '_fields'}\n . ' to: '\n . $fields\n );\n\n $this->profile->{$fieldType . '_fields'} = $fields;\n }\n } catch (\\Exception $exception) {\n $this->logger->error('No access to ' . $fieldType . ' object, skipping...');\n\n continue;\n }\n }\n\n $this->profile->save();\n }\n\n /**\n * @inheritdoc\n */\n public function find(string $name, array $scopes): array\n {\n $count = $this->limit ?? 20;\n $offset = $this->offset ?? 0;\n\n $scopeValues = array_map(fn ($scope) => is_string($scope) ? $scope : $scope->value, $scopes);\n $cacheKey = sprintf('copper-search-%d-%s-%s-%d-%d', $this->team->id, $name, implode('-', $scopeValues), $count, $offset);\n\n return Cache::remember($cacheKey, 300, function () use ($name, $scopes, $count, $offset) {\n // Try local search first\n $localResults = $this->searchLocally($name, $scopes, $count, $offset);\n\n // If no local results, fall back to remote API search\n if (empty($localResults)) {\n return $this->searchRemotely($name, $scopes, $count, $offset);\n }\n\n return $localResults;\n });\n }\n\n /**\n * @inheritdoc\n */\n public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array\n {\n $data = [];\n $ownerData = [];\n $ownerId = null;\n $contact = null;\n $account = null;\n\n if ($crmAccountId) {\n $account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();\n\n if ($account === null) {\n $account = $this->syncAccount($crmAccountId);\n }\n }\n\n if ($crmContactId) {\n $contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();\n\n if ($contact === null) {\n $contact = $this->syncContact($crmContactId);\n }\n }\n\n if ($contact || $account) {\n if ($contact && $account === null) {\n $account = $contact->account;\n }\n\n if ($account === null) {\n return [];\n }\n\n $params = [\n 'company_ids' => [$account->crm_provider_id],\n 'status_ids' => [0], // The integer values are 0, 1, 2, 3, for \"Open\", \"Won\", \"Lost\", and \"Abandoned\".\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ];\n\n switch ($this->config->opportunity_assignment_rule) {\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:\n $params['sort_by'] = 'date_modified';\n $params['sort_direction'] = 'desc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:\n $params['sort_by'] = 'date_created';\n $params['sort_direction'] = 'desc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:\n $params['sort_by'] = 'date_created';\n $params['sort_direction'] = 'asc';\n\n break;\n\n case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:\n $params['sort_by'] = 'date_modified';\n $params['sort_direction'] = 'desc';\n $params['status_ids'] = [0, 1, 2, 3];\n }\n\n $cpOpportunities = $this->copperClient->opportunities()->search($params);\n\n if ($userId) {\n $profileRepository = app(ProfileRepository::class);\n $profile = $profileRepository->findProfileByUserId($this->config, $userId);\n\n $ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;\n }\n\n foreach ($cpOpportunities as $cpOpportunity) {\n $businessProcess = $this->config\n ->businessProcesses()\n ->where('crm_provider_id', (string) $cpOpportunity['pipeline_id'])\n ->first();\n\n if ($businessProcess === null) {\n // Import it.\n $businessProcess = $this->importStages(\n [Stage::TYPE_OPPORTUNITY],\n $cpOpportunity['pipeline_stage_id']\n );\n }\n\n $stage = $businessProcess\n ->stages()\n ->where('crm_provider_id', (string) $cpOpportunity['pipeline_stage_id'])\n ->where('type', Stage::TYPE_OPPORTUNITY)\n ->first();\n\n if ($stage === null) {\n // Import it.\n $stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $cpOpportunity['pipeline_stage_id']);\n }\n\n $recordType = $businessProcess->recordTypes()->first();\n\n $record = [\n 'crmId' => $cpOpportunity['id'],\n 'name' => $cpOpportunity['name'],\n 'value' => currency_format($cpOpportunity['monetary_value'], $cpOpportunity['monetary_unit']),\n 'won' => $cpOpportunity['status'] === 'Won',\n 'stage' => [\n 'id' => $stage->id_string,\n 'name' => $stage->name,\n ],\n 'recordType' => [\n 'id' => $recordType->id_string,\n 'name' => $recordType->name,\n ],\n ];\n\n if ($ownerId && isset($cpOpportunity['assignee_id']) && $cpOpportunity['assignee_id'] === $ownerId) {\n $ownerData[] = $record;\n }\n\n $data[] = $record;\n }\n }\n\n if (! empty($ownerData)) {\n return $ownerData;\n }\n\n return $data;\n }\n\n /**\n * @inheritdoc\n */\n public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array\n {\n $data = $cpTasks = [];\n\n switch ($objectType) {\n case 'lead':\n $cpTasks = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->relatedTasks($objectId)\n );\n\n break;\n\n case 'account':\n $cpTasks = $this->copperClient->accounts()->relatedTasks($objectId);\n\n break;\n case 'contact':\n if ($opportunityId) {\n $cpTasks = $this->copperClient->opportunities()->relatedTasks($opportunityId);\n } elseif ($objectType === 'contact') {\n $cpTasks = $this->copperClient->contacts()->relatedTasks($objectId);\n }\n\n break;\n }\n\n foreach ($cpTasks as $cpTask) {\n // We only get the ID itself returned, so pull out the full object.\n try {\n $cpTask = $this->copperClient->tasks()->find($cpTask['id']);\n } catch (Exception $exception) {\n $this->logger->error('[Copper] Error fetching task', [\n 'resource_id' => $cpTask['id'],\n 'error' => $exception->getMessage(),\n ]);\n\n continue;\n }\n\n // Only allow open tasks.\n if ($cpTask['status'] === 'Open') {\n $data[] = [\n 'crmId' => $cpTask['id'],\n 'subject' => $cpTask['name'],\n 'due' => $cpTask['due_date']\n ? Carbon::createFromTimestamp($cpTask['due_date'])->format('Y-m-d\\TH:i:sO')\n : null,\n 'type' => null,\n ];\n }\n }\n\n return $data;\n }\n\n /**\n * Try to find email address in CRM service\n *\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n *}\n */\n public function matchExactlyByEmail(string $email, ?int $userId = null): ?array\n {\n $cpObjectType = 'contact';\n\n $cpObjects = $this->copperClient->contacts()->search([\n 'emails' => $email,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (empty($cpObjects)) {\n $cpObjectType = 'lead';\n $cpObjects = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'emails' => $email,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (empty($cpObjects)) {\n return null;\n }\n\n // Search returns an array of results, but we only want the first\n $cpObject = reset($cpObjects);\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByPhone(string $phone, ?string $rawPhoneNumber = null, ?int $userId = null): ?array\n {\n // Check if the user is internal.\n $teamMember = $this->team->users()->where('phone', $phone)->exists();\n\n // Skip the attendee if internal.\n if ($teamMember === false) {\n $cpObjectType = 'contact';\n $cpObject = $this->copperClient->contacts()->search([\n 'phone_number' => $phone,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (\\count($cpObject) === 0) {\n $cpObjectType = 'lead';\n $cpObject = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'phone_number' => $phone,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (empty($cpObject)) {\n return null;\n }\n\n $cpObject = reset($cpObject);\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : null;\n }\n\n return null;\n }\n\n /**\n * @return null|array{\n * Lead|null,\n * Account|null,\n * Opportunity|null,\n * Contact|null,\n * Stage|null,\n * string|null\n * }\n */\n public function matchByName(string $name, ?int $userId = null): ?array\n {\n // Don't waste time searching for single character strings.\n if (\\strlen($name) <= 1) {\n return null;\n }\n\n $result = \\Cache::remember($this->team->id . $name, 60, function () use ($name, $userId) {\n $cpObjectType = 'contact';\n $cpObject = $this->copperClient->contacts()->search([\n 'name' => $name,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ]);\n\n if (\\count($cpObject) === 0) {\n $cpObjectType = 'lead';\n $cpObject = $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->search([\n 'name' => $name,\n 'sort_by' => 'date_modified',\n 'sort_direction' => 'desc',\n ])\n );\n }\n\n if (! empty($cpObject)) {\n $cpObject = reset($cpObject);\n }\n\n $data = $this->convertCrmData($cpObject, $cpObjectType, $userId);\n\n return ! empty(array_filter($data)) ? $data : false;\n });\n\n return is_array($result) ? $result : null;\n }\n\n private function convertCrmData(array $object, string $objectType, ?int $userId = null): array\n {\n $lead = null;\n $contact = null;\n $opportunity = null;\n $account = null;\n $stage = null;\n $countryCode = null;\n\n if ($objectType === 'lead') {\n $lead = $this->importLead($object);\n\n // Lead might not be imported if the Stage is null for example.\n if ($lead) {\n $countryCode = $lead->country_code;\n $stage = $lead->stage;\n }\n } else {\n $contact = $this->importContact($object);\n $account = $contact->account;\n\n if ($contact->country_code) {\n $countryCode = $contact->country_code;\n } elseif ($account) {\n $countryCode = $account->country_code;\n }\n\n try {\n $cpOpportunities = $this->findOpportunities(\n $account?->crm_provider_id,\n $contact->crm_provider_id,\n $userId,\n );\n\n if (! empty($cpOpportunities)) {\n // Persist this remote object.\n $opportunity = $this->syncOpportunity($cpOpportunities[0]['crmId']);\n $stage = $opportunity?->getStage();\n }\n } catch (\\Exception $e) {\n // Nothing to see here.\n }\n }\n\n return [\n $lead,\n $account,\n $opportunity,\n $contact,\n $stage,\n $countryCode,\n ];\n }\n\n public function saveActivity(Activity $activity): Activity\n {\n switch ($activity->type) {\n case Activity::TYPE_CONFERENCE:\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n $activity = $this->buildCallPayload($activity);\n\n break;\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $activity = $this->buildTextMessagePayload($activity);\n\n break;\n }\n\n return $activity;\n }\n\n private function convertActivityAssociations(Activity $activity): array\n {\n if ($activity->lead) {\n $type = 'lead';\n $id = $activity->lead->crm_provider_id;\n } elseif ($activity->contact) {\n $type = 'person';\n $id = $activity->contact->crm_provider_id;\n } elseif ($activity->opportunity) {\n $type = 'opportunity';\n $id = $activity->opportunity->crm_provider_id;\n } else {\n $type = 'company';\n $id = $activity->account->crm_provider_id;\n }\n\n return [\n 'type' => $type,\n 'id' => $id,\n ];\n }\n\n private function convertActivityType(PlaybookCategory $activityType): array\n {\n return [\n 'category' => 'user',\n 'id' => $this->getCrmType($activityType)->value,\n ];\n }\n\n /**\n * @throws CrmException\n */\n private function buildCallPayload(Activity $activity): Activity\n {\n try {\n if ($activity->crm_provider_id) {\n // The activity should be logged under the existing Task (not Activity).\n $newActivityType = $this->getCrmType($activity->category);\n if ($newActivityType === null) {\n $message = sprintf('[Copper] invalid CRM Custom Activity Type: %s', $activity->category);\n\n throw new CrmException($message, 400);\n }\n $this->copperClient->tasks()->update($activity->crm_provider_id, [\n 'status' => 'Completed',\n 'custom_activity_type_id' => $newActivityType->value,\n 'details' => $this->generateActivityDescription($activity),\n ]);\n } else {\n if ($this->getCrmType($activity->category) === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n if ($this->getCrmType($activity->category)->value === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n // Just create an activity.\n $cpActivity = $this->copperClient->activities()->create([\n 'user_id' => $this->profile->crm_provider_id,\n 'activity_date' => $activity->scheduled_start_time->timestamp,\n 'parent' => $this->convertActivityAssociations($activity),\n 'type' => $this->convertActivityType($activity->category),\n 'details' => $this->generateActivityDescription($activity),\n ]);\n\n $activity->crm_provider_id = $cpActivity['id'];\n $activity->save();\n }\n } catch (ClientException $exception) {\n //Log all errors to Sentry\n \\Sentry::captureException($exception);\n\n $response = $exception->getResponse();\n\n $responseBody = $response->getBody();\n $message = $responseBody;\n $errorCode = $response->getStatusCode();\n\n $jsonResponse = json_decode($responseBody, true);\n if (isset($jsonResponse[0]['message'])) {\n $message = $jsonResponse[0]['message'];\n }\n\n throw new CrmException($message, $errorCode);\n }\n\n return $activity;\n }\n\n private function buildTextMessagePayload(Activity $activity): Activity\n {\n if ($this->getCrmType($activity->category) === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n if ($this->getCrmType($activity->category)->value === null) {\n $message = sprintf('[Copper] Invalid CRM Activity Type: %s value', $activity->category->getName());\n\n throw new CrmException($message, 400);\n }\n\n $cpActivity = $this->copperClient->activities()->create([\n 'user_id' => $this->profile->crm_provider_id,\n 'activity_date' => $activity->created_at->timestamp,\n 'parent' => $this->convertActivityAssociations($activity),\n 'type' => $this->convertActivityType($activity->category),\n 'details' => $this->generateActivityDescription($activity),\n ]);\n\n $activity->crm_provider_id = $cpActivity['id'];\n $activity->save();\n\n return $activity;\n }\n\n private function generateActivityDescription(Activity $activity): string\n {\n $description = '';\n\n switch ($activity->type) {\n case Activity::TYPE_SOFTPHONE:\n case Activity::TYPE_SOFTPHONE_INBOUND:\n case Activity::TYPE_CONFERENCE:\n\n $description = 'Jiminny Call Summary' . PHP_EOL . PHP_EOL;\n $description .= 'Call Duration: ' . $activity->duration_for_humans . PHP_EOL . PHP_EOL;\n\n // Tell them which number was dialed.\n if ($activity->to) {\n $description .= 'Dialed: ' . $activity->to->phone_number . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->hasReasonCodeBotKicked()) {\n $description .= 'Notetaker removed from this meeting' . PHP_EOL . PHP_EOL;\n // When we fix the state to be Activity::RECORDING_RECORDED as it should be this can change.\n } elseif ($activity->hasReasonCodeNotCompliant()) {\n $description .= 'Notetaker did not join due to recording consent not being provided by attendees' . PHP_EOL . PHP_EOL;\n } elseif ($activity->canReviewActivity()) {\n $playbackUrl = $activity->user->team->partner->getPlaybackUrl($activity);\n $description .= 'Review Activity:' . PHP_EOL . $playbackUrl . PHP_EOL . PHP_EOL;\n }\n\n if ($activity->getCrmType() === Activity::TYPE_CONFERENCE) {\n $description .= 'Attendees:'\n . PHP_EOL\n . (new FilterJoinedParticipants())->toString($activity);\n }\n\n if (\\count($activity->notes) > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Notes: ' . PHP_EOL;\n\n foreach ($activity->notes as $note) {\n $nTime = (int) ceil($note->time);\n $time = ($nTime > 3600) ? gmdate('H:i:s', $nTime) : gmdate('i:s', $nTime);\n $description .= $time . ' ' . $note->note . PHP_EOL;\n }\n }\n\n // Get all private messages.\n $messages = $activity->messages()\n ->where('is_private', 1)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Coaching Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n // Get all public messages.\n $messages = $activity->messages()\n ->where('is_private', 0)\n ->orderBy('created_at', 'asc');\n\n if ($messages->count() > 0) {\n $description .= PHP_EOL . PHP_EOL . 'Customer Chat: ' . PHP_EOL;\n\n foreach ($messages->get() as $message) {\n $description .= $message->participant->name . ': ' . $message->message . PHP_EOL;\n }\n }\n\n if ($activity->summary) {\n $description .= PHP_EOL . PHP_EOL . 'Summary: ' . PHP_EOL . $activity->summary;\n }\n\n break;\n\n case Activity::TYPE_SMS_INBOUND:\n case Activity::TYPE_SMS_OUTBOUND:\n $description = $activity->description;\n\n break;\n }\n\n return $description;\n }\n\n public function saveFollowupActivity(Activity $activity, array $fields): ?string\n {\n // This is the user provided activity subject field.\n if (empty($fields['type'])) {\n return null;\n }\n\n $reminder = null;\n if (empty($fields['reminder_date']) === false) {\n $formatReminder = Carbon::createFromFormat('Y-m-d\\TH:i:s\\Z', $fields['reminder_date']);\n $reminder = $formatReminder->getTimestamp();\n }\n\n $due = null;\n if (empty($fields['due_date']) === false) {\n $formatDue = Carbon::createFromFormat('Y-m-d\\TH:i:s\\Z', $fields['due_date']);\n $due = $formatDue->getTimestamp();\n }\n\n $data = [\n 'custom_activity_type_id' => $fields['type'],\n 'status' => 'Open',\n 'assignee_id' => $this->profile->crm_provider_id,\n 'due_date' => $due,\n 'details' => $fields['details'] ?? '',\n 'reminder_date' => $reminder,\n 'name' => $fields['name'] ?? 'Follow-up',\n 'related_resource' => $this->convertActivityAssociations($activity),\n 'custom_fields' => $this->fetchCustomFieldData($activity, Field::OBJECT_TASK),\n ];\n\n // We don't actually create a corresponding activity object on our side yet.\n return $this->copperClient->tasks()->create($data)['id'];\n }\n\n /**\n * Store transcripts as note.\n *\n * @throws \\Exception\n */\n public function createTranscriptNotes(Activity $activity): void\n {\n // Generate activity transcription.\n $transcriptionData = $this->generateTranscription($activity);\n\n // Truncate Notes with max notes length because transcription text could be very long.\n $transcripts = mb_strimwidth($transcriptionData, 0, static::NOTE_BODY_MAX_LENGTH);\n\n $data = [\n 'user_id' => $this->profile->crm_provider_id,\n 'type' => [\n 'category' => 'user',\n 'id' => 0, // This creates a note.\n ],\n 'activity_date' => time(),\n 'details' => $transcripts,\n 'parent' => $this->convertActivityAssociations($activity),\n ];\n\n $cpActivity = $this->copperClient->activities()->create($data);\n\n // Store CRM Activity ID in transcription.\n $transcription = $activity->getTranscription();\n $transcription->crm_activity_id = $cpActivity['id'];\n $transcription->save();\n }\n\n /**\n * @inheritdoc\n */\n public function updateStage($crmObject, Stage $stage): void\n {\n if ($crmObject instanceof Lead) {\n $this->requestWithExceptionHandling(\n fn () => $this->copperClient->leads()->update($crmObject->crm_provider_id, [\n 'status_id' => $stage->crm_provider_id,\n ])\n );\n } else {\n $this->copperClient->opportunities()->update($crmObject->crm_provider_id, [\n 'pipeline_stage_id' => $stage->crm_provider_id,\n ]);\n }\n }\n\n public function prepareValueForUpdate(array $params): array\n {\n return [$params['fieldName'] => $params['fieldValue']];\n }\n\n /*\n * @inheritdoc\n */\n public function updateRecord(string $objectType, string $objectId, array $data, array $headers = []): void\n {\n $preparedData = $data;\n\n if ($objectType === Field::OBJECT_OPPORTUNITY) {\n $preparedData = $this->prepareOpportunityFieldsForUpdate($data);\n }\n\n try {\n $this->copperClient\n ->createResourceFromObjectType($objectType)\n ->update($objectId, $preparedData)\n ;\n } catch (Exception $e) {\n $this->logger->error(self::RESOURCE_UPDATE_FAILED_ERROR_MESSAGE, [\n 'resource_id' => $objectId,\n 'data' => $preparedData,\n 'error' => $e->getMessage(),\n ]);\n\n throw new CrmException(self::RESOURCE_UPDATE_FAILED_ERROR_MESSAGE, $e->getCode(), $e);\n }\n }\n\n /**\n * @param array<string,string> $fieldData\n *\n * @throws CrmException\n *\n * @return array<string,array<int,array<string,bool|float|int|string|null>>|bool|float|int|string|null>\n */\n private function prepareOpportunityFieldsForUpdate(array $fieldData): array\n {\n $preparedData = [];\n $customFields = [];\n\n foreach ($fieldData as $fieldName => $fieldValue) {\n $field = $this->config\n ->fields()\n ->where('crm_provider_id', $fieldName)\n ->first();\n\n if (! $field instanceof Field) {\n throw new CrmException('Field not found');\n }\n\n $convertedValue = $this->fieldValueConverter->convertToCrm($field->getType(), $fieldValue);\n\n if ($this->isStandardField($fieldName)) {\n $preparedData[$fieldName] = $convertedValue;\n\n continue;\n }\n\n $customFields[] = [\n 'custom_field_definition_id' => $fieldName,\n 'value' => $convertedValue,\n ];\n }\n\n if (! empty($customFields)) {\n $preparedData['custom_fields'] = $customFields;\n }\n\n return $preparedData;\n }\n\n /*\n * @inheritdoc\n */\n public function getRecord(string $objectType, string $objectId, array $fields = []): array\n {\n return $this->copperClient->createResourceFromObjectType($objectType)->find($objectId);\n }\n\n private function fetchCustomFieldData(Activity $activity, string $objectType): array\n {\n $payload = [];\n\n $fieldData = FieldData::where([\n 'object_id' => $activity->id,\n ])->whereHas('field', function ($query) use ($objectType) {\n $query->where('object_type', $objectType);\n })->get();\n\n foreach ($fieldData as $data) {\n // Add the field and value to the payload.\n $payload += [\n 'custom_field_definition_id' => $data->field->crm_provider_id,\n 'value' => $data->value,\n ];\n }\n\n return $payload;\n }\n\n public function generateProviderUrl(string $providerId, string $objectType): ?string\n {\n $baseUrl = 'https://app.prosperworks.com/companies/' . $this->config->crm_provider_id . '/app#/';\n switch ($objectType) {\n case 'lead':\n $url = $baseUrl . 'leads/' . $providerId;\n\n break;\n\n case 'account':\n $url = $baseUrl . 'organization/' . $providerId;\n\n break;\n\n case 'contact':\n $url = $baseUrl . 'contact/' . $providerId;\n\n break;\n\n case 'opportunity':\n $url = $baseUrl . 'deal/' . $providerId;\n\n break;\n\n default:\n case 'task':\n case 'activity':\n // Sadly we can't deeplink to these in Copper UI.\n $url = null;\n }\n\n return $url;\n }\n\n /**\n * Generate transcription for the activity.\n */\n private function generateTranscription(Activity $activity): string\n {\n if (! ($this->config->store_transcript)) {\n // If sending transcription to activity toggle is disabled\n return '';\n }\n\n return $this->transcriptionService\n ->findTranscriptionByActivity($activity)\n ->map(static function (array $transcriptionSegment): string {\n return $transcriptionSegment['formattedStartsAt'] . ' | ' . $transcriptionSegment['transcript'];\n })\n ->implode(PHP_EOL);\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n *\n * @return int|string|bool|float|null\n */\n private function extractFieldValue(array $opportunityData, string $fieldName)\n {\n $fieldValue = $this->isStandardField($fieldName)\n ? $opportunityData[$fieldName]\n : $this->resolveCustomFieldFromOpportunityData($opportunityData, $fieldName);\n\n if (is_array($fieldValue)) {\n $fieldValue = implode(', ', $fieldValue);\n }\n\n return $fieldValue;\n }\n\n private function isStandardField(string $fieldName): bool\n {\n return array_key_exists($fieldName, self::STANDARD_OPPORTUNITY_FIELDS);\n }\n\n /**\n * @param array<string, mixed> $opportunityData\n *\n * @return string|int|float|bool|null|array<string, mixed>\n */\n private function resolveCustomFieldFromOpportunityData(array $opportunityData, string $fieldName)\n {\n $fieldData = array_filter(\n $opportunityData['custom_fields'],\n static fn ($field) => (string) $field['custom_field_definition_id'] === $fieldName\n );\n\n return array_pop($fieldData)['value'] ?? '';\n }\n\n private function isSupportedObjectType(string $objectType): bool\n {\n return $objectType !== self::UNSUPPORTED_OBJECT_TYPE;\n }\n\n private function syncStandardFields(): void\n {\n foreach (self::STANDARD_OPPORTUNITY_FIELDS as $fieldId => $fieldData) {\n $this->config->fields()->updateOrCreate([\n 'crm_provider_id' => mb_strimwidth($fieldId, 0, 128),\n 'object_type' => Field::OBJECT_OPPORTUNITY,\n ], [\n 'label' => mb_strimwidth($fieldData['label'], 0, Field::LABEL_MAX_LENGTH),\n 'type' => $fieldData['type'],\n ]);\n }\n\n $this->importStages([Stage::TYPE_OPPORTUNITY]);\n }\n\n private function requestWithExceptionHandling(\\Closure $apiRequest): iterable\n {\n try {\n return $apiRequest();\n } catch (\\Exception $exception) {\n if ($exception->getCode() === 403) {\n // Object might not be supported\n return [];\n }\n\n \\Sentry::captureException($exception);\n\n return [];\n }\n }\n\n public function verifyTaskExists(Activity $activity): bool\n {\n $crmProviderId = $activity->getCrmProviderId();\n $cacheKey = \"crm_task_exists:{$this->config->getId()}:$crmProviderId\";\n\n return Cache::remember($cacheKey, self::TASK_VERIFICATION_CACHE_TTL, function () use ($crmProviderId) {\n try {\n if ($this->copperClient === null) {\n return false;\n }\n\n $task = $this->copperClient->tasks()->find($crmProviderId);\n\n return ! empty($task);\n } catch (HttpNotFoundException) {\n // Task not found in CRM - this is expected and permanent\n $this->logger->info('[Copper] Task not found during verification', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n } catch (RequestFailedException $e) {\n // Handle 404 responses from Copper API\n if ($e->getCode() === 404) {\n $this->logger->info('[Copper] Task not found during verification (404)', [\n 'task_id' => $crmProviderId,\n 'config_id' => $this->config->getId(),\n ]);\n\n return false;\n }\n\n // Re-throw other Copper exceptions for retry\n throw $e;\n }\n // Let other exceptions (network errors, rate limits, etc.) bubble up for retry\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":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"View Parameters","depth":4,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
2931661465023499269
|
-7959665055215974171
|
click
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
Analyzing…
<?php
namespace Jiminny\Services\Crm\Copper;
use Carbon\Carbon;
use Exception;
use GuzzleHttp\Exception\ClientException;
use Illuminate\Support\Facades\Cache;
use Jiminny\Contracts\Services\Crm\LayoutManagementInterface;
use Jiminny\Contracts\Services\Crm\MatchCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\Provider\CopperInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityLookupInterface;
use Jiminny\Contracts\Services\Crm\RemoteEntityManipulationInterface;
use Jiminny\Contracts\Services\Crm\SettingsInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmEntitiesInterface;
use Jiminny\Contracts\Services\Crm\SyncCrmMetadataInterface;
use Jiminny\Contracts\Services\Crm\VerifyTaskExistsInterface;
use Jiminny\Exceptions\CrmException;
use Jiminny\Exceptions\HttpNotFoundException;
use Jiminny\Models\Account;
use Jiminny\Models\Activity;
use Jiminny\Models\Contact;
use Jiminny\Models\Crm\BusinessProcess;
use Jiminny\Models\Crm\Configuration;
use Jiminny\Models\Crm\Field;
use Jiminny\Models\Crm\FieldData;
use Jiminny\Models\Crm\FieldValue;
use Jiminny\Models\Crm\LayoutEntity;
use Jiminny\Models\Crm\Profile;
use Jiminny\Models\Lead;
use Jiminny\Models\Opportunity;
use Jiminny\Models\Playbook;
use Jiminny\Models\PlaybookCategory;
use Jiminny\Models\SocialAccount;
use Jiminny\Models\Stage;
use Jiminny\Models\User;
use Jiminny\Repositories\Crm\CrmEntityRepository;
use Jiminny\Repositories\Crm\FieldRepository;
use Jiminny\Repositories\Crm\ProfileRepository;
use Jiminny\Repositories\UserRepository;
use Jiminny\Services\Avatar\ProspectPhotoPathService;
use Jiminny\Services\Crm\BaseService;
use Jiminny\Services\Crm\Copper\Api\Client;
use Jiminny\Services\Crm\Copper\Api\ClientFactory;
use Jiminny\Services\Crm\Copper\Exception\RequestFailedException;
use Jiminny\Services\Crm\Helpers\FilterJoinedParticipants;
use Jiminny\Services\Crm\OpportunitySyncStrategyResolver;
use Jiminny\Services\Crm\Copper\Traits\SearchesCrmEntities;
use Jiminny\Utils\CurrencyFormatter;
use Jiminny\Utils\StringUtil;
class Service extends BaseService implements
CopperInterface,
SyncCrmEntitiesInterface,
SyncCrmMetadataInterface,
RemoteEntityManipulationInterface,
LayoutManagementInterface,
SettingsInterface,
MatchCrmEntitiesInterface,
RemoteEntityLookupInterface,
VerifyTaskExistsInterface
{
use SearchesCrmEntities;
private const int NOTE_BODY_MAX_LENGTH = 3000000;
private const int TASK_VERIFICATION_CACHE_TTL = 86400; // 1 day
private const array STANDARD_OPPORTUNITY_FIELDS = [
'monetary_value' => [
'label' => 'Value',
'available_on' => Field::OBJECT_OPPORTUNITY,
'type' => Field::TYPE_CURRENCY,
],
'pipeline_stage_id' => [
'label' => 'Stage',
'type' => Field::TYPE_PICKLIST,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
'close_date' => [
'label' => 'Close date',
'type' => Field::TYPE_DATE,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
'win_probability' => [
'label' => 'Win probability',
'type' => Field::TYPE_NUMBER,
'available_on' => Field::OBJECT_OPPORTUNITY,
],
];
private const string UNSUPPORTED_OBJECT_TYPE = 'unsupported';
private const string OPPORTUNITY_STATUS_OPEN = 'Open';
private const string OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE = 'Opportunity import failed';
private const string RESOURCE_UPDATE_FAILED_ERROR_MESSAGE = 'Failed to update resource';
private FieldValueConverter $fieldValueConverter;
private ClientFactory $clientFactory;
private ?Client $copperClient = null;
public function __construct(
ClientFactory $clientFactory,
FieldValueConverter $fieldValueConverter,
private readonly UserRepository $userRepository,
private readonly ProspectPhotoPathService $prospectPhotoPathService,
private readonly CrmEntityRepository $crmEntityRepository
) {
parent::__construct();
$this->clientFactory = $clientFactory;
$this->fieldValueConverter = $fieldValueConverter;
}
public function getDisplayName(): string
{
return 'Copper';
}
/**
* Get the CRM entity repository (used by SearchesCrmEntities trait)
*/
protected function getCrmEntityRepository(): CrmEntityRepository
{
return $this->crmEntityRepository;
}
public function getMinimumApiVersion(): string
{
return Client::MIN_API_VERSION;
}
protected function getOAuthAccount(User $user): ?SocialAccount
{
// In this case, the Account Owner is always the connection for any API operations.
$owner = $user->team->owner;
return $owner->getSocialAccount(SocialAccount::PROVIDER_COPPER);
}
public function setUser(User $user): void
{
$this->configureSentryScope($user);
$this->team = $user->getTeam();
$this->teamService->setTeam($user->getTeam());
$this->setConfiguration($user->getTeam()->getCrmConfiguration());
// Reset state.
$this->profile = $user->getProfile();
if (! $this->profile instanceof Profile) {
// Try to fetch their profile, maybe it was not yet imported?
$this->profile = $this->getProfile($user);
}
}
public function setConfiguration(Configuration $configuration): void
{
$this->config = $configuration;
$this->copperClient = $this->clientFactory->create($configuration);
if ($this->team === null) {
$this->team = $configuration->getTeam();
}
}
public function normalizeValue(string $fieldType, string $fieldValue, bool $internal = false): string
{
return $this->fieldValueConverter->convertFromCrm($fieldType, $fieldValue);
}
private function mapObjectType(string $objectType): string
{
$objectType = strtolower($objectType);
switch ($objectType) {
case Field::OBJECT_TASK:
case Field::OBJECT_OPPORTUNITY:
case Field::OBJECT_LEAD:
$mappedType = $objectType;
break;
case Field::OBJECT_ACCOUNT:
$mappedType = 'company';
break;
case Field::OBJECT_CONTACT:
$mappedType = 'person';
break;
default:
$mappedType = self::UNSUPPORTED_OBJECT_TYPE;
break;
}
return $mappedType;
}
/**
* @param string $crmObject The name of the CRM object. i.e. Opportunity or Contact
*/
protected function getFields(string $crmObject): array
{
$mappedObjectType = $this->mapObjectType($crmObject);
if (! $this->isSupportedObjectType($mappedObjectType)) {
return [];
}
$customFields = $this->copperClient->fields()->all();
$filteredFields = array_filter(
$customFields,
static fn ($field) => in_array($mappedObjectType, $field['available_on'], true)
);
return array_map(
fn (array $property) => [
'name' => $property['id'],
'label' => $property['name'],
'type' => $this->convertFieldType($property['data_type']),
],
$filteredFields
);
}
/**
* @inheritdoc
*/
public function getDefaultFields(string $activityType): array
{
$fields = [];
if ($activityType === Playbook::ACTIVITY_TYPE_TASK) {
$defaultFields = FieldDefinitions::defaultTaskFields();
// This lazy creates these fields if not already setup.
foreach ($defaultFields as $defaultField) {
$fields[] = $this->config->fields()->firstOrCreate($defaultField);
}
}
return $fields;
}
/**
* @inheritdoc
*/
public function getDefaultActivityField(string $activityType): Field
{
// Setup the activity field as the default Type.
$activityField = $this->config->fields()->where([
'crm_provider_id' => 'type',
'object_type' => $activityType,
])->first();
return $activityField;
}
/**
* @inheritdoc
*/
public function getSupportedPlaybookTypes(): array
{
return [Playbook::ACTIVITY_TYPE_TASK];
}
public function getDealInsightsFields(): array
{
return FieldDefinitions::dealInsightsFields();
}
protected function getDefaultFollowupLayoutFields(string $activityType): array
{
$fields = [];
$fieldRepo = app(FieldRepository::class);
$fieldFilters = FieldDefinitions::taskFollowupFieldsFilter();
foreach ($fieldFilters as $data) {
$field = $fieldRepo->findOneConfigurationFieldByProperties($this->config, $data);
// Only add the field if it is created, which it should be.
if ($field) {
$fields[] = $field;
}
}
return $fields;
}
public function syncFields(): void
{
$this->syncStandardFields();
$this->syncCustomFields();
}
public function syncField(Field $field): void
{
if ($field->getCrmProviderId() === 'type') {
/**
* This field is a special case, it is not a custom field and is not returned by the Copper API.
*
* The field is created manually during layout setup.
*
* @see getDefaultFields()
*
* There is a separate endpoint to get the activity types.
* @see importPicklistValues()
*/
return;
}
if ($field->getCrmProviderId() === 'pipeline_stage_id') {
// Not a custom type
return;
}
$crmField = $this->copperClient->fields()->find($field->getCrmProviderId());
$field->label = $crmField['name'];
$field->type = $this->convertFieldType($crmField['data_type']);
$field->save();
}
/**
* @param string $fieldType How the data should be input
*/
private function convertFieldType(string $fieldType): string
{
$fieldType = strtolower($fieldType);
switch ($fieldType) {
case 'dropdown':
$convertedType = Field::TYPE_PICKLIST;
break;
case 'string':
$convertedType = Field::TYPE_TEXT;
break;
case 'float':
case 'percentage':
$convertedType = Field::TYPE_NUMBER;
break;
case 'text':
$convertedType = Field::TYPE_TEXTAREA;
break;
case 'checkbox':
$convertedType = Field::TYPE_BOOLEAN;
break;
case Field::TYPE_DATE:
case Field::TYPE_CURRENCY:
case Field::TYPE_URL:
$convertedType = $fieldType;
break;
default:
$convertedType = Field::TYPE_UNSUPPORTED;
break;
}
return $convertedType;
}
/**
* @inheritdoc
*/
public function importPicklistValues(Field $field): array
{
$fieldValues = [];
if ($field->object_type === 'opportunity' && $field->crm_provider_id === 'pipeline_stage_id') {
return $this->importFieldValuesForDealInsights($field);
}
$values = [];
if ($field->object_type === Field::OBJECT_TASK && $field->crm_provider_id === 'type') {
$activityTypes = $this->copperClient->activityTypes()->all();
/**
* We ignore "system" activity types, disabled activity types and the "Note" activity type.
*/
$activityTypes = array_filter(
$activityTypes['user'],
fn (array $activityType) => ! $activityType['is_disabled'] && $activityType['id'] !== 0
);
// Import all activity values.
$i = 0;
foreach ($activityTypes as $activityType) {
$values[] = [
'value' => $activityType['id'],
'label' => mb_strimwidth($activityType['name'], 0, Field::LABEL_MAX_LENGTH),
'sequence' => $i++,
];
}
} else {
// We just check for the field in the custom definitions.
$crmField = $this->copperClient->fields()->find($field->crm_provider_id);
// Import all values.
foreach ($crmField['options'] as $option) {
$values[] = [
'value' => $option['id'],
'label' => mb_strimwidth($option['name'], 0, 191),
'sequence' => $option['rank'],
];
}
}
// Take the existing set of field values.
$fieldsToPurge = $field->values()->get()->pluck('value')->toArray();
foreach ($values as $value) {
// For all current values, upsert the field.
$value['value'] = substr($value['value'] ?? '', 0, 255);
$fieldValues[] = $field->values()->updateOrCreate([
'value' => $value['value'],
], $value);
// Remove this value from the ones we are going to purge.
$key = array_search($value['value'], $fieldsToPurge, false);
if ($key !== false) {
unset($fieldsToPurge[$key]);
}
}
// Delete the old values that are no longer used.
$field->values()->whereIn('value', $fieldsToPurge)->delete();
return $fieldValues;
}
/**
*
* @return FieldValue[]
*/
private function importFieldValuesForDealInsights(Field $field): array
{
$fieldValues = [];
$pipelines = $this->copperClient->pipelines()->all();
foreach ($pipelines as $pipeline) {
foreach ($pipeline['stages'] as $i => $dealStage) {
$fieldValues[] = $field->values()->updateOrCreate(
['value' => $dealStage['id']],
[
'label' => $dealStage['name'],
'sequence' => $i,
]
);
}
}
return $fieldValues;
}
/**
* @inheritdoc
*/
public function importStages(?array $types = null, ?string $missingStageName = null): ?Stage
{
if ($types === null) {
$types = [Stage::TYPE_LEAD, Stage::TYPE_OPPORTUNITY];
}
$missingStage = null;
foreach ($types as $type) {
if ($type === Stage::TYPE_LEAD) {
$statuses = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leadStatuses()->all()
);
if (count($statuses) > 0) {
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => BusinessProcess::TYPE_LEAD,
], [
'team_id' => $this->team->id,
'name' => BusinessProcess::TYPE_LEAD,
'type' => BusinessProcess::TYPE_LEAD,
'is_selectable' => true,
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => BusinessProcess::TYPE_LEAD,
], [
'team_id' => $this->team->id,
'name' => BusinessProcess::TYPE_LEAD,
'is_selectable' => true,
'business_process_id' => $businessProcess->id ?? null,
]);
$leadStatuses = [];
foreach ($statuses as $status) {
// Upsert all statuses for the team.
$status = $this->config->stages()->updateOrCreate([
'crm_provider_id' => $status['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($status['name'], 0, 50),
'label' => mb_strimwidth($status['name'], 0, 191),
'type' => Stage::TYPE_LEAD,
'sequence' => $status['order'],
'is_selectable' => true,
]);
if ($missingStageName && $missingStageName === $status['id']) {
$missingStage = $status;
}
$leadStatuses[] = $status['id'];
}
$businessProcess->stages()->sync($leadStatuses);
}
} else {
// We create a business process to contain the pipeline, and later store all stages against it.
foreach ($this->copperClient->pipelines()->all() as $pipeline) {
$businessProcess = $this->config->businessProcesses()->updateOrCreate([
'crm_provider_id' => $pipeline['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($pipeline['name'], 0, 150),
'type' => BusinessProcess::TYPE_OPPORTUNITY,
'is_selectable' => true,
]);
// A record type is really a clone of the business process, used to store which record uses which pipeline.
$this->config->recordTypes()->updateOrCreate([
'crm_provider_id' => $pipeline['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($pipeline['name'], 0, 150),
'is_selectable' => true,
'business_process_id' => $businessProcess->id ?? null,
]);
$stages = [];
foreach ($pipeline['stages'] as $i => $dealStage) {
// Upsert all stages for the team.
$stage = $this->config->stages()->updateOrCreate([
'crm_provider_id' => $dealStage['id'],
], [
'team_id' => $this->team->id,
'name' => mb_strimwidth($dealStage['name'], 0, 50),
'label' => mb_strimwidth($dealStage['name'], 0, 191),
'type' => Stage::TYPE_OPPORTUNITY,
'sequence' => $i,
'is_selectable' => true,
'probability' => $dealStage['win_probability'],
]);
if ($missingStageName && $missingStageName === $dealStage['id']) {
$missingStage = $stage;
}
$stages[] = $stage['id'];
}
$businessProcess->stages()->sync($stages);
}
}
}
return $missingStage;
}
/**
* @inheritdoc
*/
public function syncLeads(Carbon $since, ?Carbon $to = null, ?string $crmProfileId = null): int
{
$syncCount = 0;
$cpLeads = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->paginate([
'minimum_modified_date' => $since->timestamp,
'sort_by' => 'date_modified',
])
);
foreach ($cpLeads as $cpLead) {
// Only sync if previously imported.
if ($this->hasLead($cpLead['id']) === false) {
$this->importLead($cpLead);
$syncCount++;
}
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncLead(string $crmId): ?Lead
{
$cpLead = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->find($crmId)
);
if (\count($cpLead) === 0) {
return null;
}
return $this->importLead($cpLead);
}
/**
* @inheritdoc
*/
private function importLead($crmData): ?Lead
{
$countryCode = null;
if (! empty($crmData['address']) && isset($crmData['address']['country'])) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$mobilePhone = $parsedNumber = null;
if (! empty($crmData['phone_numbers'])) {
foreach ($crmData['phone_numbers'] as $phoneNumber) {
if ($phoneNumber['category'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);
} else {
$parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);
}
}
}
$name = $crmData['name'];
if (empty($crmData['company_name'])) {
$company = 'Unknown';
} else {
$company = mb_strimwidth($crmData['company_name'], 0, 191);
}
$domain = null;
if (empty($crmData['websites']) === false) {
$domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);
$domain = StringUtil::resolveDomain($domain);
}
$email = null;
if (empty($crmData['email']) === false) {
$email = mb_strimwidth($crmData['email']['email'], 0, 80);
}
$stage = $this->config
->stages()
->where('crm_provider_id', (string) $crmData['status_id'])
->where('type', Stage::TYPE_LEAD)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_LEAD], $crmData['status_id']);
}
if (! $stage instanceof Stage) {
return null;
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($name, 0, 191),
'company' => $company,
'domain' => $domain,
'title' => $crmData['title'] ? mb_strimwidth($crmData['title'], 0, 128) : null,
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'mobile_phone' => $mobilePhone,
'stage_id' => $stage->id,
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Lead::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'country_code' => $countryCode,
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->leads()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
/**
* @inheritdoc
*/
public function syncAccounts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
$cpAccounts = $this->copperClient->accounts()->paginate([
'minimum_modified_date' => $since->timestamp,
'sort_by' => 'date_modified',
]);
foreach ($cpAccounts as $cpAccount) {
// Only sync if previously imported.
if ($this->hasAccount($cpAccount['id'])) {
$this->importAccount($cpAccount);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncAccount(string $crmId): ?Account
{
$cpAccount = $this->copperClient->accounts()->find($crmId);
if (empty($cpAccount)) {
return null;
}
return $this->importAccount($cpAccount);
}
/**
* @inheritdoc
*/
private function importAccount($crmData): Account
{
$countryCode = null;
if (empty($crmData['address']) === false && $crmData['address']['country']) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$name = $crmData['name'];
$parsedNumber = null;
foreach ($crmData['phone_numbers'] as $phoneNumber) {
$parsedNumber = parsePhoneNumber($countryCode, $phoneNumber['number']);
}
$domain = null;
if (empty($crmData['websites']) === false) {
$domain = mb_strimwidth($crmData['websites'][0]['url'], 0, 191);
$domain = StringUtil::resolveDomain($domain);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($name, 0, 191),
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Account::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'country_code' => $countryCode,
'domain' => $domain,
'phone' => $parsedNumber['phone'] ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->accounts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
public function syncOpportunities(array $parameters, ?string $strategy = null): int
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->copperClient,
]);
$strategies = $strategyResolver->getStrategies($this->config, $strategy);
$syncCount = 0;
try {
foreach ($strategies as $syncStrategy) {
foreach ($syncStrategy->fetchOpportunities($parameters) as $opportunityData) {
$this->importOpportunity($opportunityData);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
$this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => $exception->getMessage(),
]);
}
return $syncCount;
}
public function syncOpportunity(string $crmId): ?Opportunity
{
$strategyResolver = app(OpportunitySyncStrategyResolver::class, [
'client' => $this->copperClient,
]);
$strategy = $strategyResolver->resolve(
$this->config,
OpportunitySyncStrategyResolver::SINGLE_SYNC_OPPORTUNITY_STRATEGY
);
$parameters['crm_id'] = $crmId;
$cpOpportunity = $strategy->fetchOpportunities($parameters);
return $this->importOpportunity($cpOpportunity);
}
private function importOpportunity($crmData): ?Opportunity
{
$companyId = (string) $crmData['company_id'];
if (empty($companyId)) {
$this->logger->error(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => 'No company id',
]);
return null;
}
$account = $this->config->accounts()->where('crm_provider_id', $companyId)->first();
if ($account === null) {
$account = $this->syncAccount($companyId);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', (string) $crmData['pipeline_id'])
->first();
if ($businessProcess === null) {
// It is possible for some deals to not be in a pipeline.
$this->logger->warning(self::OPPORTUNITY_IMPORT_FAILED_ERROR_MESSAGE, [
'error' => 'Missing pipeline',
]);
return null;
}
$stage = $businessProcess
->stages()
->where('crm_provider_id', (string) $crmData['pipeline_stage_id'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
$this->logger->info('Stage not found, importing', [
'pipeline_id' => $crmData['pipeline_id'],
'stage_id' => $crmData['pipeline_stage_id'],
]);
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $crmData['pipeline_stage_id']);
}
$recordType = $businessProcess->recordTypes()->first();
$closeDate = null;
$isClosed = $crmData['status'] !== self::OPPORTUNITY_STATUS_OPEN;
if ($crmData['close_date']) {
$closeDate = Carbon::parse($crmData['close_date'])->format('Y-m-d');
}
$data = [
'team_id' => $this->team->getId(),
'account_id' => $account->id,
'user_id' => $profile->user_id ?? null,
'owner_id' => $crmData['assignee_id'],
'name' => mb_strimwidth($crmData['name'], 0, 128),
'value' => $crmData['monetary_value'],
'currency_code' => CurrencyFormatter::formatCode($crmData['monetary_unit']),
'close_date' => $closeDate,
'is_closed' => $isClosed,
'is_won' => $crmData['status'] === 'Won',
'stage_id' => $stage->id,
'record_type_id' => $recordType->id ?? null,
'remotely_created_at' => $crmData['date_created'],
];
/** @var Opportunity $opportunity */
$opportunity = $this->config
->opportunities()
->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data)
;
// import external fields into crm_field_data if present
$dealInsightsFields = $this->getOpportunitySyncableFields();
$this->importOpportunityCrmFieldData($crmData, $dealInsightsFields, $opportunity->id);
return $opportunity;
}
/**
* @param array<string, mixed> $opportunityData
* @param string[] $dealInsightsFields
*/
public function importOpportunityCrmFieldData(
array $opportunityData,
array $dealInsightsFields,
int $opportunityId
): void {
foreach ($dealInsightsFields as $fieldName) {
$field = $this->config->fields()->with('entities')
->where('crm_provider_id', $fieldName)
->where('object_type', Field::OBJECT_OPPORTUNITY)
->first();
if (! $field instanceof Field) {
$this->logger->warning('Field not found', [
'field' => $fieldName,
'opportunity_id' => $opportunityId,
]);
continue;
}
$entity = $field->getEntities()->first();
if (! $entity instanceof LayoutEntity) {
continue;
}
$fieldValue = $this->extractFieldValue($opportunityData, $fieldName);
$normalizedValue = $this->normalizeValue($field->getType(), (string) $fieldValue, true);
$field->data()
->updateOrCreate([
'crm_layout_entity_id' => $entity->id,
'crm_field_id' => $field->id,
'object_type' => 'opportunity',
'object_id' => $opportunityId,
], ['value' => $normalizedValue])
;
}
}
/**
* @inheritdoc
*/
public function syncContacts(Carbon $since, ?Carbon $to = null): int
{
$syncCount = 0;
try {
$cpContacts = $this->copperClient->contacts()->paginate([
'minimum_interaction_date' => $since->timestamp,
'sort_by' => 'date_modified',
]);
foreach ($cpContacts as $cpContact) {
// Only sync if previously imported.
if ($this->hasContact($cpContact['id'])) {
$this->importContact($cpContact);
$syncCount++;
}
}
} catch (\Exception $exception) {
// Do nothing for now.
throw $exception;
}
return $syncCount;
}
/**
* @inheritdoc
*/
public function syncContact(string $crmId): ?Contact
{
$cpContact = $this->copperClient->contacts()->find($crmId);
if (empty($cpContact)) {
return null;
}
return $this->importContact($cpContact);
}
/**
* @inheritdoc
*/
private function importContact($crmData): Contact
{
$account = null;
if ($crmData['company_id']) {
$account = $this->team
->crm
->accounts()
->where('crm_provider_id', (string) $crmData['company_id'])
->first();
if ($account === null) {
$account = $this->syncAccount($crmData['company_id']);
}
}
$countryCode = null;
if (empty($crmData['address']) === false && $crmData['address']['country']) {
$countryCode = $this->convertCountryNameToCode($crmData['address']['country']);
}
$mobilePhone = $parsedNumber = null;
foreach ($crmData['phone_numbers'] as $phoneNumber) {
if ($phoneNumber['category'] === 'mobile') {
$mobilePhone = $this->buildContactMobilePhone($countryCode, $phoneNumber['number']);
} else {
$parsedNumber = $this->buildContactPhone($countryCode, $phoneNumber['number']);
}
}
$email = null;
if (empty($crmData['emails']) === false) {
$email = mb_strimwidth($crmData['emails'][0]['email'], 0, 80);
}
$profile = $this->config->profiles()->where('crm_provider_id', (string) $crmData['assignee_id'])->first();
$data = [
'team_id' => $this->team->id,
'account_id' => $account->id ?? null,
'user_id' => $profile ? $profile->user_id : null,
'owner_id' => $crmData['assignee_id'],
'name' => $crmData['name'],
'email' => $email,
'phone' => $parsedNumber['phone'] ?? null,
'mobile_phone' => $mobilePhone ?? null,
'ext' => $parsedNumber['ext'] ?? null,
'title' => $crmData['title'],
'country_code' => $countryCode,
'photo_path' => $this->prospectPhotoPathService->getOrGeneratePhotoPath(
crmConfiguration: $this->config,
crmProviderId: $crmData['id'],
modelType: Contact::class,
fileName: $crmData['id'],
avatarText: $crmData['name']
),
'remotely_created_at' => $crmData['date_created'],
];
return $this->config->contacts()->updateOrCreate(['crm_provider_id' => (string) $crmData['id']], $data);
}
private function buildContactPhone(?string $countryCode, ?string $number): ?array
{
if ($number) {
// Trim to our width and attempt to parse it.
$number = mb_strimwidth($number, 0, 25);
$parsedNumber = parsePhoneNumber($countryCode, $number);
} else {
$parsedNumber = [];
}
return $parsedNumber;
}
private function buildContactMobilePhone(?string $countryCode, ?string $number): ?string
{
return $number ? mb_strimwidth(phone_e164($countryCode, $number), 0, 25) : null;
}
/**
* @inheritdoc
*/
public function syncOrganization(): void
{
$organization = $this->copperClient->organisation()->all();
if ($this->config->crm_provider_id !== $organization['id']) {
$this->config->update(['crm_provider_id' => $organization['id']]);
}
}
private function syncCustomFields(): void
{
foreach ($this->getFieldTypes() as $fieldType) {
$currentFields = $this->getFields($fieldType);
foreach ($currentFields as $field) {
/** @var Field $field */
$field = $this->config->fields()->updateOrCreate([
'crm_provider_id' => $field['name'],
'object_type' => $fieldType,
], [
'label' => mb_strimwidth($field['label'], 0, Field::LABEL_MAX_LENGTH),
'type' => $field['type'],
]);
if ($field->getType() === Field::TYPE_PICKLIST) {
$this->importPicklistValues($field);
}
}
}
$this->config->save();
}
protected function getFieldTypes(): array
{
return [
parent::OBJECT_TASK,
parent::OBJECT_LEAD,
parent::OBJECT_ACCOUNT,
parent::OBJECT_CONTACT,
parent::OBJECT_OPPORTUNITY,
];
}
/**
* @inheritdoc
*/
public function syncProfiles(?User $userToSearch = null): ?Profile
{
$profiles = $this->copperClient->users()->all();
foreach ($profiles as $profile) {
$user = $this->userRepository->findByTeamAndEmailAddress($this->team, $profile['email'], onlyActive: true);
// Only import profiles for users we have locally.
if ($user) {
$profile = $user->crmProfile()->updateOrCreate([
'crm_configuration_id' => $this->config->id,
'crm_provider_id' => $profile['id'],
]);
if ($userToSearch && $userToSearch->id === $user->id) {
return $profile;
}
}
}
return null;
}
/**
* @inheritdoc
*/
public function syncProfileFields(): void
{
$fieldTypes = [
'task',
'lead',
'account',
'contact',
'opportunity',
];
foreach ($fieldTypes as $fieldType) {
try {
$currentFields = $this->getFields(ucfirst($fieldType));
$newFields = array_column($currentFields, 'name');
$changedFields = array_merge(
array_diff($this->profile->getFieldsAsArray($fieldType), $newFields),
array_diff($newFields, $this->profile->getFieldsAsArray($fieldType))
);
if (\count($changedFields) > 0) {
$fields = implode(',', $newFields);
$this->logger->debug(
ucfirst($fieldType)
. ' fields changed from '
. $this->profile->{$fieldType . '_fields'}
. ' to: '
. $fields
);
$this->profile->{$fieldType . '_fields'} = $fields;
}
} catch (\Exception $exception) {
$this->logger->error('No access to ' . $fieldType . ' object, skipping...');
continue;
}
}
$this->profile->save();
}
/**
* @inheritdoc
*/
public function find(string $name, array $scopes): array
{
$count = $this->limit ?? 20;
$offset = $this->offset ?? 0;
$scopeValues = array_map(fn ($scope) => is_string($scope) ? $scope : $scope->value, $scopes);
$cacheKey = sprintf('copper-search-%d-%s-%s-%d-%d', $this->team->id, $name, implode('-', $scopeValues), $count, $offset);
return Cache::remember($cacheKey, 300, function () use ($name, $scopes, $count, $offset) {
// Try local search first
$localResults = $this->searchLocally($name, $scopes, $count, $offset);
// If no local results, fall back to remote API search
if (empty($localResults)) {
return $this->searchRemotely($name, $scopes, $count, $offset);
}
return $localResults;
});
}
/**
* @inheritdoc
*/
public function findOpportunities(?string $crmAccountId, ?string $crmContactId, ?int $userId = null): array
{
$data = [];
$ownerData = [];
$ownerId = null;
$contact = null;
$account = null;
if ($crmAccountId) {
$account = $this->config->accounts()->where('crm_provider_id', $crmAccountId)->first();
if ($account === null) {
$account = $this->syncAccount($crmAccountId);
}
}
if ($crmContactId) {
$contact = $this->config->contacts()->where('crm_provider_id', $crmContactId)->first();
if ($contact === null) {
$contact = $this->syncContact($crmContactId);
}
}
if ($contact || $account) {
if ($contact && $account === null) {
$account = $contact->account;
}
if ($account === null) {
return [];
}
$params = [
'company_ids' => [$account->crm_provider_id],
'status_ids' => [0], // The integer values are 0, 1, 2, 3, for "Open", "Won", "Lost", and "Abandoned".
'sort_by' => 'date_modified',
'sort_direction' => 'desc',
];
switch ($this->config->opportunity_assignment_rule) {
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_UPDATED:
$params['sort_by'] = 'date_modified';
$params['sort_direction'] = 'desc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_RECENTLY_CREATED:
$params['sort_by'] = 'date_created';
$params['sort_direction'] = 'desc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_OPEN_OLDEST_CREATED:
$params['sort_by'] = 'date_created';
$params['sort_direction'] = 'asc';
break;
case Configuration::OPP_ASSIGNMENT_ALL_RECENTLY_UPDATED:
$params['sort_by'] = 'date_modified';
$params['sort_direction'] = 'desc';
$params['status_ids'] = [0, 1, 2, 3];
}
$cpOpportunities = $this->copperClient->opportunities()->search($params);
if ($userId) {
$profileRepository = app(ProfileRepository::class);
$profile = $profileRepository->findProfileByUserId($this->config, $userId);
$ownerId = $profile instanceof Profile ? $profile->getCrmProviderId() : null;
}
foreach ($cpOpportunities as $cpOpportunity) {
$businessProcess = $this->config
->businessProcesses()
->where('crm_provider_id', (string) $cpOpportunity['pipeline_id'])
->first();
if ($businessProcess === null) {
// Import it.
$businessProcess = $this->importStages(
[Stage::TYPE_OPPORTUNITY],
$cpOpportunity['pipeline_stage_id']
);
}
$stage = $businessProcess
->stages()
->where('crm_provider_id', (string) $cpOpportunity['pipeline_stage_id'])
->where('type', Stage::TYPE_OPPORTUNITY)
->first();
if ($stage === null) {
// Import it.
$stage = $this->importStages([Stage::TYPE_OPPORTUNITY], $cpOpportunity['pipeline_stage_id']);
}
$recordType = $businessProcess->recordTypes()->first();
$record = [
'crmId' => $cpOpportunity['id'],
'name' => $cpOpportunity['name'],
'value' => currency_format($cpOpportunity['monetary_value'], $cpOpportunity['monetary_unit']),
'won' => $cpOpportunity['status'] === 'Won',
'stage' => [
'id' => $stage->id_string,
'name' => $stage->name,
],
'recordType' => [
'id' => $recordType->id_string,
'name' => $recordType->name,
],
];
if ($ownerId && isset($cpOpportunity['assignee_id']) && $cpOpportunity['assignee_id'] === $ownerId) {
$ownerData[] = $record;
}
$data[] = $record;
}
}
if (! empty($ownerData)) {
return $ownerData;
}
return $data;
}
/**
* @inheritdoc
*/
public function getTasks(string $objectType, string $objectId, ?string $opportunityId): array
{
$data = $cpTasks = [];
switch ($objectType) {
case 'lead':
$cpTasks = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->relatedTasks($objectId)
);
break;
case 'account':
$cpTasks = $this->copperClient->accounts()->relatedTasks($objectId);
break;
case 'contact':
if ($opportunityId) {
$cpTasks = $this->copperClient->opportunities()->relatedTasks($opportunityId);
} elseif ($objectType === 'contact') {
$cpTasks = $this->copperClient->contacts()->relatedTasks($objectId);
}
break;
}
foreach ($cpTasks as $cpTask) {
// We only get the ID itself returned, so pull out the full object.
try {
$cpTask = $this->copperClient->tasks()->find($cpTask['id']);
} catch (Exception $exception) {
$this->logger->error('[Copper] Error fetching task', [
'resource_id' => $cpTask['id'],
'error' => $exception->getMessage(),
]);
continue;
}
// Only allow open tasks.
if ($cpTask['status'] === 'Open') {
$data[] = [
'crmId' => $cpTask['id'],
'subject' => $cpTask['name'],
'due' => $cpTask['due_date']
? Carbon::createFromTimestamp($cpTask['due_date'])->format('Y-m-d\TH:i:sO')
: null,
'type' => null,
];
}
}
return $data;
}
/**
* Try to find email address in CRM service
*
* @return null|array{
* Lead|null,
* Account|null,
* Opportunity|null,
* Contact|null,
* Stage|null,
* string|null
*}
*/
public function matchExactlyByEmail(string $email, ?int $userId = null): ?array
{
$cpObjectType = 'contact';
$cpObjects = $this->copperClient->contacts()->search([
'emails' => $email,
'sort_by' => 'date_modified',
'sort_direction' => 'desc',
]);
if (empty($cpObjects)) {
$cpObjectType = 'lead';
$cpObjects = $this->requestWithExceptionHandling(
fn () => $this->copperClient->leads()->search([
'emails' => $email,
'sort_by' => 'date_...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
53265
|
1871
|
3
|
2026-05-18T11:59:57.128610+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779105597128_m2.jpg...
|
PhpStorm
|
faVsco.js – Constants.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormVIeWINavigarecodeLaravelKeractorFV faVsco. PhostormVIeWINavigarecodeLaravelKeractorFV faVsco.js°9 master kProiectC ActivityController.ongC BaseService.onp© GroupPatchOperation.php(C) CoreUserRequest.onpo seimrrovisionine.onp© CoreUser.phpc userratchoperation.onCc) RoleAttrTest.png@ scimintenace.onpC 1extwessagingservice.phpscimprovisioning.pnpclass constantsw seederPUDLIC COnST JIELA UPEKATLUNS AUy = 'a00')D Sentnno usadesW Serializerpublic const MELA OPERATLONS ADD.UPPER = "Add';settingsno usagesW Sidekickpublic const MELA OPERATLONS REMOVE,UPPER = 'Remove";l TlimeMemorvMaooer17 TranscriotionSummarvm Twilidv N Conference• M ConferenceHandlerv ConferenceManager© SoftPhoneManager.php© ConferenceCallbackHandler.php© ConferenceManager.php>MDTOTM EventTh SycentionD Jobm Docolvor07 ServicecTwilloconstants.php© TwilioRepository.phpC Uploadernubilic const META VALlE ='valuel:0 UrlGeneratornublic const META OPERATTONS = "Onerations'.a UtilityaUuidpublic const META_OP = 'op';Waveform_ Webhookspublic const META RESOURCE TYPE = 'resourceType';Workflow> 2 Confiqurationpublic const META CREATED = 'created';v D Consolev MCommandspublic const META LAST MODIFIED = 'lastModified':> M Activities> M Analvticcpublic const META FORMATTED = 'formatted':TM Calendarsv MCrmpublic const META EMAILS = 'emails':M Huhsnot> D IntegrationApppubLic const MElA USEkNANE = "UserName'")M Traitee Addl awoutEntitios nhnpublic const META_ NAME = 'name':© AutoloqDelayedCommand.php© BackfillOpportunityUserFromAccount/ 64public const Methoffeditg . Accept File s-X Reject File 4%g+ 2 of 8 files →rectored Il Pollback II Confiaure (40 minutes aao)=custom.log= laravel.logA SF [jiminny@localhost]4 HS_local [jiminny@localhost]& console [PROD]& console [EU]A console [STAGING] X555_55¢— 558— 559-561— 561581F583584585≤586- 59Tx: AutovPlavaroundGo jiminny_jupiter019 A19 V17 ^select * from teamsSELECT r.* FROM automated_reports rioin teams t on r.team id = t.idWHERE r.frequency = 'daily'and r.status = 1AND t.status = 'activeAND (r.expires_at >= now OR r.expires_ at IS NULL);select * from automated_report_results where report id IN (18, 33):select * from users where team_id = 1 and id = 1047;SELECT * FROM social_accounts WHERE sociable_id = 1047;select * from activity searches where id = 10932select * from activity search_filters where activity search_id = 10932select * fromselect * fromresults order by 1d descselect * from automated reports where id IN (55)esults where id IN (81):select * from users where id IN (10633. 13987, 11985)select * from users where aroup id IN (3710):SELECT * FROMautomated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;SELECT * FROM automated report_ results WHERE uuid to_ bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;select * from teams,select * fron accounts where team id = 1:select * from automated_report_results where media tyRe = 'pdf' and status = 2;SELECT * EROMWHERE uuid_to_bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid;select * from teams where id = 1029;select * from crm_configurations where provider = 'pipedrive';SELSCTCONCAT(u.id, CASE WHEN u.id = t.owner_id THEN' (owner)' ELSE '' END) AS user_id,nomailsa.*,t.owner id FROM social accounts saJOIN users u on u.id = sa.sociable ioIOTM +oome + 1 ne-s1: on + id e m toom ¿dWHEPE n.tean id = 1029 and sa.provider = 'pipedrive':"user id". "23460 (owner)""[EMAIL]""id": 69• suppont Dally • In 1m100% 1• Mon 18 May 14:59:56AskJiminnyReportActivityServiceTest vCascadeImplement Trial OwneFixing Redis Rate LimSalestorce Token FalliSCIM Role Manageme+0 ..inp on LineWARN Metadata found iin doc-comment for method9/ 10 tacke doneWrite unit tests for SCIM role management10) Contact Mario to vodate customer10 / 10 tasks doneselm role managementtor leamtallor has been successtully implemented. Here's what was completed:Implementation Summary:1. CoreUserRequest DTO - Added role parsina from SCIM requests2. SCIM Constants - Added META ROLES and USER_PATCH_ATTR_ ROLES constants3. RoleAttr Mutator - Created mutator for handlina role assianments via SCIM PATCH operations4. ScimProvisioning - Updated to handle roles during user creation with proper validation5. ListenerRoleCannotHaveAdminOrManagerPermissionRule - Created validation rule to prevent listener role fromhaving admin/manager permissions6. CoreUser Response - Updated to include roles in SClM responses7. Unit Tests - Created comprehensive tests for the validation ruleKey Features:• Customers can now assign roles via SCIM (recorder, recorder & voice, analyst, listener, admin, manager)• Validation ensures listener role is onlv assianable if the LISTENER ROLE feature flaa is enabledl•LIstener role cannot de comolned with aamin or manager permissions• Uses existing UpdateUserRolesAction for role syncing and logging• Follows platform validation rules (DependentRolesRule, ListenerRoleRequiresListenerFeatureRule)Next Step: Please contact Mario to update the customer that SCIM role management is now available for Teamtailorintearationapp/Component/SClM/ Constants.php +3app/Component/SCIM/ ® ScimProvisioning.php +85-15nse/ CoreUser.php +21ec/lserlẞ PoleAtrnhn 117'app/DTO/SCIM/AAD/Request/CoreUserRequest.phpr/PoleAttrTect.nhn +224* Reiect allAccent alliAsk anvthina 884-L)« Code SWF-1.6W Windsurf Teams 1:1 UTF-8io 4 spaces...
|
NULL
|
-8277940583930417123
|
NULL
|
click
|
ocr
|
NULL
|
PhostormVIeWINavigarecodeLaravelKeractorFV faVsco. PhostormVIeWINavigarecodeLaravelKeractorFV faVsco.js°9 master kProiectC ActivityController.ongC BaseService.onp© GroupPatchOperation.php(C) CoreUserRequest.onpo seimrrovisionine.onp© CoreUser.phpc userratchoperation.onCc) RoleAttrTest.png@ scimintenace.onpC 1extwessagingservice.phpscimprovisioning.pnpclass constantsw seederPUDLIC COnST JIELA UPEKATLUNS AUy = 'a00')D Sentnno usadesW Serializerpublic const MELA OPERATLONS ADD.UPPER = "Add';settingsno usagesW Sidekickpublic const MELA OPERATLONS REMOVE,UPPER = 'Remove";l TlimeMemorvMaooer17 TranscriotionSummarvm Twilidv N Conference• M ConferenceHandlerv ConferenceManager© SoftPhoneManager.php© ConferenceCallbackHandler.php© ConferenceManager.php>MDTOTM EventTh SycentionD Jobm Docolvor07 ServicecTwilloconstants.php© TwilioRepository.phpC Uploadernubilic const META VALlE ='valuel:0 UrlGeneratornublic const META OPERATTONS = "Onerations'.a UtilityaUuidpublic const META_OP = 'op';Waveform_ Webhookspublic const META RESOURCE TYPE = 'resourceType';Workflow> 2 Confiqurationpublic const META CREATED = 'created';v D Consolev MCommandspublic const META LAST MODIFIED = 'lastModified':> M Activities> M Analvticcpublic const META FORMATTED = 'formatted':TM Calendarsv MCrmpublic const META EMAILS = 'emails':M Huhsnot> D IntegrationApppubLic const MElA USEkNANE = "UserName'")M Traitee Addl awoutEntitios nhnpublic const META_ NAME = 'name':© AutoloqDelayedCommand.php© BackfillOpportunityUserFromAccount/ 64public const Methoffeditg . Accept File s-X Reject File 4%g+ 2 of 8 files →rectored Il Pollback II Confiaure (40 minutes aao)=custom.log= laravel.logA SF [jiminny@localhost]4 HS_local [jiminny@localhost]& console [PROD]& console [EU]A console [STAGING] X555_55¢— 558— 559-561— 561581F583584585≤586- 59Tx: AutovPlavaroundGo jiminny_jupiter019 A19 V17 ^select * from teamsSELECT r.* FROM automated_reports rioin teams t on r.team id = t.idWHERE r.frequency = 'daily'and r.status = 1AND t.status = 'activeAND (r.expires_at >= now OR r.expires_ at IS NULL);select * from automated_report_results where report id IN (18, 33):select * from users where team_id = 1 and id = 1047;SELECT * FROM social_accounts WHERE sociable_id = 1047;select * from activity searches where id = 10932select * from activity search_filters where activity search_id = 10932select * fromselect * fromresults order by 1d descselect * from automated reports where id IN (55)esults where id IN (81):select * from users where id IN (10633. 13987, 11985)select * from users where aroup id IN (3710):SELECT * FROMautomated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;SELECT * FROM automated report_ results WHERE uuid to_ bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;select * from teams,select * fron accounts where team id = 1:select * from automated_report_results where media tyRe = 'pdf' and status = 2;SELECT * EROMWHERE uuid_to_bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid;select * from teams where id = 1029;select * from crm_configurations where provider = 'pipedrive';SELSCTCONCAT(u.id, CASE WHEN u.id = t.owner_id THEN' (owner)' ELSE '' END) AS user_id,nomailsa.*,t.owner id FROM social accounts saJOIN users u on u.id = sa.sociable ioIOTM +oome + 1 ne-s1: on + id e m toom ¿dWHEPE n.tean id = 1029 and sa.provider = 'pipedrive':"user id". "23460 (owner)""[EMAIL]""id": 69• suppont Dally • In 1m100% 1• Mon 18 May 14:59:56AskJiminnyReportActivityServiceTest vCascadeImplement Trial OwneFixing Redis Rate LimSalestorce Token FalliSCIM Role Manageme+0 ..inp on LineWARN Metadata found iin doc-comment for method9/ 10 tacke doneWrite unit tests for SCIM role management10) Contact Mario to vodate customer10 / 10 tasks doneselm role managementtor leamtallor has been successtully implemented. Here's what was completed:Implementation Summary:1. CoreUserRequest DTO - Added role parsina from SCIM requests2. SCIM Constants - Added META ROLES and USER_PATCH_ATTR_ ROLES constants3. RoleAttr Mutator - Created mutator for handlina role assianments via SCIM PATCH operations4. ScimProvisioning - Updated to handle roles during user creation with proper validation5. ListenerRoleCannotHaveAdminOrManagerPermissionRule - Created validation rule to prevent listener role fromhaving admin/manager permissions6. CoreUser Response - Updated to include roles in SClM responses7. Unit Tests - Created comprehensive tests for the validation ruleKey Features:• Customers can now assign roles via SCIM (recorder, recorder & voice, analyst, listener, admin, manager)• Validation ensures listener role is onlv assianable if the LISTENER ROLE feature flaa is enabledl•LIstener role cannot de comolned with aamin or manager permissions• Uses existing UpdateUserRolesAction for role syncing and logging• Follows platform validation rules (DependentRolesRule, ListenerRoleRequiresListenerFeatureRule)Next Step: Please contact Mario to update the customer that SCIM role management is now available for Teamtailorintearationapp/Component/SClM/ Constants.php +3app/Component/SCIM/ ® ScimProvisioning.php +85-15nse/ CoreUser.php +21ec/lserlẞ PoleAtrnhn 117'app/DTO/SCIM/AAD/Request/CoreUserRequest.phpr/PoleAttrTect.nhn +224* Reiect allAccent alliAsk anvthina 884-L)« Code SWF-1.6W Windsurf Teams 1:1 UTF-8io 4 spaces...
|
53263
|
NULL
|
NULL
|
NULL
|
|
53264
|
1870
|
3
|
2026-05-18T11:59:57.084961+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779105597084_m1.jpg...
|
PhpStorm
|
faVsco.js – Constants.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpEUDOCKER881DEV SlackFileEditViewGoHistoryWindowHelpEUDOCKER881DEV (docker)782sticsearch""@timestamp":"2026-05-18T11:59:49Z" , "tags" : ["warning"connections"}{"type" : "log""@timestamp": "2026-05-18T11:59:49Z","tags" : ["warning""licensing"],"message" : "Licenseinformationcould not be obtained from ElasError: No Living connections1 {"type" : "log"."@timestamp": "2026-05-18T11:59:49Z", "tags": ["warning", "monitoring"], "pid" :7, "message" : "Unableconnection: [URL_WITH_CREDENTIALS] "tags" : ["warning", "elasticsearch", "monitoring"],"pid" :7,"message" : "Noliving connections"}kibana{"type" : "log""@timestamp":"2026-05-18T11:59:49Z"gins""licensing"],"tags" : ["warning"pid":7,"message": "License information could not be obtained from ElasticsearchduetoError:No Living connectionskibana{"type" : "log""@timestamp" : "2026-05-18T11:59:49Z", "tags" : ["error"icsearch","data"],pid":7,"message":"[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch: 9200"}kibana"@timestamp": "2026-05-18T11:59:51Z","tags": ["warning","elasticsearch", "data"], "pid":7, "message": "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T11:59:51Z", "tags" : ["warning"sticsearch", "data"],"pid":7,"message": "No living connections"}kibana1 {"type" : "log","@timestamp": "2026-05-18T11:59:51Z"ns", "tags" : ["error", "plugi, "taskManager""taskManager"], "pid" :7, "message" : "Failed to pollfor work: Error: No Living connections"}kibana1 {"'type": "log", "@timestamp" : "2026-05-18T11:59:52Z" ,"tags" : ["error""elasticsearch", "data"], "pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type" : "log", "@timestamp" : "2026-05-18T11:59:54Z".,"tags" : ["warning", "elasticsearch", "data"], "pid":7, "message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T11:59:547", "tags" : ["warning", "elasticsearch", "data"], "pid":7, "message" : "No living connections"}kibana1 {"type" : "log", "@timestamp" : "2026-05-18T11:59:54Z""tags": ["error"ns", "taskManager", "taskManager"],"pid" :7, "message": "Failed to poll for work: Error: No Living connections"}klbana1 {"type" : "log"!,"@timestamp" : "2026-05-18T11:59:54Z","tags" : ["error","elasticsearch", "data"], "pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type": "log", "@timestamp": "2026-05-18T11:59:54Z", "tags" : ["error","elasticsearch", "data"], "pid" :7,"message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearchelasticsearch: 9200"}View in Docker Desktop• View ConfigEnable WatchHomeDMsActivityFilesLaterMore-Jiminny ...Metrotrtene# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...0 Direct messages. Nikolay YankovR. Aneliya Angelovaão Stefka StoyanovaStoyan Tomov€. Vasil VasilevGalya DimitrovaLe Todor Stamatov "NMario Georgiev. Nikolay IvanovLo James Graham *2 Stoyan Tanev&. Steliyan Georgiev&e Petko KashinskiLukas Kovalik y...AppsJira CloudToastGoogle Cale...Support Daily • in 1m100% <78• Mon 18 May 14:59:56Support Dailyin 1m - 15:00-15:15= Notes - Support Daily.C Join Google MeetmessagesLe Aaa canvaso riesPreparation for Refinementin 1m - 15:00-16:00= Notes - Preparation for RefinementC7 Join Google Meetпс ме пускаNikolay Yankov 2:17 PMЕй сегаГОТОВОLukas Kovalik 2:26 PMоще ведньж и в СФNikolay Yankov 2:27 PMгТоТОвОLukas Kovalik 2:27 PMработи вечеNikolay Yankov 2:27 PMимаше ли нещо за фиксLukas Kovalik 2:28 PMтрябва да си вързан към SF да работиNikolay Yankov 2:28 PMaxaaaNikolay Yankov 2:41 PMимаме approve на PRда го даваме за QА?Lukas Kovalik 2:42 PMдаMessage Nikolay Yankov...
|
NULL
|
-1763956128456212158
|
NULL
|
click
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpEUDOCKER881DEV SlackFileEditViewGoHistoryWindowHelpEUDOCKER881DEV (docker)782sticsearch""@timestamp":"2026-05-18T11:59:49Z" , "tags" : ["warning"connections"}{"type" : "log""@timestamp": "2026-05-18T11:59:49Z","tags" : ["warning""licensing"],"message" : "Licenseinformationcould not be obtained from ElasError: No Living connections1 {"type" : "log"."@timestamp": "2026-05-18T11:59:49Z", "tags": ["warning", "monitoring"], "pid" :7, "message" : "Unableconnection: [URL_WITH_CREDENTIALS] "tags" : ["warning", "elasticsearch", "monitoring"],"pid" :7,"message" : "Noliving connections"}kibana{"type" : "log""@timestamp":"2026-05-18T11:59:49Z"gins""licensing"],"tags" : ["warning"pid":7,"message": "License information could not be obtained from ElasticsearchduetoError:No Living connectionskibana{"type" : "log""@timestamp" : "2026-05-18T11:59:49Z", "tags" : ["error"icsearch","data"],pid":7,"message":"[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch: 9200"}kibana"@timestamp": "2026-05-18T11:59:51Z","tags": ["warning","elasticsearch", "data"], "pid":7, "message": "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T11:59:51Z", "tags" : ["warning"sticsearch", "data"],"pid":7,"message": "No living connections"}kibana1 {"type" : "log","@timestamp": "2026-05-18T11:59:51Z"ns", "tags" : ["error", "plugi, "taskManager""taskManager"], "pid" :7, "message" : "Failed to pollfor work: Error: No Living connections"}kibana1 {"'type": "log", "@timestamp" : "2026-05-18T11:59:52Z" ,"tags" : ["error""elasticsearch", "data"], "pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type" : "log", "@timestamp" : "2026-05-18T11:59:54Z".,"tags" : ["warning", "elasticsearch", "data"], "pid":7, "message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T11:59:547", "tags" : ["warning", "elasticsearch", "data"], "pid":7, "message" : "No living connections"}kibana1 {"type" : "log", "@timestamp" : "2026-05-18T11:59:54Z""tags": ["error"ns", "taskManager", "taskManager"],"pid" :7, "message": "Failed to poll for work: Error: No Living connections"}klbana1 {"type" : "log"!,"@timestamp" : "2026-05-18T11:59:54Z","tags" : ["error","elasticsearch", "data"], "pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type": "log", "@timestamp": "2026-05-18T11:59:54Z", "tags" : ["error","elasticsearch", "data"], "pid" :7,"message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearchelasticsearch: 9200"}View in Docker Desktop• View ConfigEnable WatchHomeDMsActivityFilesLaterMore-Jiminny ...Metrotrtene# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...0 Direct messages. Nikolay YankovR. Aneliya Angelovaão Stefka StoyanovaStoyan Tomov€. Vasil VasilevGalya DimitrovaLe Todor Stamatov "NMario Georgiev. Nikolay IvanovLo James Graham *2 Stoyan Tanev&. Steliyan Georgiev&e Petko KashinskiLukas Kovalik y...AppsJira CloudToastGoogle Cale...Support Daily • in 1m100% <78• Mon 18 May 14:59:56Support Dailyin 1m - 15:00-15:15= Notes - Support Daily.C Join Google MeetmessagesLe Aaa canvaso riesPreparation for Refinementin 1m - 15:00-16:00= Notes - Preparation for RefinementC7 Join Google Meetпс ме пускаNikolay Yankov 2:17 PMЕй сегаГОТОВОLukas Kovalik 2:26 PMоще ведньж и в СФNikolay Yankov 2:27 PMгТоТОвОLukas Kovalik 2:27 PMработи вечеNikolay Yankov 2:27 PMимаше ли нещо за фиксLukas Kovalik 2:28 PMтрябва да си вързан към SF да работиNikolay Yankov 2:28 PMaxaaaNikolay Yankov 2:41 PMимаме approve на PRда го даваме за QА?Lukas Kovalik 2:42 PMдаMessage Nikolay Yankov...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
53263
|
1871
|
2
|
2026-05-18T11:59:52.659923+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779105592659_m2.jpg...
|
PhpStorm
|
faVsco.js – Constants.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
namespace Jiminny\Component\SCIM;
use Jiminny\Component\SCIM\Builders\Filters;
class Constants
{
/**
* HTTP codes
*/
public const HTTP_OK = 200;
public const HTTP_CREATED = 201;
public const HTTP_NO_CONTENT = 204;
public const HTTP_NOT_FOUND = 404;
public const HTTP_BAD_REQUEST = 400;
public const HTTP_ACCESS_DENIED = 403;
public const HTTP_ERROR = 501;
/**
* Users resource constants
*/
public const USER_FIRST_NAME = 'givenName';
public const USER_FAMILY_NAME = 'familyName';
public const USER_STATUS = 'Active';
public const USER_USERNAME = 'UserName';
public const USER_EXTERNAL_ID = 'externalId';
public const USER_FIELDS = [
self::USER_FIRST_NAME,
self::USER_FAMILY_NAME,
self::USER_STATUS,
self::USER_USERNAME,
];
public const META_OPERATIONS_REPLACE = 'replace';
public const META_OPERATIONS_REPLACE_UPPER = 'Replace';
public const META_OPERATIONS_ADD = 'add';
public const META_OPERATIONS_ADD_UPPER = 'Add';
public const META_OPERATIONS_REMOVE_UPPER = 'Remove';
public const META_OPERATIONS_REMOVE = 'remove';
public const META_ID = 'id';
public const META_PHONE_NUMBERS = 'phoneNumbers';
public const META_TITLE = 'title';
public const META_ROLES = 'roles';
public const META_PATH = 'path';
public const META_ENTERPRISE_SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';
public const META_DEPARTMENT = 'department';
public const META_META = 'meta';
public const META_TYPE = 'type';
public const META_VALUE = 'value';
public const META_OPERATIONS = 'Operations';
public const META_OP = 'op';
public const META_RESOURCE_TYPE = 'resourceType';
public const META_CREATED = 'created';
public const META_LAST_MODIFIED = 'lastModified';
public const META_FORMATTED = 'formatted';
public const META_EMAILS = 'emails';
public const META_USERNAME = 'userName';
public const META_NAME = 'name';
public const META_STATUS = 'active';
public const META_PRIMARY = 'primary';
public const META_ERROR_STATUS = 'status';
public const META_ERROR_DETAIL = 'detail';
public const META_LIST_TOTAL_RESULTS = 'totalResults';
public const META_LIST_RESOURCES = 'Resources';
public const META_LIST_START_INDEX = 'startIndex';
public const META_LIST_COUNT = 'count';
public const META_LIST_ITEMS_PER_PAGE = 'itemsPerPage';
public const META_SCHEMAS = 'schemas';
public const META_FILTER = 'filter';
public const META_TYPE_WORK = 'work';
public const META_PHONE_NUMBER_TYPE_MOBILE = 'mobile';
public const META_EMAIL_TYPE_HOME = 'home';
public const META_CONTAINER_NAME = 'name';
public const META_CONTAINER_EMAILS = 'emails';
public const RESOURCE_TYPE_USER = 'User';
public const USER_PATCH_ATTR_TITLE = 'title';
public const USER_PATCH_ATTR_ACTIVE = 'active';
public const USER_PATCH_ATTR_USERNAME = 'userName';
public const USER_PATCH_ATTR_FIRST_NAME = 'name.givenName';
public const USER_PATCH_ATTR_LAST_NAME = 'name.familyName';
public const USER_PATCH_ATTR_PRIMARY_EMAIL = 'emails[type eq "work"].value';
public const USER_PATCH_ATTR_SECONDARY_EMAIL = 'emails[type eq "home"].value';
public const USER_PATCH_ATTR_PHONE_NUMBER = 'phoneNumbers[type eq "work"].value';
public const USER_PATCH_ATTR_PHONE_NUMBER_MOBILE = 'phoneNumbers[type eq "mobile"].value';
public const USER_PATCH_ATTR_ROLES = 'roles';
public const USER_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [
self::USER_PATCH_ATTR_TITLE => Mutators\Attributes\User\TitleAttr::class,
self::USER_PATCH_ATTR_ACTIVE => Mutators\Attributes\User\ActiveAttr::class,
self::USER_PATCH_ATTR_USERNAME => Mutators\Attributes\User\UsernameAttr::class,
self::USER_PATCH_ATTR_FIRST_NAME => Mutators\Attributes\User\FirstNameAttr::class,
self::USER_PATCH_ATTR_LAST_NAME => Mutators\Attributes\User\LastNameAttr::class,
self::USER_PATCH_ATTR_PRIMARY_EMAIL => Mutators\Attributes\User\PrimaryEmailAttr::class,
self::USER_PATCH_ATTR_SECONDARY_EMAIL => Mutators\Attributes\User\SecondaryEmailAttr::class,
self::USER_PATCH_ATTR_PHONE_NUMBER => Mutators\Attributes\User\PhoneNumberPrimaryAttr::class,
self::USER_PATCH_ATTR_PHONE_NUMBER_MOBILE => Mutators\Attributes\User\PhoneNumberSecondaryAttr::class,
self::USER_PATCH_ATTR_ROLES => Mutators\Attributes\User\RoleAttr::class,
];
public const FILTER_OPERATOR_EQ = 'eq';
public const SUPPORTED_FILTERS_OPERATORS = [
self::FILTER_OPERATOR_EQ,
];
public const USER_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [
self::USER_FILTER_LOCAL_ID => Filters\User\LocalIdFilter::class,
self::USER_FILTER_USERNAME => Filters\User\UserNameFilter::class,
self::USER_FILTER_FIRST_NAME => Filters\User\FirstNameFilter::class,
self::USER_FILTER_LAST_NAME => Filters\User\LastNameFilter::class,
self::USER_FILTER_EXTERNAL_ID => Filters\User\ExternalIdFilter::class,
self::USER_FILTER_DISPLAY_NAME => Filters\User\DisplayNameFilter::class,
];
public const USER_FILTER_LOCAL_ID = 'id';
public const USER_FILTER_USERNAME = 'userName';
public const USER_FILTER_FIRST_NAME = 'givenName';
public const USER_FILTER_LAST_NAME = 'familyName';
public const USER_FILTER_EXTERNAL_ID = 'externalId';
public const USER_FILTER_DISPLAY_NAME = 'DisplayName';
public const SCIM_SUPPORTED_RESOURCES = [
self::USER_RESOURCE_PREFIX,
self::GROUP_RESOURCE_PREFIX,
];
public const USER_RESOURCE_PREFIX = 'Users';
public const GROUP_RESOURCE_PREFIX = 'Groups';
public const OUTGOING_SCHEMAS_SUPPORTED = [
self::OUTGOING_CORE_USER,
];
/**
* Outgoing supported schemas
*/
public const OUTGOING_CORE_USER = 'urn:ietf:params:scim:schemas:core:2.0:User';
public const OUTGOING_ERROR = 'urn:ietf:params:scim:api:messages:2.0:Error';
public const OUTGOING_LIST_RESPONSE = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';
public const OUTGOING_CORE_GROUP = 'urn:ietf:params:scim:schemas:core:2.0:Group';
/**
* Groups resource constants
*/
public const GROUP_ATTRIBUTE_DISPLAY_NAME = 'displayName';
public const GROUP_ATTRIBUTE_EXTERNAL_ID = 'externalId';
public const GROUP_ATTRIBUTE_ID = 'id';
public const RESOURCE_TYPE_GROUP = 'Group';
public const GROUP_FILTER_QUERY_NAME = 'filter';
public const GROUP_EXCLUDED_ATTRIBUTES = 'excludedAttributes';
public const GROUP_SUPPORTED_FILTER_ATTRIBUTES = [
self::GROUP_ATTRIBUTE_DISPLAY_NAME,
];
public const GROUP_MEMBERS = 'members';
public const SUPPORTED_PATCH_OPERATIONS = [
self::META_OPERATIONS_ADD,
self::META_OPERATIONS_REPLACE,
self::META_OPERATIONS_REMOVE,
];
public const GROUP_PATCH_ATTRIBUTE_MEMBERS = 'members';
public const GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME = 'displayName';
public const GROUP_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [
self::GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME => Mutators\Attributes\Group\DisplayNameAttr::class,
self::GROUP_PATCH_ATTRIBUTE_MEMBERS => Mutators\Attributes\Group\MembersAttr::class,
];
public const GROUP_FILTER_DISPLAY_NAME = 'displayname';
public const GROUP_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [
self::GROUP_FILTER_DISPLAY_NAME => Filters\Group\DisplayNameFilter::class,
];
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny_jupiter
Sync Changes
Hide This Notification
Code changed:
Hide
19
19
17
Previous Highlighted Error
Next Highlighted Error
SELECT * FROM teams WHERE id = 1;
select * from crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 283;
SELECT * FROM crm_fields WHERE id = 2234;
SELECT * FROM crm_field_values WHERE crm_field_id = 2234;
select * from crm_profiles where user_id = 143;
select * from record_types where crm_configuration_id = 39; # 0121K000001MHElQAO,0121K000001MHEqQAO
select * from business_processes where crm_configuration_id = 39;
# 01941000000H669AAC, 01941000000H66JAAS
select * from record_type_field_values
where record_type_id IN (24);
select * from crm_field_values where id IN (2730);
select * from crm_configurations where id = 39;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce'; #1035
select * from users where team_id = 1; # 222 group 3
SELECT * FROM activities WHERE user_id = 222 order by id desc;
select * from sidekick_settings where team_id = 1;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from activities where crm_configuration_id = 2
and provider = 'ms-teams' and id = 608765;
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id = '59523413338';
select * from sidekick_settings where team_id = 2;
SELECT * FROM activities WHERE id = 608660;
select * from activity_summary_logs where activity_id = 608660;
select * from ai_prompts where transcription_id = 11214;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('ed78a437-2804-450e-ab2f-56ab1c641346') = uuid;
# id: 608818, crm: 59628809737
SELECT * FROM activities WHERE uuid_to_bin('36b06e55-afdd-4782-8dee-c624cd0af191') = uuid;
# id: 608821, crm: 59632069252
SELECT ce.start_time, ce.end_time, a.id, a.uuid, crm_provider_id, calendar_event_id, title,
playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id,
scheduled_start_time, scheduled_end_time, actual_start_time, actual_end_time, a.created_at
FROM activities a
join calendar_events ce on a.calendar_event_id = ce.id
WHERE a.id IN (608818, 608821);
select * from users where team_id = 1;
select * from team_settings where team_id = 1;
select * from crm_profiles where crm_configuration_id = 39 order by user_id;
select * from team_features where team_id = 1;
select * from users where team_id = 2;
SELECT * FROM activities WHERE uuid_to_bin('ec7647e9-5225-458b-b475-f31aa2769204') = uuid; # 612639
# Preslava N. Ivanova, grou id 3
SELECT * FROM opportunities WHERE uuid_to_bin('a2928fe5-aec5-46cb-85d9-7654c89e46a6') = uuid;
select * from activities where opportunity_id = 344 and actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00';
select
a.id,
a.type,
a.scheduled_start_time,
a.actual_start_time,
a.created_at,
a.opportunity_id,
a.status
FROM activities a
WHERE opportunity_id = 344
and status IN ('completed', 'received', 'delivered')
and (
(a.actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')
OR (a.created_at between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')
OR (a.scheduled_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00'))
;
SELECT * FROM users WHERE id = 222;
SELECT * FROM crm_profiles WHERE user_id = 222;
select * from crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 281;
select * from group_deal_risk_types;
select * from opportunities where team_id = 1;
SELECT * FROM opportunities WHERE id = 315;
SELECT * FROM crm_field_data WHERE object_id = 315;
select * from crm_field_data where object_id = 260;
select * from generic_ai_prompts where subject_id = 315;
select * from teams; # 36, 21, 121, [EMAIL]
SELECT * FROM social_accounts WHERE sociable_id = 121 and provider = 'bullhorn';
# [PASSWORD_DOTS]
select * from teams where id = 1;
select * from crm_configurations where id = 39;
select * from users where team_id = 1;
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 1;
# 1 - 00541000004281rAAA
# 204 - 0052g000003freeAAA
# 429 - 0052g000003qGOiAAM
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce';
select * from activities where type = 'softphone'
and created_at > '2024-12-11 15:24:36' order by id desc;
select * from activity_providers where team_id = 1;
select * from activity_provider_users where activity_provider_id = 328;
select * from opportunities where crm_configuration_id = 39
AND account_id = 178 AND is_closed = false
order by created_at DESC;
select * from contacts where id = 3952;
select * from accounts where id = 178;
# [PASSWORD_DOTS]
select * from teams where id = 36;
select * from crm_configurations where id = 21;
select * from users where team_id = 36;
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 36;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 36
and sa.provider = 'bullhorn';
select * from social_accounts where id = 348;
UPDATE social_accounts SET
provider_user_token = '21442_6802599_91:41179a58-21e7-4d7c-ad58-56bb666b2f65',
provider_refresh_token = '21442_6802599_91:01c6b335-3f2a-42e4-85ff-8a08fa65fceb',
expires = 1733998131,
state = 'connected'
WHERE id = 348;
# [PASSWORD_DOTS]
select * from teams where id = 31;
select * from crm_configurations where id = 18;
select * from users where team_id = 31; # 257
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 31;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 31
and sa.provider = 'close';
select * from contacts where crm_configuration_id = 18;
# [PASSWORD_DOTS] NEPTUNE [PASSWORD_DOTS]
select * from teams;
select * from users where id IN (1030, 1035, 1052);
select * from crm_configurations;
select * from users where team_id = 65; # 257
select * from team_settings where team_id = 65; # 257
select * from invitations where team_id = 65; # 257
select * from users where email = '[EMAIL]'; # 257
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 65;
select * from crm_configurations where id = 53;
select * from accounts where crm_configuration_id = 53 order by id desc;
select * from leads where crm_configuration_id = 53 order by id desc;
select * from contacts where crm_configuration_id = 53 order by id desc;
select * from opportunities where crm_configuration_id = 53 order by id desc;
select * from crm_profiles where crm_configuration_id = 53 order by id desc;
select * from crm_fields where crm_configuration_id = 53 order by id desc;
select * from crm_field_values where crm_field_id = 3341 order by id desc;
select * from crm_layouts where crm_configuration_id = 53 order by id desc;
select * from stages where crm_configuration_id = 53 order by id desc;
select * from crm_profiles where crm_configuration_id = 13;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 65
and sa.provider = 'integration-app';
select * from contacts where crm_configuration_id = 13;
select * from social_accounts where sociable_id = 283;
SELECT * FROM opportunities WHERE crm_provider_id = '006O400000E9bzeIAB';
select * from activity_providers where team_id = 65;
SELECT * FROM activities WHERE crm_configuration_id IN (51, 52, 53);
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 65
;
# [PASSWORD_DOTS] STAGING [PASSWORD_DOTS]
SELECT * FROM teams;
SELECT * FROM teams WHERE id = 88;
SELECT * FROM teams WHERE id = 89;
select * from team_settings where team_id = 89;
SELECT * FROM users WHERE team_id = 89;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 89;
select * from users;
SELECT * FROM social_accounts WHERE sociable_id = 1761;
SELECT * FROM crm_configurations WHERE id = 70;
select * from accounts where crm_configuration_id = 70 order by id desc;
select * from leads where crm_configuration_id = 70 order by id desc;
select * from contacts where crm_configuration_id = 70 order by id desc;
select * from opportunities where crm_configuration_id = 70 order by id desc;
select * from crm_profiles where crm_configuration_id = 70 order by id desc;
select * from crm_fields where crm_configuration_id = 70 order by id desc;
select * from crm_field_values where crm_field_id = 3536 order by id desc;
select * from crm_layouts where crm_configuration_id = 70 order by id desc;
select * from stages where crm_configuration_id = 70 order by id desc;
select * from business_processes where crm_configuration_id = 70 order by id desc;
select * from business_process_stages where business_process_id = 34;
select * from contacts where id = 10468;
select * from crm_layouts where crm_configuration_id = 70;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 388;
SELECT * FROM crm_fields WHERE id IN (3533,3534,3535);
select * from activities where crm_configuration_id = 70
and (account_id IS NOT NULL or lead_id IS NOT NULL or contact_id IS NOT NULL or opportunity_id IS NOT NULL) order by id desc;
SELECT * FROM activities WHERE uuid_to_bin('2e10b60f-8a61-41c5-a3d4-28835353dc65') = uuid;
SELECT * FROM activities where crm_configuration_id = 69 ;
SELECT * FROM users WHERE email LIKE '%[EMAIL]%';
SELECT * FROM activities WHERE uuid_to_bin('5a150c93-40fc-42ec-b3bd-c1d328e09f6e') = uuid;
SELECT * FROM opportunities WHERE id = 385;
select * from participants p
join activities a on p.activity_id = a.id
where a.crm_configuration_id = 70
and (p.lead_id IS NOT NULL or p.contact_id IS NOT NULL);
SELECT * FROM participants WHERE id = 1013638;
select * from teams where id = 90;
select * from users where team_id = 90;
select * from social_accounts where social_accounts.sociable_id IN (1960,1760);
SELECT * FROM crm_profiles WHERE crm_configuration_id = 71;
select * from invitations where team_id = 90;
select * from crm_configurations where id = 71;
select * from accounts where crm_configuration_id = 71 order by id desc;
select * from leads where crm_configuration_id = 71 order by id desc;
select * from contacts where crm_configuration_id = 71 order by id desc;
select * from opportunities where crm_configuration_id = 71 order by id desc;
select * from crm_profiles where crm_configuration_id = 71 order by id desc;
select * from crm_fields where crm_configuration_id = 71 order by id desc;
select * from crm_field_values where crm_field_id = 3341 order by id desc;
select * from crm_layouts where crm_configuration_id = 71 order by id desc;
select * from stages where crm_configuration_id = 71 order by id desc;
select * from users order by secondary_email desc;
select u.id, u.email, u.status, sa.id, sa.provider_user_id from social_accounts sa
join users u on sa.sociable_id = u.id
where sa.provider = 'google' and u.email LIKE 'aneliya%';
select * from failed_jobs order by id desc;
select * from users where email = '[EMAIL]' or secondary_email = '[EMAIL]';
select * from teams;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 39;
SELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type = 'task';
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce';
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('c38b3895-fd0f-4b1f-9fb2-c170dba137c6') = uuid;
SELECT * FROM crm_configurations WHERE id = 70;
select * from teams where id = 1;
select * from groups where team_id = 1;
select * from users where team_id = 1;
select o.id, o.name,o.close_date, u.id, u.name, u.group_id, r.id, r.display_name, g.name, g.scope from opportunities o
join users u on o.user_id = u.id
join groups g on u.group_id = g.id
join role_user ru on u.id = ru.user_id
join roles r on ru.role_id = r.id
where o.crm_configuration_id = 39 and close_date > '2024-01-01 00:00:00';
select * from role_user where user_id = 143;
select * from roles;
select * from role_user;
select * from groups where id = 9;
select * from scope_groups where group_id = 9;
# [PASSWORD_DOTS]
select * from teams where id = 36;
select * from crm_configurations;
SELECT * FROM social_accounts WHERE sociable_id = 121;
https://crmsandbox.zoho.com/crm/jiminnyw4/tab/Leads/4776201000005049105
https://crmsandbox.zoho.com/crm/
https://crm.zoho.com/crm/org3469620/tab/Leads/230045000229559080
https://crm.zoho.com/crm/
org3469620
SELECT * FROM activities WHERE uuid_to_bin('03382d20-c8bc-48e7-a3d4-90b52fa5ceab') = uuid;
select * from users where email LIKE "%mobile_automation_%";
select * from social_accounts where sociable_id IN (2228);
select * from crm_profiles where user_id IN (2222,2223,2226,2227);
select * from teams order by id desc;
SELECT * FROM users WHERE id = 2229;
SELECT * FROM crm_profiles WHERE user_id = 2229;
select * from opportunities where crm_configuration_id = 88;
select * from crm_fields where crm_configuration_id = 88;
select * from crm_profiles where crm_configuration_id = 88;
SELECT * FROM teams WHERE id = 1;
SELECT * FROM users WHERE id = 143;
SELECT * FROM users WHERE uuid_to_bin('fde193d3-06a2-4e1a-8895-62b94039215d') = uuid;
SELECT * FROM teams WHERE uuid_to_bin('73385071-a756-42ae-9c73-8b53f2309467') = uuid;
https://app.staging.jiminny.com/ondemand?
min_duration=1
&
only_recorded=1
&
user_id%5B%5D=641f1acb-16b8-42d1-8726-df52979dad0e
&
sequence_number=2
select * from users where team_id = 1 and email like '%stoyan%'
select * from coaching_feedbacks;
select * from teams;
SELECT * FROM users WHERE team_id = 36;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 19
and sa.provider = 'pipedrive';
select * from users where id = 143;
SELECT * FROM users WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
SELECT * FROM teams WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
SELECT * FROM activity_shares WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
select * from users where team_id = 2;
select * from activities where crm_configuration_id = 39
and activities.scheduled_start_time BETWEEN '2025-04-09 00:00:00' AND '2025-04-09 23:59:59'
AND user_id = 143
order by id desc;
# [PASSWORD_DOTS]
select * from teams where id = 142; # 2312, 126
select * from team_settings;
select * from users where team_id = 142; # 21642
SELECT * FROM social_accounts WHERE sociable_id = 21642;
SELECT * FROM crm_profiles cp join users u ON u.id = cp.user_id WHERE team_id = 142;
select * from crm_profiles where id IN (93);
select * from invitations;
select * from team_features where team_id = 1;
SELECT * FROM crm_configurations WHERE id = 126;
select * from accounts where crm_configuration_id = 126 order by id desc;
select * from leads where crm_configuration_id = 126 order by id desc;
select * from contacts where crm_configuration_id = 126 order by id desc;
select * from opportunities where crm_configuration_id = 126 order by id desc;
select * from crm_profiles where crm_configuration_id = 126 order by id desc;
select * from crm_fields where crm_configuration_id = 126 # 11060
# and type IN ('picklist', 'status')
# and object_type = 'task'
order by id desc;
# 5731,5732,5733
select DISTINCT crm_field_id from crm_field_values where crm_field_id IN (11151,12239,12215,12185,12175,12165,12144,12137,12127,12109,12107,12105,12103,12092,12037,12005,12003,11987,11969,11958,11951,11942,11931,11924,11921,11917,11915,11901,11893,11883,11872,11870,11868,11866,11839,11833,11821,11793,11780,11777,11769,11757,11737,11735,11656,11645,11638,11629,11618,11611,11602,11591,11584,11581,11558,11544,11543,11534,11532,11529,11527,11503,11497,11493,11488,11470,11468,11457,11455,11397,11387,11372,11363,11348,11323,11318,11309,11301,11300,11292,11290,11286,11284,11256,11252,11242,11237,11233,11219,11176,11160) order by id desc;
select * from crm_layouts where crm_configuration_id = 126 order by id desc;
SELECT * FROM crm_layout_entities WHERE crm_layout_id in (300,299,298);
select * from stages where crm_configuration_id = 126 order by id desc;
select * from business_processes where crm_configuration_id = 126 order by id desc;
select * from business_process_stages where business_process_id IN (76,75,74,73);
select * from playbooks where team_id = 142;
select * from playbook_layouts where playbook_id IN (108);
SELECT * FROM playbook_categories WHERE playbook_id IN (108);
select * from teams where id = 130;
SELECT * FROM social_accounts WHERE sociable_id = 2291;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 2
and sa.provider = 'hubspot';
SELECT * FROM activities
WHERE crm_configuration_id = 110;
select * from teams;
select * from crm_configurations;
SELECT * FROM activities WHERE id = 628773;
SELECT * FROM crm_profiles WHERE user_id = 1460;
SELECT * FROM social_accounts WHERE sociable_id = 2291;
select * from teams;
select ru.*, pr.*, p.* from users u join role_user ru on ru.user_id = u.id
join permission_role pr on pr.role_id = ru.role_id
join permissions p on p.id = pr.permission_id
where team_id = 495 and p.name IN ('dial');
select * from teams where id = 145;
select * from crm_configurations where id = 129;
select * from social_accounts where sociable_id = 2317;
SELECT * FROM activities WHERE uuid_to_bin('8dbab184-a333-4268-ad57-fb41f8d53a9a') = uuid;
select * from teams where id = 1;
SELECT * FROM crm_layouts WHERE crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 280;
SELECT * FROM crm_layout_entities WHERE id = 5507;
SELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type IN ('event');
select * from teams;
select * from activities where crm_configuration_id = 14;
SELECT * FROM social_accounts where provider = 'copper';
select * from activities where id = 628467;
select * from participants where activity_id = 628467;
SELECT * FROM contacts WHERE id = 3969;
SELECT * FROM accounts WHERE id = 177;
SELECT * FROM activities WHERE uuid_to_bin('4eb54c77-cfa3-2bd4-84a7-9ed46a21c988') = uuid;
# [PASSWORD_DOTS] BH
select * from teams where id = 36;
SELECT * FROM crm_configurations WHERE id = 21;
select * from activities where crm_configuration_id = 21 and id = 607901;
select * from activities where crm_configuration_id = 21;
select * roles;
select * from permissions;
select * from permission_role where permission_id = 226;
select * from migrations order by id desc;
# mercury
# neptune
# earth
select * from teams;
select * from teams where id = 19;
select * from teams where id = 27;
select * from users where team_id = 27;
SELECT * FROM crm_configurations WHERE id = 42;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 19
and sa.provider = 'pipedrive';
select * from activities where id = 631461;
SELECT * FROM crm_field_values WHERE crm_field_id = 180;
select * from teams where id = 2;
SELECT * FROM social_accounts WHERE sociable_id = 89;
SELECT * FROM activities WHERE uuid_to_bin('ba0c029a-bc14-4e17-8603-64174acebcbb') = uuid; # 634273
select * from activity_summary_logs where activity_id = 634273;
select * from sidekick_settings where team_id = 2;
select * from teams; # 2, 2
SELECT * FROM crm_configurations WHERE team_id = 2; # 2
select * from team_features where team_id = 2;
select * from features;
SELECT * FROM opportunities WHERE crm_configuration_id = 2 and crm_provider_id = '51317301383';
SELECT * FROM opportunities WHERE crm_configuration_id = 2 order by id desc;
select * from automated_reports order by id desc;
select * from automated_report_results order by id desc;
select * from users where team_id = 1 and id IN (7160, 3248);
select * from migrations order by id desc;
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 = 1052 and sa.provider = 'hubspot';
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 = 565;
select * from playbooks where team_id = 1;
select * from playbooks where id = 175;
select * from playbook_categories where playbook_id = 175;
select * from users where team_id = 1052;
select * from users where id = 7160;
select * from crm_profiles where user_id = 7160;
select * from features;
select
*
# id, uuid, type, provider, playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id, stage_id,
# crm_configuration_id, crm_provider_id, transcription_id, status
from activities where crm_configuration_id = 1 and type = 'conference'
# and crm_provider_id IS NOT NULL
and provider != 'uploader' and actual_start_time IS NOT NULL
ORDER by id desc;
select * from activities where id = 54747783; # 00UO400000pCzojMAC
select p.id, p.activity_type, pc.id, pc.name
FROM playbooks p
join playbook_categories pc on p.id = pc.playbook_id
where p.team_id = 1 and p.activity_type = 'event';
SELECT * FROM crm_fields WHERE crm_configuration_id = 1 and object_type = 'event';
SELECT * FROM crm_field_values WHERE crm_field_id = 4;
select * from crm_layouts cl join playbook_layouts pl on cl.id = pl.layout_id
where crm_configuration_id = 1 and pl.playbook_id = 175;
select * from teams;
SELECT r.* FROM automated_reports r
join teams t on r.team_id = t.id
WHERE r.frequency = 'daily'
and r.status = 1
AND t.status = 'active'
AND (r.expires_at >= now() OR r.expires_at IS NULL);
select * from automated_report_results where report_id IN (18, 33);
select * from users where team_id = 1 and id = 1047;
SELECT * FROM social_accounts WHERE sociable_id = 1047;
select * from activity_searches where id = 10932;
select * from activity_search_filters where activity_search_id = 10932;
select * from automated_reports order by id desc;
select * from automated_report_results order by id desc;
select * from automated_reports where id IN (55);
select * from automated_report_results where id IN (81);
select * from users where id IN (10633, 13987, 11985);
select * from users where group_id IN (3710);
SELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;
SELECT * FROM automated_report_results WHERE uuid_to_bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;
select * from teams;
select * from accounts where team_id = 1;
select * from automated_report_results where media_type = 'pdf' and status = 2;
SELECT * FROM automated_report_results WHERE uuid_to_bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid;
select * from teams where id = 1029;
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 = 1029 and sa.provider = 'pipedrive';
[
{
"user_id": "23460 (owner)",
"email": "[EMAIL]",
"id": 69,
"sociable_id": 23460,
"provider_user_id": "19555731",
"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,
"refresh_token_expires": null,
"provider": "pipedrive",
"state": "connected",
"auth_scope": "base,deals:full,activities:full,contacts:full,search:read",
"retry_after": null,
"created_at": "2025-04-16 08:23:28",
"updated_at": "2026-05-18 07:13:18",
"provider_user_token_encrypted": "eyJpdiI6Ik9oYzBwcTVteWN4ajBRaDdMb0FjWGc9PSIsInZhbHVlIjoiQUNMbjU5UHR2Q1RnbWRXMEU1TUx6UVpRU3gzdVc5WktmTE4rVlhXa3lRaGhyUUlZMVZRWEJuR0JaWWhZZXNPRlBuanhuYU5MVHZ5TG9NTVVjNjJSUUpZZ2VhbGYxbHg0UzJEdTVmQjNFZnJRZkMwYjd0N2RMZ05GRS9IR3c2K0NoVjBjYTA5UG12SkxHeDlDMGVNN3ptUWUzblFiTngyYzR1eUpHSEYrdEwvZm0yZklGYjBSNEtTR2ZGazhLM1hqT3lVbjFobDNPZ0d3anFlcjhKcXpERlZGOVN1YmFyNDIvM1BFRDFMYnp4WEI4TGVLM2xYcy9CL0RDOWlQNHI3N0NwWnJPMWRtZllmM2ZKeE9TV2NBeDZxL2M1YnlSVzd3ZW96T3F1QmtBYXBHYkUraGcvdCtRajlYZXBjVVBSdFlMUjVPVDVJbDdyenVoWjMrbVJvU3ZZR1dQZ3pqQ3F3aDF2U2xPZWZIN3BCWVFLNXpxQUtDb2pIK0xHc1E3SklSM3Q0VkNSbm9oK2pFK3hLaW54T1dWbEVneUp0RGhhdVBuOFI4MXROc3dZWnFnTUpiaDVMMnZ4QmlRM3k4QWFlMVFWUFYvdGhJQzZBYnhBQmhWa2ZKN1ZhSnhpaExxbmlTemgzUWw3aXJtWjlSMlhmd0lWMDNDN1N3My9Ua0hCL2xqY3RkVFhMSjFJMDRjOE5DWlgrZ3FMVXN6RWlwUE5GWERZdG1xVjVxOFlLRGs2VVJKS3FLeWRxQjYxdDh4Z2JJNXhlWEZ3dkQ4SGtybDNUcndzblFHeVJNRkYraFh2UDFIUTdMQ1BZa3dEU1dBbzk5K0dyT2RNVFBZZUJpRytSck5pYlI1YUZyMmhUNEZCdWxHYmJLREtzbUpjVkhvV0RoejJpbm1SWHlNaXE5M0RhcS94UW9EdFoweWF3bVFVY0dTZWFPSXBmOCtDYndia215cmtyZU1oT0Exam1CV2tPblNhYjY4clVEeUs3anVHUmNHeS9YLzRha1VhbGl3N3lwaDlzZnRhQUZta2s4eFllNHgzRklSRmNyazJ4dlBDMnByNCtBRjNaVjJCTT0iLCJtYWMiOiJkYTQxZDY1OTY2ZTljMTgyZWRhNGEzMGZjZDc2MjBjN2NlNzU2YTViNGQxNWE1NTI2ZmI1MWQyYjQ2ODYxZmEwIiwidGFnIjoiIn0=",
"provider_refresh_token_encrypted": "eyJpdiI6Imt2bGxlSmxUK05GMjF0dEtPaTMrUlE9PSIsInZhbHVlIjoiUXZHTElZRXkreHFxUU02SnZ4eVBacG9WWTRlVkd0USszV3JyVFlpU2ZaY25GSWo2WFcrRzNlbFRlUXRQczNwSXRCcEdvZEpveG9jMzBDSTgwdnZLQnc9PSIsIm1hYyI6ImQxYWI0NzU5Nzg5MDI4YWVhZmQ4Mjg1YzhkZDQzMjRkYWYwYTdhZTY5MDMxMjc0OWNiYjY0Nzc3NDQ0MTEyY2EiLCJ0YWciOiIifQ==",
"encryption_key": "0x01020300786192D9D96DD60D3D1EBC9DFAEE5F0C45EE80165CF3F3D2B3B627026AA7CFC7CA0128DD463535D32EE491ADBADF8B07596B0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040C7FB1319048ECB2EA3F23B995020110802B52D22F5EAD341AB238FBBCB6093156E443876A664BA5555D722565C2B2D04422C868CD7350555E3CC74221",
"sociable_type": "user",
"owner_id": 23460
},
{
"user_id": "23463",
"email": "[EMAIL]",
"id": 72,
"sociable_id": 23463,
"provider_user_id": "23270841",
"provider_user_token": "v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:txqCuWLeVhgwiaFqXIvQWWrtrnFIy_4lT3VCr-sRB4g6_2lK8KcQ_6ka_qFmZhr-IeIAKmAImx6H1iIKx4Ab7XZ5MnKIh03GKbHjI0n0rGT9UYkeH21jKOxJvKaSX_TyLbxFPR6irPQyvqcpBClXI52gVJH01KzZy_dMTHFXhhDLOIhEpSrQXHG7Qo8q7OuBeSPZrU1ALi9kmAm4GTpzGTbzfl-hUt9IAfPunJOCyv3mf2Tl-MT8EyQgOFPrsP3yz9UlSyVhb40zO_bCnUrqNxjwgm_E6vgpVrwULTQbHe-43Dq-TRetjceUzT88GBgVJ0UdxXP5BRBVXcL5ir8-9ZTMaNU",
"provider_refresh_token": "5034113:[TELEGRAM_TOKEN]78ad1",
"expires": 1753837219,
"refresh_token_expires": null,
"provider": "pipedrive",
"state": "full-refresh",
"auth_scope": "base,deals:full,activities:full,contacts:full,search:read",
"retry_after": null,
"created_at": "2025-04-16 10:41:12",
"updated_at": "2025-07-30 01:00:17",
"provider_user_token_encrypted": "eyJpdiI6InVEVEl2SzIxMjd1bkNDWG9lY3YvQ0E9PSIsInZhbHVlIjoiRlJLbDZ3ZHo2dHMxUWQwdGU2YUZjV3lPWHlxQTJ0eWh4S0RTMjlSaThVcktoaWhXcTd2UXl4Mjg4bW5UUnZCZEQ5NXpuQTVKOURiMDNIa3l3K0lSWCt5azRBOEdHbitWQXhxeEpMVUZ1dnF2NVl1TTZLelZOaGNvRlBLeGpIWlpoRGloUEprd2xoNUFPcTlLcUd3WVlUU2svR1NOeXBYQ2NnMWhnK1V2aytOeVVMNzJGdVZXMU1JS3BSaGNCcmxkVjEwQ01mQXNBdWNhS1lMZWZobnZwcHBkN1R4bUVDRUNYdnNtSVJkdG5MdkN3djJBT0hMRDl1MHFGbnl4WU13ejBkUWsrdUljWkZhcTJlN0JDSGdTVzlPY0FGMUJlZi9WRGpkMUk5R20wblYwSk9VR2FuaHpLTzJNeitMbnF1V1NEMUUxRmYzaDRGZDMyaXd3Z0FjQno4SzVoYjUyTmV3UXNpRlF4TGZKNVl3dUFqdGhKVWJjRVlUUXRGalBpaXJvSGJmbS8rd25aQ2Zvc05saHRDRjlHV1VEUFFiRU5xbWRVNkxFSXV0RUZyaUlYNWMwMmhnZ0Y1VUQ4eEFkY2QyWXpnR0NidkVJSWdjVGljUjA3NDdpZW9WUHhtSlpGSGdNU2hRUTA5ZW03RGpiRFdrdytkOHJXSUxlazZNaG9iaUg2NFZYdEc3YklMeFZvblBzWmVRSDcvN2M4WUNtL3h4S2IrUW00cXhialBia3BJcW5XallBNlV5WWdhcE1ZVFBBM3RSSUVBamYvOGZEQWM5a2FJMGwyWkRSU3dlTEtPemZlQ3RXRGNDcEdYRHdMNTlTQVg2SUdUN0hVaXdZT1dUOUlrVzkrZHFBemhwWXg1cm4rSy9UOHUzcnNSM2dISlhBRTEyVUNyTkZYaFJYUlN1a2RKVHhhM2dHckR3a1JGaVZ2Wk9BVnhTclVpSEhwWTVpQTlJbXVkOUxSTGpRbDk0a1VtbE9QMVAvN3VlVEhJUHd2elowd0laNVIzZ3M3N0ZOK0NDakIwQ2FicGxoMDBhTXI0VUppUmFOZHdlWUdGV21NNFQ4RU1nY0dnWT0iLCJtYWMiOiI0ZTU4ZmJkNTdkYmY0NGE4NTJjZjlhNDExNzE2YjhlOWM2NTA5OGY2MDA4OTcyZDVlOTljY2JjZDhmMjBhMDUyIiwidGFnIjoiIn0=",
"provider_refresh_token_encrypted": "eyJpdiI6IkJGMkdRVHRKM2VTcitKNGcvQWJtUGc9PSIsInZhbHVlIjoicmFyRkxPZ1Rybm1ORXlEVjJ2TXFGTzJtM3hWaFhnUVVHN2ZlR1lRM0I5d3ozbnZTcU5EdzJqRkI2elhyNWhlenRTUXV3bjk0N1JXeklDMVAyUzBKcHc9PSIsIm1hYyI6ImJhODVjMGQyZDE3Y2ExNjc2OWVjYWJiNmFjYWVkODIyMTMyNWVhYTExMTgwYTEyMTU0MzUzZGE1YjQ5YzQ5ZjEiLCJ0YWciOiIifQ==",
"encryption_key": "0x01020300788C37CDF66ABE9301A68D5D4866AC0C197E04EEE4D904F20A59991322EBAE252301BEF4B24FF01359E934E5654617E4EEAC0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040CEB00EF45BDEA999A5558889E020110802B925F372F7BEFAF0B45E48686113D1DA430ECFCC07B1F61BA6828CC44235278EDB05C486E8068D0BE737D91",
"sociable_type": "user",
"owner_id": 23460
}
]
Project
Project
New File or Directory…...
|
[{"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":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>114 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"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":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Component\\SCIM;\n\nuse Jiminny\\Component\\SCIM\\Builders\\Filters;\n\nclass Constants\n{\n /**\n * HTTP codes\n */\n public const HTTP_OK = 200;\n public const HTTP_CREATED = 201;\n public const HTTP_NO_CONTENT = 204;\n\n public const HTTP_NOT_FOUND = 404;\n public const HTTP_BAD_REQUEST = 400;\n public const HTTP_ACCESS_DENIED = 403;\n\n public const HTTP_ERROR = 501;\n\n /**\n * Users resource constants\n */\n public const USER_FIRST_NAME = 'givenName';\n public const USER_FAMILY_NAME = 'familyName';\n public const USER_STATUS = 'Active';\n public const USER_USERNAME = 'UserName';\n public const USER_EXTERNAL_ID = 'externalId';\n\n public const USER_FIELDS = [\n self::USER_FIRST_NAME,\n self::USER_FAMILY_NAME,\n self::USER_STATUS,\n self::USER_USERNAME,\n ];\n\n public const META_OPERATIONS_REPLACE = 'replace';\n public const META_OPERATIONS_REPLACE_UPPER = 'Replace';\n public const META_OPERATIONS_ADD = 'add';\n public const META_OPERATIONS_ADD_UPPER = 'Add';\n public const META_OPERATIONS_REMOVE_UPPER = 'Remove';\n public const META_OPERATIONS_REMOVE = 'remove';\n\n public const META_ID = 'id';\n public const META_PHONE_NUMBERS = 'phoneNumbers';\n public const META_TITLE = 'title';\n public const META_ROLES = 'roles';\n public const META_PATH = 'path';\n public const META_ENTERPRISE_SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';\n public const META_DEPARTMENT = 'department';\n public const META_META = 'meta';\n public const META_TYPE = 'type';\n public const META_VALUE = 'value';\n public const META_OPERATIONS = 'Operations';\n public const META_OP = 'op';\n public const META_RESOURCE_TYPE = 'resourceType';\n public const META_CREATED = 'created';\n public const META_LAST_MODIFIED = 'lastModified';\n public const META_FORMATTED = 'formatted';\n public const META_EMAILS = 'emails';\n public const META_USERNAME = 'userName';\n public const META_NAME = 'name';\n public const META_STATUS = 'active';\n public const META_PRIMARY = 'primary';\n public const META_ERROR_STATUS = 'status';\n public const META_ERROR_DETAIL = 'detail';\n public const META_LIST_TOTAL_RESULTS = 'totalResults';\n public const META_LIST_RESOURCES = 'Resources';\n public const META_LIST_START_INDEX = 'startIndex';\n public const META_LIST_COUNT = 'count';\n public const META_LIST_ITEMS_PER_PAGE = 'itemsPerPage';\n public const META_SCHEMAS = 'schemas';\n public const META_FILTER = 'filter';\n public const META_TYPE_WORK = 'work';\n public const META_PHONE_NUMBER_TYPE_MOBILE = 'mobile';\n public const META_EMAIL_TYPE_HOME = 'home';\n public const META_CONTAINER_NAME = 'name';\n public const META_CONTAINER_EMAILS = 'emails';\n\n public const RESOURCE_TYPE_USER = 'User';\n\n public const USER_PATCH_ATTR_TITLE = 'title';\n public const USER_PATCH_ATTR_ACTIVE = 'active';\n public const USER_PATCH_ATTR_USERNAME = 'userName';\n public const USER_PATCH_ATTR_FIRST_NAME = 'name.givenName';\n public const USER_PATCH_ATTR_LAST_NAME = 'name.familyName';\n public const USER_PATCH_ATTR_PRIMARY_EMAIL = 'emails[type eq \"work\"].value';\n public const USER_PATCH_ATTR_SECONDARY_EMAIL = 'emails[type eq \"home\"].value';\n public const USER_PATCH_ATTR_PHONE_NUMBER = 'phoneNumbers[type eq \"work\"].value';\n public const USER_PATCH_ATTR_PHONE_NUMBER_MOBILE = 'phoneNumbers[type eq \"mobile\"].value';\n public const USER_PATCH_ATTR_ROLES = 'roles';\n\n public const USER_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [\n self::USER_PATCH_ATTR_TITLE => Mutators\\Attributes\\User\\TitleAttr::class,\n self::USER_PATCH_ATTR_ACTIVE => Mutators\\Attributes\\User\\ActiveAttr::class,\n self::USER_PATCH_ATTR_USERNAME => Mutators\\Attributes\\User\\UsernameAttr::class,\n self::USER_PATCH_ATTR_FIRST_NAME => Mutators\\Attributes\\User\\FirstNameAttr::class,\n self::USER_PATCH_ATTR_LAST_NAME => Mutators\\Attributes\\User\\LastNameAttr::class,\n self::USER_PATCH_ATTR_PRIMARY_EMAIL => Mutators\\Attributes\\User\\PrimaryEmailAttr::class,\n self::USER_PATCH_ATTR_SECONDARY_EMAIL => Mutators\\Attributes\\User\\SecondaryEmailAttr::class,\n self::USER_PATCH_ATTR_PHONE_NUMBER => Mutators\\Attributes\\User\\PhoneNumberPrimaryAttr::class,\n self::USER_PATCH_ATTR_PHONE_NUMBER_MOBILE => Mutators\\Attributes\\User\\PhoneNumberSecondaryAttr::class,\n self::USER_PATCH_ATTR_ROLES => Mutators\\Attributes\\User\\RoleAttr::class,\n ];\n\n public const FILTER_OPERATOR_EQ = 'eq';\n\n public const SUPPORTED_FILTERS_OPERATORS = [\n self::FILTER_OPERATOR_EQ,\n ];\n\n public const USER_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [\n self::USER_FILTER_LOCAL_ID => Filters\\User\\LocalIdFilter::class,\n self::USER_FILTER_USERNAME => Filters\\User\\UserNameFilter::class,\n self::USER_FILTER_FIRST_NAME => Filters\\User\\FirstNameFilter::class,\n self::USER_FILTER_LAST_NAME => Filters\\User\\LastNameFilter::class,\n self::USER_FILTER_EXTERNAL_ID => Filters\\User\\ExternalIdFilter::class,\n self::USER_FILTER_DISPLAY_NAME => Filters\\User\\DisplayNameFilter::class,\n ];\n\n public const USER_FILTER_LOCAL_ID = 'id';\n public const USER_FILTER_USERNAME = 'userName';\n public const USER_FILTER_FIRST_NAME = 'givenName';\n public const USER_FILTER_LAST_NAME = 'familyName';\n public const USER_FILTER_EXTERNAL_ID = 'externalId';\n public const USER_FILTER_DISPLAY_NAME = 'DisplayName';\n\n public const SCIM_SUPPORTED_RESOURCES = [\n self::USER_RESOURCE_PREFIX,\n self::GROUP_RESOURCE_PREFIX,\n ];\n\n public const USER_RESOURCE_PREFIX = 'Users';\n public const GROUP_RESOURCE_PREFIX = 'Groups';\n\n public const OUTGOING_SCHEMAS_SUPPORTED = [\n self::OUTGOING_CORE_USER,\n\n ];\n\n /**\n * Outgoing supported schemas\n */\n public const OUTGOING_CORE_USER = 'urn:ietf:params:scim:schemas:core:2.0:User';\n public const OUTGOING_ERROR = 'urn:ietf:params:scim:api:messages:2.0:Error';\n public const OUTGOING_LIST_RESPONSE = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';\n\n public const OUTGOING_CORE_GROUP = 'urn:ietf:params:scim:schemas:core:2.0:Group';\n\n /**\n * Groups resource constants\n */\n public const GROUP_ATTRIBUTE_DISPLAY_NAME = 'displayName';\n public const GROUP_ATTRIBUTE_EXTERNAL_ID = 'externalId';\n public const GROUP_ATTRIBUTE_ID = 'id';\n public const RESOURCE_TYPE_GROUP = 'Group';\n public const GROUP_FILTER_QUERY_NAME = 'filter';\n public const GROUP_EXCLUDED_ATTRIBUTES = 'excludedAttributes';\n\n public const GROUP_SUPPORTED_FILTER_ATTRIBUTES = [\n self::GROUP_ATTRIBUTE_DISPLAY_NAME,\n ];\n\n public const GROUP_MEMBERS = 'members';\n\n public const SUPPORTED_PATCH_OPERATIONS = [\n self::META_OPERATIONS_ADD,\n self::META_OPERATIONS_REPLACE,\n self::META_OPERATIONS_REMOVE,\n ];\n\n public const GROUP_PATCH_ATTRIBUTE_MEMBERS = 'members';\n public const GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME = 'displayName';\n\n public const GROUP_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [\n self::GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME => Mutators\\Attributes\\Group\\DisplayNameAttr::class,\n self::GROUP_PATCH_ATTRIBUTE_MEMBERS => Mutators\\Attributes\\Group\\MembersAttr::class,\n ];\n\n public const GROUP_FILTER_DISPLAY_NAME = 'displayname';\n\n public const GROUP_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [\n self::GROUP_FILTER_DISPLAY_NAME => Filters\\Group\\DisplayNameFilter::class,\n ];\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Component\\SCIM;\n\nuse Jiminny\\Component\\SCIM\\Builders\\Filters;\n\nclass Constants\n{\n /**\n * HTTP codes\n */\n public const HTTP_OK = 200;\n public const HTTP_CREATED = 201;\n public const HTTP_NO_CONTENT = 204;\n\n public const HTTP_NOT_FOUND = 404;\n public const HTTP_BAD_REQUEST = 400;\n public const HTTP_ACCESS_DENIED = 403;\n\n public const HTTP_ERROR = 501;\n\n /**\n * Users resource constants\n */\n public const USER_FIRST_NAME = 'givenName';\n public const USER_FAMILY_NAME = 'familyName';\n public const USER_STATUS = 'Active';\n public const USER_USERNAME = 'UserName';\n public const USER_EXTERNAL_ID = 'externalId';\n\n public const USER_FIELDS = [\n self::USER_FIRST_NAME,\n self::USER_FAMILY_NAME,\n self::USER_STATUS,\n self::USER_USERNAME,\n ];\n\n public const META_OPERATIONS_REPLACE = 'replace';\n public const META_OPERATIONS_REPLACE_UPPER = 'Replace';\n public const META_OPERATIONS_ADD = 'add';\n public const META_OPERATIONS_ADD_UPPER = 'Add';\n public const META_OPERATIONS_REMOVE_UPPER = 'Remove';\n public const META_OPERATIONS_REMOVE = 'remove';\n\n public const META_ID = 'id';\n public const META_PHONE_NUMBERS = 'phoneNumbers';\n public const META_TITLE = 'title';\n public const META_ROLES = 'roles';\n public const META_PATH = 'path';\n public const META_ENTERPRISE_SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';\n public const META_DEPARTMENT = 'department';\n public const META_META = 'meta';\n public const META_TYPE = 'type';\n public const META_VALUE = 'value';\n public const META_OPERATIONS = 'Operations';\n public const META_OP = 'op';\n public const META_RESOURCE_TYPE = 'resourceType';\n public const META_CREATED = 'created';\n public const META_LAST_MODIFIED = 'lastModified';\n public const META_FORMATTED = 'formatted';\n public const META_EMAILS = 'emails';\n public const META_USERNAME = 'userName';\n public const META_NAME = 'name';\n public const META_STATUS = 'active';\n public const META_PRIMARY = 'primary';\n public const META_ERROR_STATUS = 'status';\n public const META_ERROR_DETAIL = 'detail';\n public const META_LIST_TOTAL_RESULTS = 'totalResults';\n public const META_LIST_RESOURCES = 'Resources';\n public const META_LIST_START_INDEX = 'startIndex';\n public const META_LIST_COUNT = 'count';\n public const META_LIST_ITEMS_PER_PAGE = 'itemsPerPage';\n public const META_SCHEMAS = 'schemas';\n public const META_FILTER = 'filter';\n public const META_TYPE_WORK = 'work';\n public const META_PHONE_NUMBER_TYPE_MOBILE = 'mobile';\n public const META_EMAIL_TYPE_HOME = 'home';\n public const META_CONTAINER_NAME = 'name';\n public const META_CONTAINER_EMAILS = 'emails';\n\n public const RESOURCE_TYPE_USER = 'User';\n\n public const USER_PATCH_ATTR_TITLE = 'title';\n public const USER_PATCH_ATTR_ACTIVE = 'active';\n public const USER_PATCH_ATTR_USERNAME = 'userName';\n public const USER_PATCH_ATTR_FIRST_NAME = 'name.givenName';\n public const USER_PATCH_ATTR_LAST_NAME = 'name.familyName';\n public const USER_PATCH_ATTR_PRIMARY_EMAIL = 'emails[type eq \"work\"].value';\n public const USER_PATCH_ATTR_SECONDARY_EMAIL = 'emails[type eq \"home\"].value';\n public const USER_PATCH_ATTR_PHONE_NUMBER = 'phoneNumbers[type eq \"work\"].value';\n public const USER_PATCH_ATTR_PHONE_NUMBER_MOBILE = 'phoneNumbers[type eq \"mobile\"].value';\n public const USER_PATCH_ATTR_ROLES = 'roles';\n\n public const USER_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [\n self::USER_PATCH_ATTR_TITLE => Mutators\\Attributes\\User\\TitleAttr::class,\n self::USER_PATCH_ATTR_ACTIVE => Mutators\\Attributes\\User\\ActiveAttr::class,\n self::USER_PATCH_ATTR_USERNAME => Mutators\\Attributes\\User\\UsernameAttr::class,\n self::USER_PATCH_ATTR_FIRST_NAME => Mutators\\Attributes\\User\\FirstNameAttr::class,\n self::USER_PATCH_ATTR_LAST_NAME => Mutators\\Attributes\\User\\LastNameAttr::class,\n self::USER_PATCH_ATTR_PRIMARY_EMAIL => Mutators\\Attributes\\User\\PrimaryEmailAttr::class,\n self::USER_PATCH_ATTR_SECONDARY_EMAIL => Mutators\\Attributes\\User\\SecondaryEmailAttr::class,\n self::USER_PATCH_ATTR_PHONE_NUMBER => Mutators\\Attributes\\User\\PhoneNumberPrimaryAttr::class,\n self::USER_PATCH_ATTR_PHONE_NUMBER_MOBILE => Mutators\\Attributes\\User\\PhoneNumberSecondaryAttr::class,\n self::USER_PATCH_ATTR_ROLES => Mutators\\Attributes\\User\\RoleAttr::class,\n ];\n\n public const FILTER_OPERATOR_EQ = 'eq';\n\n public const SUPPORTED_FILTERS_OPERATORS = [\n self::FILTER_OPERATOR_EQ,\n ];\n\n public const USER_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [\n self::USER_FILTER_LOCAL_ID => Filters\\User\\LocalIdFilter::class,\n self::USER_FILTER_USERNAME => Filters\\User\\UserNameFilter::class,\n self::USER_FILTER_FIRST_NAME => Filters\\User\\FirstNameFilter::class,\n self::USER_FILTER_LAST_NAME => Filters\\User\\LastNameFilter::class,\n self::USER_FILTER_EXTERNAL_ID => Filters\\User\\ExternalIdFilter::class,\n self::USER_FILTER_DISPLAY_NAME => Filters\\User\\DisplayNameFilter::class,\n ];\n\n public const USER_FILTER_LOCAL_ID = 'id';\n public const USER_FILTER_USERNAME = 'userName';\n public const USER_FILTER_FIRST_NAME = 'givenName';\n public const USER_FILTER_LAST_NAME = 'familyName';\n public const USER_FILTER_EXTERNAL_ID = 'externalId';\n public const USER_FILTER_DISPLAY_NAME = 'DisplayName';\n\n public const SCIM_SUPPORTED_RESOURCES = [\n self::USER_RESOURCE_PREFIX,\n self::GROUP_RESOURCE_PREFIX,\n ];\n\n public const USER_RESOURCE_PREFIX = 'Users';\n public const GROUP_RESOURCE_PREFIX = 'Groups';\n\n public const OUTGOING_SCHEMAS_SUPPORTED = [\n self::OUTGOING_CORE_USER,\n\n ];\n\n /**\n * Outgoing supported schemas\n */\n public const OUTGOING_CORE_USER = 'urn:ietf:params:scim:schemas:core:2.0:User';\n public const OUTGOING_ERROR = 'urn:ietf:params:scim:api:messages:2.0:Error';\n public const OUTGOING_LIST_RESPONSE = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';\n\n public const OUTGOING_CORE_GROUP = 'urn:ietf:params:scim:schemas:core:2.0:Group';\n\n /**\n * Groups resource constants\n */\n public const GROUP_ATTRIBUTE_DISPLAY_NAME = 'displayName';\n public const GROUP_ATTRIBUTE_EXTERNAL_ID = 'externalId';\n public const GROUP_ATTRIBUTE_ID = 'id';\n public const RESOURCE_TYPE_GROUP = 'Group';\n public const GROUP_FILTER_QUERY_NAME = 'filter';\n public const GROUP_EXCLUDED_ATTRIBUTES = 'excludedAttributes';\n\n public const GROUP_SUPPORTED_FILTER_ATTRIBUTES = [\n self::GROUP_ATTRIBUTE_DISPLAY_NAME,\n ];\n\n public const GROUP_MEMBERS = 'members';\n\n public const SUPPORTED_PATCH_OPERATIONS = [\n self::META_OPERATIONS_ADD,\n self::META_OPERATIONS_REPLACE,\n self::META_OPERATIONS_REMOVE,\n ];\n\n public const GROUP_PATCH_ATTRIBUTE_MEMBERS = 'members';\n public const GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME = 'displayName';\n\n public const GROUP_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [\n self::GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME => Mutators\\Attributes\\Group\\DisplayNameAttr::class,\n self::GROUP_PATCH_ATTRIBUTE_MEMBERS => Mutators\\Attributes\\Group\\MembersAttr::class,\n ];\n\n public const GROUP_FILTER_DISPLAY_NAME = 'displayname';\n\n public const GROUP_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [\n self::GROUP_FILTER_DISPLAY_NAME => Filters\\Group\\DisplayNameFilter::class,\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_jupiter","depth":4,"bounds":{"left":0.69348407,"top":0.09896249,"width":0.04089096,"height":0.01915403},"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":"19","depth":4,"bounds":{"left":0.6871675,"top":0.123703115,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"19","depth":4,"bounds":{"left":0.6988032,"top":0.123703115,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":4,"bounds":{"left":0.71043885,"top":0.123703115,"width":0.00930851,"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 * FROM teams WHERE id = 1;\n\nselect * from crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 283;\nSELECT * FROM crm_fields WHERE id = 2234;\nSELECT * FROM crm_field_values WHERE crm_field_id = 2234;\n\nselect * from crm_profiles where user_id = 143;\n\nselect * from record_types where crm_configuration_id = 39; # 0121K000001MHElQAO,0121K000001MHEqQAO\nselect * from business_processes where crm_configuration_id = 39;\n# 01941000000H669AAC, 01941000000H66JAAS\n\nselect * from record_type_field_values\n where record_type_id IN (24);\n\nselect * from crm_field_values where id IN (2730);\n\nselect * from crm_configurations where id = 39;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce'; #1035\n\n\nselect * from users where team_id = 1; # 222 group 3\nSELECT * FROM activities WHERE user_id = 222 order by id desc;\nselect * from sidekick_settings where team_id = 1;\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\n\nselect * from activities where crm_configuration_id = 2\nand provider = 'ms-teams' and id = 608765;\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id = '59523413338';\n\nselect * from sidekick_settings where team_id = 2;\n\nSELECT * FROM activities WHERE id = 608660;\nselect * from activity_summary_logs where activity_id = 608660;\nselect * from ai_prompts where transcription_id = 11214;\n\n# ********************************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('ed78a437-2804-450e-ab2f-56ab1c641346') = uuid;\n# id: 608818, crm: 59628809737\nSELECT * FROM activities WHERE uuid_to_bin('36b06e55-afdd-4782-8dee-c624cd0af191') = uuid;\n# id: 608821, crm: 59632069252\nSELECT ce.start_time, ce.end_time, a.id, a.uuid, crm_provider_id, calendar_event_id, title,\nplaybook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id,\nscheduled_start_time, scheduled_end_time, actual_start_time, actual_end_time, a.created_at\nFROM activities a\njoin calendar_events ce on a.calendar_event_id = ce.id\nWHERE a.id IN (608818, 608821);\n\nselect * from users where team_id = 1;\nselect * from team_settings where team_id = 1;\nselect * from crm_profiles where crm_configuration_id = 39 order by user_id;\n\nselect * from team_features where team_id = 1;\n\nselect * from users where team_id = 2;\n\nSELECT * FROM activities WHERE uuid_to_bin('ec7647e9-5225-458b-b475-f31aa2769204') = uuid; # 612639\n# Preslava N. Ivanova, grou id 3\n\nSELECT * FROM opportunities WHERE uuid_to_bin('a2928fe5-aec5-46cb-85d9-7654c89e46a6') = uuid;\n\nselect * from activities where opportunity_id = 344 and actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00';\n\nselect\n a.id,\n a.type,\n a.scheduled_start_time,\n a.actual_start_time,\n a.created_at,\n a.opportunity_id,\n a.status\nFROM activities a\nWHERE opportunity_id = 344\nand status IN ('completed', 'received', 'delivered')\nand (\n (a.actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')\nOR (a.created_at between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')\nOR (a.scheduled_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00'))\n;\n\nSELECT * FROM users WHERE id = 222;\n\nSELECT * FROM crm_profiles WHERE user_id = 222;\nselect * from crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 281;\n\nselect * from group_deal_risk_types;\n\nselect * from opportunities where team_id = 1;\n\nSELECT * FROM opportunities WHERE id = 315;\nSELECT * FROM crm_field_data WHERE object_id = 315;\nselect * from crm_field_data where object_id = 260;\n\nselect * from generic_ai_prompts where subject_id = 315;\n\nselect * from teams; # 36, 21, 121, james.graham@bullhorn.jiminny.com\nSELECT * FROM social_accounts WHERE sociable_id = 121 and provider = 'bullhorn';\n\n# ************************************************************************************\nselect * from teams where id = 1;\nselect * from crm_configurations where id = 39;\nselect * from users where team_id = 1;\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 1;\n# 1 - 00541000004281rAAA\n# 204 - 0052g000003freeAAA\n# 429 - 0052g000003qGOiAAM\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce';\n\nselect * from activities where type = 'softphone'\nand created_at > '2024-12-11 15:24:36' order by id desc;\n\nselect * from activity_providers where team_id = 1;\nselect * from activity_provider_users where activity_provider_id = 328;\n\nselect * from opportunities where crm_configuration_id = 39\nAND account_id = 178 AND is_closed = false\norder by created_at DESC;\n\nselect * from contacts where id = 3952;\nselect * from accounts where id = 178;\n\n# ************************************************************************************\nselect * from teams where id = 36;\nselect * from crm_configurations where id = 21;\nselect * from users where team_id = 36;\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 36;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 36\nand sa.provider = 'bullhorn';\n\nselect * from social_accounts where id = 348;\nUPDATE social_accounts SET\nprovider_user_token = '21442_6802599_91:41179a58-21e7-4d7c-ad58-56bb666b2f65',\nprovider_refresh_token = '21442_6802599_91:01c6b335-3f2a-42e4-85ff-8a08fa65fceb',\nexpires = 1733998131,\nstate = 'connected'\nWHERE id = 348;\n\n# ************************************************************************************\nselect * from teams where id = 31;\nselect * from crm_configurations where id = 18;\n\nselect * from users where team_id = 31; # 257\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 31;\n\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 31\nand sa.provider = 'close';\n\nselect * from contacts where crm_configuration_id = 18;\n\n# ********************** NEPTUNE **************************************************************\nselect * from teams;\nselect * from users where id IN (1030, 1035, 1052);\nselect * from crm_configurations;\n\nselect * from users where team_id = 65; # 257\nselect * from team_settings where team_id = 65; # 257\nselect * from invitations where team_id = 65; # 257\nselect * from users where email = 'integration-account@jiminny.com'; # 257\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 65;\n\nselect * from crm_configurations where id = 53;\nselect * from accounts where crm_configuration_id = 53 order by id desc;\nselect * from leads where crm_configuration_id = 53 order by id desc;\nselect * from contacts where crm_configuration_id = 53 order by id desc;\nselect * from opportunities where crm_configuration_id = 53 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 53 order by id desc;\nselect * from crm_fields where crm_configuration_id = 53 order by id desc;\nselect * from crm_field_values where crm_field_id = 3341 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 53 order by id desc;\nselect * from stages where crm_configuration_id = 53 order by id desc;\n\n\nselect * from crm_profiles where crm_configuration_id = 13;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 65\nand sa.provider = 'integration-app';\n\nselect * from contacts where crm_configuration_id = 13;\n\nselect * from social_accounts where sociable_id = 283;\n\nSELECT * FROM opportunities WHERE crm_provider_id = '006O400000E9bzeIAB';\n\nselect * from activity_providers where team_id = 65;\nSELECT * FROM activities WHERE crm_configuration_id IN (51, 52, 53);\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 65\n;\n\n# ***************************** STAGING ********************************************\nSELECT * FROM teams;\nSELECT * FROM teams WHERE id = 88;\nSELECT * FROM teams WHERE id = 89;\nselect * from team_settings where team_id = 89;\nSELECT * FROM users WHERE team_id = 89;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 89;\n\nselect * from users;\nSELECT * FROM social_accounts WHERE sociable_id = 1761;\nSELECT * FROM crm_configurations WHERE id = 70;\nselect * from accounts where crm_configuration_id = 70 order by id desc;\nselect * from leads where crm_configuration_id = 70 order by id desc;\nselect * from contacts where crm_configuration_id = 70 order by id desc;\nselect * from opportunities where crm_configuration_id = 70 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 70 order by id desc;\nselect * from crm_fields where crm_configuration_id = 70 order by id desc;\nselect * from crm_field_values where crm_field_id = 3536 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 70 order by id desc;\nselect * from stages where crm_configuration_id = 70 order by id desc;\nselect * from business_processes where crm_configuration_id = 70 order by id desc;\nselect * from business_process_stages where business_process_id = 34;\n\nselect * from contacts where id = 10468;\n\nselect * from crm_layouts where crm_configuration_id = 70;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 388;\nSELECT * FROM crm_fields WHERE id IN (3533,3534,3535);\n\nselect * from activities where crm_configuration_id = 70\nand (account_id IS NOT NULL or lead_id IS NOT NULL or contact_id IS NOT NULL or opportunity_id IS NOT NULL) order by id desc;\n\nSELECT * FROM activities WHERE uuid_to_bin('2e10b60f-8a61-41c5-a3d4-28835353dc65') = uuid;\nSELECT * FROM activities where crm_configuration_id = 69 ;\n\nSELECT * FROM users WHERE email LIKE '%jiminny_web_sa2@jiminny.com%';\nSELECT * FROM activities WHERE uuid_to_bin('5a150c93-40fc-42ec-b3bd-c1d328e09f6e') = uuid;\nSELECT * FROM opportunities WHERE id = 385;\n\nselect * from participants p\njoin activities a on p.activity_id = a.id\nwhere a.crm_configuration_id = 70\nand (p.lead_id IS NOT NULL or p.contact_id IS NOT NULL);\nSELECT * FROM participants WHERE id = 1013638;\n\nselect * from teams where id = 90;\nselect * from users where team_id = 90;\nselect * from social_accounts where social_accounts.sociable_id IN (1960,1760);\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 71;\nselect * from invitations where team_id = 90;\n\nselect * from crm_configurations where id = 71;\nselect * from accounts where crm_configuration_id = 71 order by id desc;\nselect * from leads where crm_configuration_id = 71 order by id desc;\nselect * from contacts where crm_configuration_id = 71 order by id desc;\nselect * from opportunities where crm_configuration_id = 71 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 71 order by id desc;\nselect * from crm_fields where crm_configuration_id = 71 order by id desc;\nselect * from crm_field_values where crm_field_id = 3341 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 71 order by id desc;\nselect * from stages where crm_configuration_id = 71 order by id desc;\n\nselect * from users order by secondary_email desc;\nselect u.id, u.email, u.status, sa.id, sa.provider_user_id from social_accounts sa\n join users u on sa.sociable_id = u.id\nwhere sa.provider = 'google' and u.email LIKE 'aneliya%';\n\nselect * from failed_jobs order by id desc;\n\nselect * from users where email = 'ben.allwright@learningpeople.co.uk' or secondary_email = 'ben.allwright@learningpeople.co.uk';\n\nselect * from teams;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 39;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type = 'task';\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce';\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('c38b3895-fd0f-4b1f-9fb2-c170dba137c6') = uuid;\nSELECT * FROM crm_configurations WHERE id = 70;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1;\nselect * from users where team_id = 1;\n\nselect o.id, o.name,o.close_date, u.id, u.name, u.group_id, r.id, r.display_name, g.name, g.scope from opportunities o\njoin users u on o.user_id = u.id\njoin groups g on u.group_id = g.id\njoin role_user ru on u.id = ru.user_id\njoin roles r on ru.role_id = r.id\nwhere o.crm_configuration_id = 39 and close_date > '2024-01-01 00:00:00';\n\nselect * from role_user where user_id = 143;\nselect * from roles;\n\nselect * from role_user;\nselect * from groups where id = 9;\nselect * from scope_groups where group_id = 9;\n\n# ************************************************************************************\nselect * from teams where id = 36;\nselect * from crm_configurations;\nSELECT * FROM social_accounts WHERE sociable_id = 121;\n\nhttps://crmsandbox.zoho.com/crm/jiminnyw4/tab/Leads/4776201000005049105\nhttps://crmsandbox.zoho.com/crm/\n\nhttps://crm.zoho.com/crm/org3469620/tab/Leads/230045000229559080\n https://crm.zoho.com/crm/\n org3469620\n\nSELECT * FROM activities WHERE uuid_to_bin('03382d20-c8bc-48e7-a3d4-90b52fa5ceab') = uuid;\n\nselect * from users where email LIKE \"%mobile_automation_%\";\nselect * from social_accounts where sociable_id IN (2228);\nselect * from crm_profiles where user_id IN (2222,2223,2226,2227);\n\nselect * from teams order by id desc;\nSELECT * FROM users WHERE id = 2229;\nSELECT * FROM crm_profiles WHERE user_id = 2229;\nselect * from opportunities where crm_configuration_id = 88;\nselect * from crm_fields where crm_configuration_id = 88;\nselect * from crm_profiles where crm_configuration_id = 88;\n\nSELECT * FROM teams WHERE id = 1;\n\nSELECT * FROM users WHERE id = 143;\nSELECT * FROM users WHERE uuid_to_bin('fde193d3-06a2-4e1a-8895-62b94039215d') = uuid;\nSELECT * FROM teams WHERE uuid_to_bin('73385071-a756-42ae-9c73-8b53f2309467') = uuid;\n\nhttps://app.staging.jiminny.com/ondemand?\n min_duration=1\n &\n only_recorded=1\n &\n user_id%5B%5D=641f1acb-16b8-42d1-8726-df52979dad0e\n &\n sequence_number=2\n\n select * from users where team_id = 1 and email like '%stoyan%'\n\nselect * from coaching_feedbacks;\n\nselect * from teams;\nSELECT * FROM users WHERE team_id = 36;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 19\nand sa.provider = 'pipedrive';\n\nselect * from users where id = 143;\n\nSELECT * FROM users WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\nSELECT * FROM teams WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\nSELECT * FROM activity_shares WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\n\nselect * from users where team_id = 2;\nselect * from activities where crm_configuration_id = 39\nand activities.scheduled_start_time BETWEEN '2025-04-09 00:00:00' AND '2025-04-09 23:59:59'\nAND user_id = 143\norder by id desc;\n\n# ************************************************************************************\nselect * from teams where id = 142; # 2312, 126\nselect * from team_settings;\nselect * from users where team_id = 142; # 21642\nSELECT * FROM social_accounts WHERE sociable_id = 21642;\nSELECT * FROM crm_profiles cp join users u ON u.id = cp.user_id WHERE team_id = 142;\nselect * from crm_profiles where id IN (93);\nselect * from invitations;\nselect * from team_features where team_id = 1;\n\nSELECT * FROM crm_configurations WHERE id = 126;\nselect * from accounts where crm_configuration_id = 126 order by id desc;\nselect * from leads where crm_configuration_id = 126 order by id desc;\nselect * from contacts where crm_configuration_id = 126 order by id desc;\nselect * from opportunities where crm_configuration_id = 126 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 126 order by id desc;\nselect * from crm_fields where crm_configuration_id = 126 # 11060\n# and type IN ('picklist', 'status')\n# and object_type = 'task'\norder by id desc;\n# 5731,5732,5733\nselect DISTINCT crm_field_id from crm_field_values where crm_field_id IN (11151,12239,12215,12185,12175,12165,12144,12137,12127,12109,12107,12105,12103,12092,12037,12005,12003,11987,11969,11958,11951,11942,11931,11924,11921,11917,11915,11901,11893,11883,11872,11870,11868,11866,11839,11833,11821,11793,11780,11777,11769,11757,11737,11735,11656,11645,11638,11629,11618,11611,11602,11591,11584,11581,11558,11544,11543,11534,11532,11529,11527,11503,11497,11493,11488,11470,11468,11457,11455,11397,11387,11372,11363,11348,11323,11318,11309,11301,11300,11292,11290,11286,11284,11256,11252,11242,11237,11233,11219,11176,11160) order by id desc;\nselect * from crm_layouts where crm_configuration_id = 126 order by id desc;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id in (300,299,298);\nselect * from stages where crm_configuration_id = 126 order by id desc;\nselect * from business_processes where crm_configuration_id = 126 order by id desc;\nselect * from business_process_stages where business_process_id IN (76,75,74,73);\nselect * from playbooks where team_id = 142;\nselect * from playbook_layouts where playbook_id IN (108);\nSELECT * FROM playbook_categories WHERE playbook_id IN (108);\n\nselect * from teams where id = 130;\nSELECT * FROM social_accounts WHERE sociable_id = 2291;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 2\nand sa.provider = 'hubspot';\n\nSELECT * FROM activities\n WHERE crm_configuration_id = 110;\n\nselect * from teams;\nselect * from crm_configurations;\n\nSELECT * FROM activities WHERE id = 628773;\nSELECT * FROM crm_profiles WHERE user_id = 1460;\nSELECT * FROM social_accounts WHERE sociable_id = 2291;\n\nselect * from teams;\nselect ru.*, pr.*, p.* from users u join role_user ru on ru.user_id = u.id\njoin permission_role pr on pr.role_id = ru.role_id\n join permissions p on p.id = pr.permission_id\nwhere team_id = 495 and p.name IN ('dial');\n\nselect * from teams where id = 145;\nselect * from crm_configurations where id = 129;\nselect * from social_accounts where sociable_id = 2317;\nSELECT * FROM activities WHERE uuid_to_bin('8dbab184-a333-4268-ad57-fb41f8d53a9a') = uuid;\n\nselect * from teams where id = 1;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 280;\nSELECT * FROM crm_layout_entities WHERE id = 5507;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type IN ('event');\n\nselect * from teams;\nselect * from activities where crm_configuration_id = 14;\n\nSELECT * FROM social_accounts where provider = 'copper';\n\nselect * from activities where id = 628467;\nselect * from participants where activity_id = 628467;\n\nSELECT * FROM contacts WHERE id = 3969;\nSELECT * FROM accounts WHERE id = 177;\n\nSELECT * FROM activities WHERE uuid_to_bin('4eb54c77-cfa3-2bd4-84a7-9ed46a21c988') = uuid;\n\n# ********************* BH\nselect * from teams where id = 36;\nSELECT * FROM crm_configurations WHERE id = 21;\nselect * from activities where crm_configuration_id = 21 and id = 607901;\nselect * from activities where crm_configuration_id = 21;\n\nselect * roles;\nselect * from permissions;\nselect * from permission_role where permission_id = 226;\n\nselect * from migrations order by id desc;\n\n# mercury\n# neptune\n# earth\n\nselect * from teams;\nselect * from teams where id = 19;\nselect * from teams where id = 27;\nselect * from users where team_id = 27;\nSELECT * FROM crm_configurations WHERE id = 42;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 19\nand sa.provider = 'pipedrive';\n\nselect * from activities where id = 631461;\nSELECT * FROM crm_field_values WHERE crm_field_id = 180;\n\nselect * from teams where id = 2;\nSELECT * FROM social_accounts WHERE sociable_id = 89;\n\nSELECT * FROM activities WHERE uuid_to_bin('ba0c029a-bc14-4e17-8603-64174acebcbb') = uuid; # 634273\nselect * from activity_summary_logs where activity_id = 634273;\n\nselect * from sidekick_settings where team_id = 2;\n\nselect * from teams; # 2, 2\nSELECT * FROM crm_configurations WHERE team_id = 2; # 2\nselect * from team_features where team_id = 2;\nselect * from features;\nSELECT * FROM opportunities WHERE crm_configuration_id = 2 and crm_provider_id = '51317301383';\nSELECT * FROM opportunities WHERE crm_configuration_id = 2 order by id desc;\n\nselect * from automated_reports order by id desc;\nselect * from automated_report_results order by id desc;\nselect * from users where team_id = 1 and id IN (7160, 3248);\nselect * from migrations order by id desc;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1052 and sa.provider = 'hubspot';\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 = 565;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 175;\nselect * from playbook_categories where playbook_id = 175;\nselect * from users where team_id = 1052;\nselect * from users where id = 7160;\nselect * from crm_profiles where user_id = 7160;\nselect * from features;\nselect\n *\n# id, uuid, type, provider, playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id, stage_id,\n# crm_configuration_id, crm_provider_id, transcription_id, status\nfrom activities where crm_configuration_id = 1 and type = 'conference'\n# and crm_provider_id IS NOT NULL\nand provider != 'uploader' and actual_start_time IS NOT NULL\nORDER by id desc;\nselect * from activities where id = 54747783; # 00UO400000pCzojMAC\n\nselect p.id, p.activity_type, pc.id, pc.name\nFROM playbooks p\njoin playbook_categories pc on p.id = pc.playbook_id\nwhere p.team_id = 1 and p.activity_type = 'event';\n\nSELECT * FROM crm_fields WHERE crm_configuration_id = 1 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id = 4;\n\nselect * from crm_layouts cl join playbook_layouts pl on cl.id = pl.layout_id\nwhere crm_configuration_id = 1 and pl.playbook_id = 175;\n\nselect * from teams;\nSELECT r.* FROM automated_reports r\njoin teams t on r.team_id = t.id\nWHERE r.frequency = 'daily'\n and r.status = 1\nAND t.status = 'active'\nAND (r.expires_at >= now() OR r.expires_at IS NULL);\n\nselect * from automated_report_results where report_id IN (18, 33);\n\nselect * from users where team_id = 1 and id = 1047;\nSELECT * FROM social_accounts WHERE sociable_id = 1047;\n\nselect * from activity_searches where id = 10932;\nselect * from activity_search_filters where activity_search_id = 10932;\nselect * from automated_reports order by id desc;\nselect * from automated_report_results order by id desc;\nselect * from automated_reports where id IN (55);\nselect * from automated_report_results where id IN (81);\nselect * from users where id IN (10633, 13987, 11985);\nselect * from users where group_id IN (3710);\n\nSELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;\nSELECT * FROM automated_report_results WHERE uuid_to_bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;\n\nselect * from teams;\nselect * from accounts where team_id = 1;\n\nselect * from automated_report_results where media_type = 'pdf' and status = 2;\nSELECT * FROM automated_report_results WHERE uuid_to_bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid;\n\nselect * from teams where id = 1029;\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 = 1029 and sa.provider = 'pipedrive';\n\n[\n {\n \"user_id\": \"23460 (owner)\",\n \"email\": \"integration-account@pipedrive.jiminny.com\",\n \"id\": 69,\n \"sociable_id\": 23460,\n \"provider_user_id\": \"19555731\",\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,\n \"refresh_token_expires\": null,\n \"provider\": \"pipedrive\",\n \"state\": \"connected\",\n \"auth_scope\": \"base,deals:full,activities:full,contacts:full,search:read\",\n \"retry_after\": null,\n \"created_at\": \"2025-04-16 08:23:28\",\n \"updated_at\": \"2026-05-18 07:13:18\",\n \"provider_user_token_encrypted\": \"eyJpdiI6Ik9oYzBwcTVteWN4ajBRaDdMb0FjWGc9PSIsInZhbHVlIjoiQUNMbjU5UHR2Q1RnbWRXMEU1TUx6UVpRU3gzdVc5WktmTE4rVlhXa3lRaGhyUUlZMVZRWEJuR0JaWWhZZXNPRlBuanhuYU5MVHZ5TG9NTVVjNjJSUUpZZ2VhbGYxbHg0UzJEdTVmQjNFZnJRZkMwYjd0N2RMZ05GRS9IR3c2K0NoVjBjYTA5UG12SkxHeDlDMGVNN3ptUWUzblFiTngyYzR1eUpHSEYrdEwvZm0yZklGYjBSNEtTR2ZGazhLM1hqT3lVbjFobDNPZ0d3anFlcjhKcXpERlZGOVN1YmFyNDIvM1BFRDFMYnp4WEI4TGVLM2xYcy9CL0RDOWlQNHI3N0NwWnJPMWRtZllmM2ZKeE9TV2NBeDZxL2M1YnlSVzd3ZW96T3F1QmtBYXBHYkUraGcvdCtRajlYZXBjVVBSdFlMUjVPVDVJbDdyenVoWjMrbVJvU3ZZR1dQZ3pqQ3F3aDF2U2xPZWZIN3BCWVFLNXpxQUtDb2pIK0xHc1E3SklSM3Q0VkNSbm9oK2pFK3hLaW54T1dWbEVneUp0RGhhdVBuOFI4MXROc3dZWnFnTUpiaDVMMnZ4QmlRM3k4QWFlMVFWUFYvdGhJQzZBYnhBQmhWa2ZKN1ZhSnhpaExxbmlTemgzUWw3aXJtWjlSMlhmd0lWMDNDN1N3My9Ua0hCL2xqY3RkVFhMSjFJMDRjOE5DWlgrZ3FMVXN6RWlwUE5GWERZdG1xVjVxOFlLRGs2VVJKS3FLeWRxQjYxdDh4Z2JJNXhlWEZ3dkQ4SGtybDNUcndzblFHeVJNRkYraFh2UDFIUTdMQ1BZa3dEU1dBbzk5K0dyT2RNVFBZZUJpRytSck5pYlI1YUZyMmhUNEZCdWxHYmJLREtzbUpjVkhvV0RoejJpbm1SWHlNaXE5M0RhcS94UW9EdFoweWF3bVFVY0dTZWFPSXBmOCtDYndia215cmtyZU1oT0Exam1CV2tPblNhYjY4clVEeUs3anVHUmNHeS9YLzRha1VhbGl3N3lwaDlzZnRhQUZta2s4eFllNHgzRklSRmNyazJ4dlBDMnByNCtBRjNaVjJCTT0iLCJtYWMiOiJkYTQxZDY1OTY2ZTljMTgyZWRhNGEzMGZjZDc2MjBjN2NlNzU2YTViNGQxNWE1NTI2ZmI1MWQyYjQ2ODYxZmEwIiwidGFnIjoiIn0=\",\n \"provider_refresh_token_encrypted\": \"eyJpdiI6Imt2bGxlSmxUK05GMjF0dEtPaTMrUlE9PSIsInZhbHVlIjoiUXZHTElZRXkreHFxUU02SnZ4eVBacG9WWTRlVkd0USszV3JyVFlpU2ZaY25GSWo2WFcrRzNlbFRlUXRQczNwSXRCcEdvZEpveG9jMzBDSTgwdnZLQnc9PSIsIm1hYyI6ImQxYWI0NzU5Nzg5MDI4YWVhZmQ4Mjg1YzhkZDQzMjRkYWYwYTdhZTY5MDMxMjc0OWNiYjY0Nzc3NDQ0MTEyY2EiLCJ0YWciOiIifQ==\",\n \"encryption_key\": \"0x01020300786192D9D96DD60D3D1EBC9DFAEE5F0C45EE80165CF3F3D2B3B627026AA7CFC7CA0128DD463535D32EE491ADBADF8B07596B0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040C7FB1319048ECB2EA3F23B995020110802B52D22F5EAD341AB238FBBCB6093156E443876A664BA5555D722565C2B2D04422C868CD7350555E3CC74221\",\n \"sociable_type\": \"user\",\n \"owner_id\": 23460\n },\n {\n \"user_id\": \"23463\",\n \"email\": \"jiminny_web_sa@pipedrive.jiminny.com\",\n \"id\": 72,\n \"sociable_id\": 23463,\n \"provider_user_id\": \"23270841\",\n \"provider_user_token\": \"v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:txqCuWLeVhgwiaFqXIvQWWrtrnFIy_4lT3VCr-sRB4g6_2lK8KcQ_6ka_qFmZhr-IeIAKmAImx6H1iIKx4Ab7XZ5MnKIh03GKbHjI0n0rGT9UYkeH21jKOxJvKaSX_TyLbxFPR6irPQyvqcpBClXI52gVJH01KzZy_dMTHFXhhDLOIhEpSrQXHG7Qo8q7OuBeSPZrU1ALi9kmAm4GTpzGTbzfl-hUt9IAfPunJOCyv3mf2Tl-MT8EyQgOFPrsP3yz9UlSyVhb40zO_bCnUrqNxjwgm_E6vgpVrwULTQbHe-43Dq-TRetjceUzT88GBgVJ0UdxXP5BRBVXcL5ir8-9ZTMaNU\",\n \"provider_refresh_token\": \"5034113:23270841:34790b44838f5fd422c2d2c82e00f1ecf2178ad1\",\n \"expires\": 1753837219,\n \"refresh_token_expires\": null,\n \"provider\": \"pipedrive\",\n \"state\": \"full-refresh\",\n \"auth_scope\": \"base,deals:full,activities:full,contacts:full,search:read\",\n \"retry_after\": null,\n \"created_at\": \"2025-04-16 10:41:12\",\n \"updated_at\": \"2025-07-30 01:00:17\",\n \"provider_user_token_encrypted\": \"eyJpdiI6InVEVEl2SzIxMjd1bkNDWG9lY3YvQ0E9PSIsInZhbHVlIjoiRlJLbDZ3ZHo2dHMxUWQwdGU2YUZjV3lPWHlxQTJ0eWh4S0RTMjlSaThVcktoaWhXcTd2UXl4Mjg4bW5UUnZCZEQ5NXpuQTVKOURiMDNIa3l3K0lSWCt5azRBOEdHbitWQXhxeEpMVUZ1dnF2NVl1TTZLelZOaGNvRlBLeGpIWlpoRGloUEprd2xoNUFPcTlLcUd3WVlUU2svR1NOeXBYQ2NnMWhnK1V2aytOeVVMNzJGdVZXMU1JS3BSaGNCcmxkVjEwQ01mQXNBdWNhS1lMZWZobnZwcHBkN1R4bUVDRUNYdnNtSVJkdG5MdkN3djJBT0hMRDl1MHFGbnl4WU13ejBkUWsrdUljWkZhcTJlN0JDSGdTVzlPY0FGMUJlZi9WRGpkMUk5R20wblYwSk9VR2FuaHpLTzJNeitMbnF1V1NEMUUxRmYzaDRGZDMyaXd3Z0FjQno4SzVoYjUyTmV3UXNpRlF4TGZKNVl3dUFqdGhKVWJjRVlUUXRGalBpaXJvSGJmbS8rd25aQ2Zvc05saHRDRjlHV1VEUFFiRU5xbWRVNkxFSXV0RUZyaUlYNWMwMmhnZ0Y1VUQ4eEFkY2QyWXpnR0NidkVJSWdjVGljUjA3NDdpZW9WUHhtSlpGSGdNU2hRUTA5ZW03RGpiRFdrdytkOHJXSUxlazZNaG9iaUg2NFZYdEc3YklMeFZvblBzWmVRSDcvN2M4WUNtL3h4S2IrUW00cXhialBia3BJcW5XallBNlV5WWdhcE1ZVFBBM3RSSUVBamYvOGZEQWM5a2FJMGwyWkRSU3dlTEtPemZlQ3RXRGNDcEdYRHdMNTlTQVg2SUdUN0hVaXdZT1dUOUlrVzkrZHFBemhwWXg1cm4rSy9UOHUzcnNSM2dISlhBRTEyVUNyTkZYaFJYUlN1a2RKVHhhM2dHckR3a1JGaVZ2Wk9BVnhTclVpSEhwWTVpQTlJbXVkOUxSTGpRbDk0a1VtbE9QMVAvN3VlVEhJUHd2elowd0laNVIzZ3M3N0ZOK0NDakIwQ2FicGxoMDBhTXI0VUppUmFOZHdlWUdGV21NNFQ4RU1nY0dnWT0iLCJtYWMiOiI0ZTU4ZmJkNTdkYmY0NGE4NTJjZjlhNDExNzE2YjhlOWM2NTA5OGY2MDA4OTcyZDVlOTljY2JjZDhmMjBhMDUyIiwidGFnIjoiIn0=\",\n \"provider_refresh_token_encrypted\": \"eyJpdiI6IkJGMkdRVHRKM2VTcitKNGcvQWJtUGc9PSIsInZhbHVlIjoicmFyRkxPZ1Rybm1ORXlEVjJ2TXFGTzJtM3hWaFhnUVVHN2ZlR1lRM0I5d3ozbnZTcU5EdzJqRkI2elhyNWhlenRTUXV3bjk0N1JXeklDMVAyUzBKcHc9PSIsIm1hYyI6ImJhODVjMGQyZDE3Y2ExNjc2OWVjYWJiNmFjYWVkODIyMTMyNWVhYTExMTgwYTEyMTU0MzUzZGE1YjQ5YzQ5ZjEiLCJ0YWciOiIifQ==\",\n \"encryption_key\": \"0x01020300788C37CDF66ABE9301A68D5D4866AC0C197E04EEE4D904F20A59991322EBAE252301BEF4B24FF01359E934E5654617E4EEAC0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040CEB00EF45BDEA999A5558889E020110802B925F372F7BEFAF0B45E48686113D1DA430ECFCC07B1F61BA6828CC44235278EDB05C486E8068D0BE737D91\",\n \"sociable_type\": \"user\",\n \"owner_id\": 23460\n }\n]","depth":4,"on_screen":true,"value":"SELECT * FROM teams WHERE id = 1;\n\nselect * from crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 283;\nSELECT * FROM crm_fields WHERE id = 2234;\nSELECT * FROM crm_field_values WHERE crm_field_id = 2234;\n\nselect * from crm_profiles where user_id = 143;\n\nselect * from record_types where crm_configuration_id = 39; # 0121K000001MHElQAO,0121K000001MHEqQAO\nselect * from business_processes where crm_configuration_id = 39;\n# 01941000000H669AAC, 01941000000H66JAAS\n\nselect * from record_type_field_values\n where record_type_id IN (24);\n\nselect * from crm_field_values where id IN (2730);\n\nselect * from crm_configurations where id = 39;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce'; #1035\n\n\nselect * from users where team_id = 1; # 222 group 3\nSELECT * FROM activities WHERE user_id = 222 order by id desc;\nselect * from sidekick_settings where team_id = 1;\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\n\nselect * from activities where crm_configuration_id = 2\nand provider = 'ms-teams' and id = 608765;\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id = '59523413338';\n\nselect * from sidekick_settings where team_id = 2;\n\nSELECT * FROM activities WHERE id = 608660;\nselect * from activity_summary_logs where activity_id = 608660;\nselect * from ai_prompts where transcription_id = 11214;\n\n# ********************************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('ed78a437-2804-450e-ab2f-56ab1c641346') = uuid;\n# id: 608818, crm: 59628809737\nSELECT * FROM activities WHERE uuid_to_bin('36b06e55-afdd-4782-8dee-c624cd0af191') = uuid;\n# id: 608821, crm: 59632069252\nSELECT ce.start_time, ce.end_time, a.id, a.uuid, crm_provider_id, calendar_event_id, title,\nplaybook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id,\nscheduled_start_time, scheduled_end_time, actual_start_time, actual_end_time, a.created_at\nFROM activities a\njoin calendar_events ce on a.calendar_event_id = ce.id\nWHERE a.id IN (608818, 608821);\n\nselect * from users where team_id = 1;\nselect * from team_settings where team_id = 1;\nselect * from crm_profiles where crm_configuration_id = 39 order by user_id;\n\nselect * from team_features where team_id = 1;\n\nselect * from users where team_id = 2;\n\nSELECT * FROM activities WHERE uuid_to_bin('ec7647e9-5225-458b-b475-f31aa2769204') = uuid; # 612639\n# Preslava N. Ivanova, grou id 3\n\nSELECT * FROM opportunities WHERE uuid_to_bin('a2928fe5-aec5-46cb-85d9-7654c89e46a6') = uuid;\n\nselect * from activities where opportunity_id = 344 and actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00';\n\nselect\n a.id,\n a.type,\n a.scheduled_start_time,\n a.actual_start_time,\n a.created_at,\n a.opportunity_id,\n a.status\nFROM activities a\nWHERE opportunity_id = 344\nand status IN ('completed', 'received', 'delivered')\nand (\n (a.actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')\nOR (a.created_at between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')\nOR (a.scheduled_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00'))\n;\n\nSELECT * FROM users WHERE id = 222;\n\nSELECT * FROM crm_profiles WHERE user_id = 222;\nselect * from crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 281;\n\nselect * from group_deal_risk_types;\n\nselect * from opportunities where team_id = 1;\n\nSELECT * FROM opportunities WHERE id = 315;\nSELECT * FROM crm_field_data WHERE object_id = 315;\nselect * from crm_field_data where object_id = 260;\n\nselect * from generic_ai_prompts where subject_id = 315;\n\nselect * from teams; # 36, 21, 121, james.graham@bullhorn.jiminny.com\nSELECT * FROM social_accounts WHERE sociable_id = 121 and provider = 'bullhorn';\n\n# ************************************************************************************\nselect * from teams where id = 1;\nselect * from crm_configurations where id = 39;\nselect * from users where team_id = 1;\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 1;\n# 1 - 00541000004281rAAA\n# 204 - 0052g000003freeAAA\n# 429 - 0052g000003qGOiAAM\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce';\n\nselect * from activities where type = 'softphone'\nand created_at > '2024-12-11 15:24:36' order by id desc;\n\nselect * from activity_providers where team_id = 1;\nselect * from activity_provider_users where activity_provider_id = 328;\n\nselect * from opportunities where crm_configuration_id = 39\nAND account_id = 178 AND is_closed = false\norder by created_at DESC;\n\nselect * from contacts where id = 3952;\nselect * from accounts where id = 178;\n\n# ************************************************************************************\nselect * from teams where id = 36;\nselect * from crm_configurations where id = 21;\nselect * from users where team_id = 36;\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 36;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 36\nand sa.provider = 'bullhorn';\n\nselect * from social_accounts where id = 348;\nUPDATE social_accounts SET\nprovider_user_token = '21442_6802599_91:41179a58-21e7-4d7c-ad58-56bb666b2f65',\nprovider_refresh_token = '21442_6802599_91:01c6b335-3f2a-42e4-85ff-8a08fa65fceb',\nexpires = 1733998131,\nstate = 'connected'\nWHERE id = 348;\n\n# ************************************************************************************\nselect * from teams where id = 31;\nselect * from crm_configurations where id = 18;\n\nselect * from users where team_id = 31; # 257\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 31;\n\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 31\nand sa.provider = 'close';\n\nselect * from contacts where crm_configuration_id = 18;\n\n# ********************** NEPTUNE **************************************************************\nselect * from teams;\nselect * from users where id IN (1030, 1035, 1052);\nselect * from crm_configurations;\n\nselect * from users where team_id = 65; # 257\nselect * from team_settings where team_id = 65; # 257\nselect * from invitations where team_id = 65; # 257\nselect * from users where email = 'integration-account@jiminny.com'; # 257\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 65;\n\nselect * from crm_configurations where id = 53;\nselect * from accounts where crm_configuration_id = 53 order by id desc;\nselect * from leads where crm_configuration_id = 53 order by id desc;\nselect * from contacts where crm_configuration_id = 53 order by id desc;\nselect * from opportunities where crm_configuration_id = 53 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 53 order by id desc;\nselect * from crm_fields where crm_configuration_id = 53 order by id desc;\nselect * from crm_field_values where crm_field_id = 3341 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 53 order by id desc;\nselect * from stages where crm_configuration_id = 53 order by id desc;\n\n\nselect * from crm_profiles where crm_configuration_id = 13;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 65\nand sa.provider = 'integration-app';\n\nselect * from contacts where crm_configuration_id = 13;\n\nselect * from social_accounts where sociable_id = 283;\n\nSELECT * FROM opportunities WHERE crm_provider_id = '006O400000E9bzeIAB';\n\nselect * from activity_providers where team_id = 65;\nSELECT * FROM activities WHERE crm_configuration_id IN (51, 52, 53);\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 65\n;\n\n# ***************************** STAGING ********************************************\nSELECT * FROM teams;\nSELECT * FROM teams WHERE id = 88;\nSELECT * FROM teams WHERE id = 89;\nselect * from team_settings where team_id = 89;\nSELECT * FROM users WHERE team_id = 89;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 89;\n\nselect * from users;\nSELECT * FROM social_accounts WHERE sociable_id = 1761;\nSELECT * FROM crm_configurations WHERE id = 70;\nselect * from accounts where crm_configuration_id = 70 order by id desc;\nselect * from leads where crm_configuration_id = 70 order by id desc;\nselect * from contacts where crm_configuration_id = 70 order by id desc;\nselect * from opportunities where crm_configuration_id = 70 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 70 order by id desc;\nselect * from crm_fields where crm_configuration_id = 70 order by id desc;\nselect * from crm_field_values where crm_field_id = 3536 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 70 order by id desc;\nselect * from stages where crm_configuration_id = 70 order by id desc;\nselect * from business_processes where crm_configuration_id = 70 order by id desc;\nselect * from business_process_stages where business_process_id = 34;\n\nselect * from contacts where id = 10468;\n\nselect * from crm_layouts where crm_configuration_id = 70;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 388;\nSELECT * FROM crm_fields WHERE id IN (3533,3534,3535);\n\nselect * from activities where crm_configuration_id = 70\nand (account_id IS NOT NULL or lead_id IS NOT NULL or contact_id IS NOT NULL or opportunity_id IS NOT NULL) order by id desc;\n\nSELECT * FROM activities WHERE uuid_to_bin('2e10b60f-8a61-41c5-a3d4-28835353dc65') = uuid;\nSELECT * FROM activities where crm_configuration_id = 69 ;\n\nSELECT * FROM users WHERE email LIKE '%jiminny_web_sa2@jiminny.com%';\nSELECT * FROM activities WHERE uuid_to_bin('5a150c93-40fc-42ec-b3bd-c1d328e09f6e') = uuid;\nSELECT * FROM opportunities WHERE id = 385;\n\nselect * from participants p\njoin activities a on p.activity_id = a.id\nwhere a.crm_configuration_id = 70\nand (p.lead_id IS NOT NULL or p.contact_id IS NOT NULL);\nSELECT * FROM participants WHERE id = 1013638;\n\nselect * from teams where id = 90;\nselect * from users where team_id = 90;\nselect * from social_accounts where social_accounts.sociable_id IN (1960,1760);\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 71;\nselect * from invitations where team_id = 90;\n\nselect * from crm_configurations where id = 71;\nselect * from accounts where crm_configuration_id = 71 order by id desc;\nselect * from leads where crm_configuration_id = 71 order by id desc;\nselect * from contacts where crm_configuration_id = 71 order by id desc;\nselect * from opportunities where crm_configuration_id = 71 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 71 order by id desc;\nselect * from crm_fields where crm_configuration_id = 71 order by id desc;\nselect * from crm_field_values where crm_field_id = 3341 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 71 order by id desc;\nselect * from stages where crm_configuration_id = 71 order by id desc;\n\nselect * from users order by secondary_email desc;\nselect u.id, u.email, u.status, sa.id, sa.provider_user_id from social_accounts sa\n join users u on sa.sociable_id = u.id\nwhere sa.provider = 'google' and u.email LIKE 'aneliya%';\n\nselect * from failed_jobs order by id desc;\n\nselect * from users where email = 'ben.allwright@learningpeople.co.uk' or secondary_email = 'ben.allwright@learningpeople.co.uk';\n\nselect * from teams;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 39;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type = 'task';\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce';\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('c38b3895-fd0f-4b1f-9fb2-c170dba137c6') = uuid;\nSELECT * FROM crm_configurations WHERE id = 70;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1;\nselect * from users where team_id = 1;\n\nselect o.id, o.name,o.close_date, u.id, u.name, u.group_id, r.id, r.display_name, g.name, g.scope from opportunities o\njoin users u on o.user_id = u.id\njoin groups g on u.group_id = g.id\njoin role_user ru on u.id = ru.user_id\njoin roles r on ru.role_id = r.id\nwhere o.crm_configuration_id = 39 and close_date > '2024-01-01 00:00:00';\n\nselect * from role_user where user_id = 143;\nselect * from roles;\n\nselect * from role_user;\nselect * from groups where id = 9;\nselect * from scope_groups where group_id = 9;\n\n# ************************************************************************************\nselect * from teams where id = 36;\nselect * from crm_configurations;\nSELECT * FROM social_accounts WHERE sociable_id = 121;\n\nhttps://crmsandbox.zoho.com/crm/jiminnyw4/tab/Leads/4776201000005049105\nhttps://crmsandbox.zoho.com/crm/\n\nhttps://crm.zoho.com/crm/org3469620/tab/Leads/230045000229559080\n https://crm.zoho.com/crm/\n org3469620\n\nSELECT * FROM activities WHERE uuid_to_bin('03382d20-c8bc-48e7-a3d4-90b52fa5ceab') = uuid;\n\nselect * from users where email LIKE \"%mobile_automation_%\";\nselect * from social_accounts where sociable_id IN (2228);\nselect * from crm_profiles where user_id IN (2222,2223,2226,2227);\n\nselect * from teams order by id desc;\nSELECT * FROM users WHERE id = 2229;\nSELECT * FROM crm_profiles WHERE user_id = 2229;\nselect * from opportunities where crm_configuration_id = 88;\nselect * from crm_fields where crm_configuration_id = 88;\nselect * from crm_profiles where crm_configuration_id = 88;\n\nSELECT * FROM teams WHERE id = 1;\n\nSELECT * FROM users WHERE id = 143;\nSELECT * FROM users WHERE uuid_to_bin('fde193d3-06a2-4e1a-8895-62b94039215d') = uuid;\nSELECT * FROM teams WHERE uuid_to_bin('73385071-a756-42ae-9c73-8b53f2309467') = uuid;\n\nhttps://app.staging.jiminny.com/ondemand?\n min_duration=1\n &\n only_recorded=1\n &\n user_id%5B%5D=641f1acb-16b8-42d1-8726-df52979dad0e\n &\n sequence_number=2\n\n select * from users where team_id = 1 and email like '%stoyan%'\n\nselect * from coaching_feedbacks;\n\nselect * from teams;\nSELECT * FROM users WHERE team_id = 36;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 19\nand sa.provider = 'pipedrive';\n\nselect * from users where id = 143;\n\nSELECT * FROM users WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\nSELECT * FROM teams WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\nSELECT * FROM activity_shares WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\n\nselect * from users where team_id = 2;\nselect * from activities where crm_configuration_id = 39\nand activities.scheduled_start_time BETWEEN '2025-04-09 00:00:00' AND '2025-04-09 23:59:59'\nAND user_id = 143\norder by id desc;\n\n# ************************************************************************************\nselect * from teams where id = 142; # 2312, 126\nselect * from team_settings;\nselect * from users where team_id = 142; # 21642\nSELECT * FROM social_accounts WHERE sociable_id = 21642;\nSELECT * FROM crm_profiles cp join users u ON u.id = cp.user_id WHERE team_id = 142;\nselect * from crm_profiles where id IN (93);\nselect * from invitations;\nselect * from team_features where team_id = 1;\n\nSELECT * FROM crm_configurations WHERE id = 126;\nselect * from accounts where crm_configuration_id = 126 order by id desc;\nselect * from leads where crm_configuration_id = 126 order by id desc;\nselect * from contacts where crm_configuration_id = 126 order by id desc;\nselect * from opportunities where crm_configuration_id = 126 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 126 order by id desc;\nselect * from crm_fields where crm_configuration_id = 126 # 11060\n# and type IN ('picklist', 'status')\n# and object_type = 'task'\norder by id desc;\n# 5731,5732,5733\nselect DISTINCT crm_field_id from crm_field_values where crm_field_id IN (11151,12239,12215,12185,12175,12165,12144,12137,12127,12109,12107,12105,12103,12092,12037,12005,12003,11987,11969,11958,11951,11942,11931,11924,11921,11917,11915,11901,11893,11883,11872,11870,11868,11866,11839,11833,11821,11793,11780,11777,11769,11757,11737,11735,11656,11645,11638,11629,11618,11611,11602,11591,11584,11581,11558,11544,11543,11534,11532,11529,11527,11503,11497,11493,11488,11470,11468,11457,11455,11397,11387,11372,11363,11348,11323,11318,11309,11301,11300,11292,11290,11286,11284,11256,11252,11242,11237,11233,11219,11176,11160) order by id desc;\nselect * from crm_layouts where crm_configuration_id = 126 order by id desc;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id in (300,299,298);\nselect * from stages where crm_configuration_id = 126 order by id desc;\nselect * from business_processes where crm_configuration_id = 126 order by id desc;\nselect * from business_process_stages where business_process_id IN (76,75,74,73);\nselect * from playbooks where team_id = 142;\nselect * from playbook_layouts where playbook_id IN (108);\nSELECT * FROM playbook_categories WHERE playbook_id IN (108);\n\nselect * from teams where id = 130;\nSELECT * FROM social_accounts WHERE sociable_id = 2291;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 2\nand sa.provider = 'hubspot';\n\nSELECT * FROM activities\n WHERE crm_configuration_id = 110;\n\nselect * from teams;\nselect * from crm_configurations;\n\nSELECT * FROM activities WHERE id = 628773;\nSELECT * FROM crm_profiles WHERE user_id = 1460;\nSELECT * FROM social_accounts WHERE sociable_id = 2291;\n\nselect * from teams;\nselect ru.*, pr.*, p.* from users u join role_user ru on ru.user_id = u.id\njoin permission_role pr on pr.role_id = ru.role_id\n join permissions p on p.id = pr.permission_id\nwhere team_id = 495 and p.name IN ('dial');\n\nselect * from teams where id = 145;\nselect * from crm_configurations where id = 129;\nselect * from social_accounts where sociable_id = 2317;\nSELECT * FROM activities WHERE uuid_to_bin('8dbab184-a333-4268-ad57-fb41f8d53a9a') = uuid;\n\nselect * from teams where id = 1;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 280;\nSELECT * FROM crm_layout_entities WHERE id = 5507;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type IN ('event');\n\nselect * from teams;\nselect * from activities where crm_configuration_id = 14;\n\nSELECT * FROM social_accounts where provider = 'copper';\n\nselect * from activities where id = 628467;\nselect * from participants where activity_id = 628467;\n\nSELECT * FROM contacts WHERE id = 3969;\nSELECT * FROM accounts WHERE id = 177;\n\nSELECT * FROM activities WHERE uuid_to_bin('4eb54c77-cfa3-2bd4-84a7-9ed46a21c988') = uuid;\n\n# ********************* BH\nselect * from teams where id = 36;\nSELECT * FROM crm_configurations WHERE id = 21;\nselect * from activities where crm_configuration_id = 21 and id = 607901;\nselect * from activities where crm_configuration_id = 21;\n\nselect * roles;\nselect * from permissions;\nselect * from permission_role where permission_id = 226;\n\nselect * from migrations order by id desc;\n\n# mercury\n# neptune\n# earth\n\nselect * from teams;\nselect * from teams where id = 19;\nselect * from teams where id = 27;\nselect * from users where team_id = 27;\nSELECT * FROM crm_configurations WHERE id = 42;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 19\nand sa.provider = 'pipedrive';\n\nselect * from activities where id = 631461;\nSELECT * FROM crm_field_values WHERE crm_field_id = 180;\n\nselect * from teams where id = 2;\nSELECT * FROM social_accounts WHERE sociable_id = 89;\n\nSELECT * FROM activities WHERE uuid_to_bin('ba0c029a-bc14-4e17-8603-64174acebcbb') = uuid; # 634273\nselect * from activity_summary_logs where activity_id = 634273;\n\nselect * from sidekick_settings where team_id = 2;\n\nselect * from teams; # 2, 2\nSELECT * FROM crm_configurations WHERE team_id = 2; # 2\nselect * from team_features where team_id = 2;\nselect * from features;\nSELECT * FROM opportunities WHERE crm_configuration_id = 2 and crm_provider_id = '51317301383';\nSELECT * FROM opportunities WHERE crm_configuration_id = 2 order by id desc;\n\nselect * from automated_reports order by id desc;\nselect * from automated_report_results order by id desc;\nselect * from users where team_id = 1 and id IN (7160, 3248);\nselect * from migrations order by id desc;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1052 and sa.provider = 'hubspot';\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 = 565;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 175;\nselect * from playbook_categories where playbook_id = 175;\nselect * from users where team_id = 1052;\nselect * from users where id = 7160;\nselect * from crm_profiles where user_id = 7160;\nselect * from features;\nselect\n *\n# id, uuid, type, provider, playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id, stage_id,\n# crm_configuration_id, crm_provider_id, transcription_id, status\nfrom activities where crm_configuration_id = 1 and type = 'conference'\n# and crm_provider_id IS NOT NULL\nand provider != 'uploader' and actual_start_time IS NOT NULL\nORDER by id desc;\nselect * from activities where id = 54747783; # 00UO400000pCzojMAC\n\nselect p.id, p.activity_type, pc.id, pc.name\nFROM playbooks p\njoin playbook_categories pc on p.id = pc.playbook_id\nwhere p.team_id = 1 and p.activity_type = 'event';\n\nSELECT * FROM crm_fields WHERE crm_configuration_id = 1 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id = 4;\n\nselect * from crm_layouts cl join playbook_layouts pl on cl.id = pl.layout_id\nwhere crm_configuration_id = 1 and pl.playbook_id = 175;\n\nselect * from teams;\nSELECT r.* FROM automated_reports r\njoin teams t on r.team_id = t.id\nWHERE r.frequency = 'daily'\n and r.status = 1\nAND t.status = 'active'\nAND (r.expires_at >= now() OR r.expires_at IS NULL);\n\nselect * from automated_report_results where report_id IN (18, 33);\n\nselect * from users where team_id = 1 and id = 1047;\nSELECT * FROM social_accounts WHERE sociable_id = 1047;\n\nselect * from activity_searches where id = 10932;\nselect * from activity_search_filters where activity_search_id = 10932;\nselect * from automated_reports order by id desc;\nselect * from automated_report_results order by id desc;\nselect * from automated_reports where id IN (55);\nselect * from automated_report_results where id IN (81);\nselect * from users where id IN (10633, 13987, 11985);\nselect * from users where group_id IN (3710);\n\nSELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;\nSELECT * FROM automated_report_results WHERE uuid_to_bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;\n\nselect * from teams;\nselect * from accounts where team_id = 1;\n\nselect * from automated_report_results where media_type = 'pdf' and status = 2;\nSELECT * FROM automated_report_results WHERE uuid_to_bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid;\n\nselect * from teams where id = 1029;\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 = 1029 and sa.provider = 'pipedrive';\n\n[\n {\n \"user_id\": \"23460 (owner)\",\n \"email\": \"integration-account@pipedrive.jiminny.com\",\n \"id\": 69,\n \"sociable_id\": 23460,\n \"provider_user_id\": \"19555731\",\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,\n \"refresh_token_expires\": null,\n \"provider\": \"pipedrive\",\n \"state\": \"connected\",\n \"auth_scope\": \"base,deals:full,activities:full,contacts:full,search:read\",\n \"retry_after\": null,\n \"created_at\": \"2025-04-16 08:23:28\",\n \"updated_at\": \"2026-05-18 07:13:18\",\n \"provider_user_token_encrypted\": \"eyJpdiI6Ik9oYzBwcTVteWN4ajBRaDdMb0FjWGc9PSIsInZhbHVlIjoiQUNMbjU5UHR2Q1RnbWRXMEU1TUx6UVpRU3gzdVc5WktmTE4rVlhXa3lRaGhyUUlZMVZRWEJuR0JaWWhZZXNPRlBuanhuYU5MVHZ5TG9NTVVjNjJSUUpZZ2VhbGYxbHg0UzJEdTVmQjNFZnJRZkMwYjd0N2RMZ05GRS9IR3c2K0NoVjBjYTA5UG12SkxHeDlDMGVNN3ptUWUzblFiTngyYzR1eUpHSEYrdEwvZm0yZklGYjBSNEtTR2ZGazhLM1hqT3lVbjFobDNPZ0d3anFlcjhKcXpERlZGOVN1YmFyNDIvM1BFRDFMYnp4WEI4TGVLM2xYcy9CL0RDOWlQNHI3N0NwWnJPMWRtZllmM2ZKeE9TV2NBeDZxL2M1YnlSVzd3ZW96T3F1QmtBYXBHYkUraGcvdCtRajlYZXBjVVBSdFlMUjVPVDVJbDdyenVoWjMrbVJvU3ZZR1dQZ3pqQ3F3aDF2U2xPZWZIN3BCWVFLNXpxQUtDb2pIK0xHc1E3SklSM3Q0VkNSbm9oK2pFK3hLaW54T1dWbEVneUp0RGhhdVBuOFI4MXROc3dZWnFnTUpiaDVMMnZ4QmlRM3k4QWFlMVFWUFYvdGhJQzZBYnhBQmhWa2ZKN1ZhSnhpaExxbmlTemgzUWw3aXJtWjlSMlhmd0lWMDNDN1N3My9Ua0hCL2xqY3RkVFhMSjFJMDRjOE5DWlgrZ3FMVXN6RWlwUE5GWERZdG1xVjVxOFlLRGs2VVJKS3FLeWRxQjYxdDh4Z2JJNXhlWEZ3dkQ4SGtybDNUcndzblFHeVJNRkYraFh2UDFIUTdMQ1BZa3dEU1dBbzk5K0dyT2RNVFBZZUJpRytSck5pYlI1YUZyMmhUNEZCdWxHYmJLREtzbUpjVkhvV0RoejJpbm1SWHlNaXE5M0RhcS94UW9EdFoweWF3bVFVY0dTZWFPSXBmOCtDYndia215cmtyZU1oT0Exam1CV2tPblNhYjY4clVEeUs3anVHUmNHeS9YLzRha1VhbGl3N3lwaDlzZnRhQUZta2s4eFllNHgzRklSRmNyazJ4dlBDMnByNCtBRjNaVjJCTT0iLCJtYWMiOiJkYTQxZDY1OTY2ZTljMTgyZWRhNGEzMGZjZDc2MjBjN2NlNzU2YTViNGQxNWE1NTI2ZmI1MWQyYjQ2ODYxZmEwIiwidGFnIjoiIn0=\",\n \"provider_refresh_token_encrypted\": \"eyJpdiI6Imt2bGxlSmxUK05GMjF0dEtPaTMrUlE9PSIsInZhbHVlIjoiUXZHTElZRXkreHFxUU02SnZ4eVBacG9WWTRlVkd0USszV3JyVFlpU2ZaY25GSWo2WFcrRzNlbFRlUXRQczNwSXRCcEdvZEpveG9jMzBDSTgwdnZLQnc9PSIsIm1hYyI6ImQxYWI0NzU5Nzg5MDI4YWVhZmQ4Mjg1YzhkZDQzMjRkYWYwYTdhZTY5MDMxMjc0OWNiYjY0Nzc3NDQ0MTEyY2EiLCJ0YWciOiIifQ==\",\n \"encryption_key\": \"0x01020300786192D9D96DD60D3D1EBC9DFAEE5F0C45EE80165CF3F3D2B3B627026AA7CFC7CA0128DD463535D32EE491ADBADF8B07596B0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040C7FB1319048ECB2EA3F23B995020110802B52D22F5EAD341AB238FBBCB6093156E443876A664BA5555D722565C2B2D04422C868CD7350555E3CC74221\",\n \"sociable_type\": \"user\",\n \"owner_id\": 23460\n },\n {\n \"user_id\": \"23463\",\n \"email\": \"jiminny_web_sa@pipedrive.jiminny.com\",\n \"id\": 72,\n \"sociable_id\": 23463,\n \"provider_user_id\": \"23270841\",\n \"provider_user_token\": \"v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:txqCuWLeVhgwiaFqXIvQWWrtrnFIy_4lT3VCr-sRB4g6_2lK8KcQ_6ka_qFmZhr-IeIAKmAImx6H1iIKx4Ab7XZ5MnKIh03GKbHjI0n0rGT9UYkeH21jKOxJvKaSX_TyLbxFPR6irPQyvqcpBClXI52gVJH01KzZy_dMTHFXhhDLOIhEpSrQXHG7Qo8q7OuBeSPZrU1ALi9kmAm4GTpzGTbzfl-hUt9IAfPunJOCyv3mf2Tl-MT8EyQgOFPrsP3yz9UlSyVhb40zO_bCnUrqNxjwgm_E6vgpVrwULTQbHe-43Dq-TRetjceUzT88GBgVJ0UdxXP5BRBVXcL5ir8-9ZTMaNU\",\n \"provider_refresh_token\": \"5034113:23270841:34790b44838f5fd422c2d2c82e00f1ecf2178ad1\",\n \"expires\": 1753837219,\n \"refresh_token_expires\": null,\n \"provider\": \"pipedrive\",\n \"state\": \"full-refresh\",\n \"auth_scope\": \"base,deals:full,activities:full,contacts:full,search:read\",\n \"retry_after\": null,\n \"created_at\": \"2025-04-16 10:41:12\",\n \"updated_at\": \"2025-07-30 01:00:17\",\n \"provider_user_token_encrypted\": \"eyJpdiI6InVEVEl2SzIxMjd1bkNDWG9lY3YvQ0E9PSIsInZhbHVlIjoiRlJLbDZ3ZHo2dHMxUWQwdGU2YUZjV3lPWHlxQTJ0eWh4S0RTMjlSaThVcktoaWhXcTd2UXl4Mjg4bW5UUnZCZEQ5NXpuQTVKOURiMDNIa3l3K0lSWCt5azRBOEdHbitWQXhxeEpMVUZ1dnF2NVl1TTZLelZOaGNvRlBLeGpIWlpoRGloUEprd2xoNUFPcTlLcUd3WVlUU2svR1NOeXBYQ2NnMWhnK1V2aytOeVVMNzJGdVZXMU1JS3BSaGNCcmxkVjEwQ01mQXNBdWNhS1lMZWZobnZwcHBkN1R4bUVDRUNYdnNtSVJkdG5MdkN3djJBT0hMRDl1MHFGbnl4WU13ejBkUWsrdUljWkZhcTJlN0JDSGdTVzlPY0FGMUJlZi9WRGpkMUk5R20wblYwSk9VR2FuaHpLTzJNeitMbnF1V1NEMUUxRmYzaDRGZDMyaXd3Z0FjQno4SzVoYjUyTmV3UXNpRlF4TGZKNVl3dUFqdGhKVWJjRVlUUXRGalBpaXJvSGJmbS8rd25aQ2Zvc05saHRDRjlHV1VEUFFiRU5xbWRVNkxFSXV0RUZyaUlYNWMwMmhnZ0Y1VUQ4eEFkY2QyWXpnR0NidkVJSWdjVGljUjA3NDdpZW9WUHhtSlpGSGdNU2hRUTA5ZW03RGpiRFdrdytkOHJXSUxlazZNaG9iaUg2NFZYdEc3YklMeFZvblBzWmVRSDcvN2M4WUNtL3h4S2IrUW00cXhialBia3BJcW5XallBNlV5WWdhcE1ZVFBBM3RSSUVBamYvOGZEQWM5a2FJMGwyWkRSU3dlTEtPemZlQ3RXRGNDcEdYRHdMNTlTQVg2SUdUN0hVaXdZT1dUOUlrVzkrZHFBemhwWXg1cm4rSy9UOHUzcnNSM2dISlhBRTEyVUNyTkZYaFJYUlN1a2RKVHhhM2dHckR3a1JGaVZ2Wk9BVnhTclVpSEhwWTVpQTlJbXVkOUxSTGpRbDk0a1VtbE9QMVAvN3VlVEhJUHd2elowd0laNVIzZ3M3N0ZOK0NDakIwQ2FicGxoMDBhTXI0VUppUmFOZHdlWUdGV21NNFQ4RU1nY0dnWT0iLCJtYWMiOiI0ZTU4ZmJkNTdkYmY0NGE4NTJjZjlhNDExNzE2YjhlOWM2NTA5OGY2MDA4OTcyZDVlOTljY2JjZDhmMjBhMDUyIiwidGFnIjoiIn0=\",\n \"provider_refresh_token_encrypted\": \"eyJpdiI6IkJGMkdRVHRKM2VTcitKNGcvQWJtUGc9PSIsInZhbHVlIjoicmFyRkxPZ1Rybm1ORXlEVjJ2TXFGTzJtM3hWaFhnUVVHN2ZlR1lRM0I5d3ozbnZTcU5EdzJqRkI2elhyNWhlenRTUXV3bjk0N1JXeklDMVAyUzBKcHc9PSIsIm1hYyI6ImJhODVjMGQyZDE3Y2ExNjc2OWVjYWJiNmFjYWVkODIyMTMyNWVhYTExMTgwYTEyMTU0MzUzZGE1YjQ5YzQ5ZjEiLCJ0YWciOiIifQ==\",\n \"encryption_key\": \"0x01020300788C37CDF66ABE9301A68D5D4866AC0C197E04EEE4D904F20A59991322EBAE252301BEF4B24FF01359E934E5654617E4EEAC0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040CEB00EF45BDEA999A5558889E020110802B925F372F7BEFAF0B45E48686113D1DA430ECFCC07B1F61BA6828CC44235278EDB05C486E8068D0BE737D91\",\n \"sociable_type\": \"user\",\n \"owner_id\": 23460\n }\n]","role_description":"text entry area","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}]...
|
-749091260980150168
|
6686649177423131725
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
namespace Jiminny\Component\SCIM;
use Jiminny\Component\SCIM\Builders\Filters;
class Constants
{
/**
* HTTP codes
*/
public const HTTP_OK = 200;
public const HTTP_CREATED = 201;
public const HTTP_NO_CONTENT = 204;
public const HTTP_NOT_FOUND = 404;
public const HTTP_BAD_REQUEST = 400;
public const HTTP_ACCESS_DENIED = 403;
public const HTTP_ERROR = 501;
/**
* Users resource constants
*/
public const USER_FIRST_NAME = 'givenName';
public const USER_FAMILY_NAME = 'familyName';
public const USER_STATUS = 'Active';
public const USER_USERNAME = 'UserName';
public const USER_EXTERNAL_ID = 'externalId';
public const USER_FIELDS = [
self::USER_FIRST_NAME,
self::USER_FAMILY_NAME,
self::USER_STATUS,
self::USER_USERNAME,
];
public const META_OPERATIONS_REPLACE = 'replace';
public const META_OPERATIONS_REPLACE_UPPER = 'Replace';
public const META_OPERATIONS_ADD = 'add';
public const META_OPERATIONS_ADD_UPPER = 'Add';
public const META_OPERATIONS_REMOVE_UPPER = 'Remove';
public const META_OPERATIONS_REMOVE = 'remove';
public const META_ID = 'id';
public const META_PHONE_NUMBERS = 'phoneNumbers';
public const META_TITLE = 'title';
public const META_ROLES = 'roles';
public const META_PATH = 'path';
public const META_ENTERPRISE_SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';
public const META_DEPARTMENT = 'department';
public const META_META = 'meta';
public const META_TYPE = 'type';
public const META_VALUE = 'value';
public const META_OPERATIONS = 'Operations';
public const META_OP = 'op';
public const META_RESOURCE_TYPE = 'resourceType';
public const META_CREATED = 'created';
public const META_LAST_MODIFIED = 'lastModified';
public const META_FORMATTED = 'formatted';
public const META_EMAILS = 'emails';
public const META_USERNAME = 'userName';
public const META_NAME = 'name';
public const META_STATUS = 'active';
public const META_PRIMARY = 'primary';
public const META_ERROR_STATUS = 'status';
public const META_ERROR_DETAIL = 'detail';
public const META_LIST_TOTAL_RESULTS = 'totalResults';
public const META_LIST_RESOURCES = 'Resources';
public const META_LIST_START_INDEX = 'startIndex';
public const META_LIST_COUNT = 'count';
public const META_LIST_ITEMS_PER_PAGE = 'itemsPerPage';
public const META_SCHEMAS = 'schemas';
public const META_FILTER = 'filter';
public const META_TYPE_WORK = 'work';
public const META_PHONE_NUMBER_TYPE_MOBILE = 'mobile';
public const META_EMAIL_TYPE_HOME = 'home';
public const META_CONTAINER_NAME = 'name';
public const META_CONTAINER_EMAILS = 'emails';
public const RESOURCE_TYPE_USER = 'User';
public const USER_PATCH_ATTR_TITLE = 'title';
public const USER_PATCH_ATTR_ACTIVE = 'active';
public const USER_PATCH_ATTR_USERNAME = 'userName';
public const USER_PATCH_ATTR_FIRST_NAME = 'name.givenName';
public const USER_PATCH_ATTR_LAST_NAME = 'name.familyName';
public const USER_PATCH_ATTR_PRIMARY_EMAIL = 'emails[type eq "work"].value';
public const USER_PATCH_ATTR_SECONDARY_EMAIL = 'emails[type eq "home"].value';
public const USER_PATCH_ATTR_PHONE_NUMBER = 'phoneNumbers[type eq "work"].value';
public const USER_PATCH_ATTR_PHONE_NUMBER_MOBILE = 'phoneNumbers[type eq "mobile"].value';
public const USER_PATCH_ATTR_ROLES = 'roles';
public const USER_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [
self::USER_PATCH_ATTR_TITLE => Mutators\Attributes\User\TitleAttr::class,
self::USER_PATCH_ATTR_ACTIVE => Mutators\Attributes\User\ActiveAttr::class,
self::USER_PATCH_ATTR_USERNAME => Mutators\Attributes\User\UsernameAttr::class,
self::USER_PATCH_ATTR_FIRST_NAME => Mutators\Attributes\User\FirstNameAttr::class,
self::USER_PATCH_ATTR_LAST_NAME => Mutators\Attributes\User\LastNameAttr::class,
self::USER_PATCH_ATTR_PRIMARY_EMAIL => Mutators\Attributes\User\PrimaryEmailAttr::class,
self::USER_PATCH_ATTR_SECONDARY_EMAIL => Mutators\Attributes\User\SecondaryEmailAttr::class,
self::USER_PATCH_ATTR_PHONE_NUMBER => Mutators\Attributes\User\PhoneNumberPrimaryAttr::class,
self::USER_PATCH_ATTR_PHONE_NUMBER_MOBILE => Mutators\Attributes\User\PhoneNumberSecondaryAttr::class,
self::USER_PATCH_ATTR_ROLES => Mutators\Attributes\User\RoleAttr::class,
];
public const FILTER_OPERATOR_EQ = 'eq';
public const SUPPORTED_FILTERS_OPERATORS = [
self::FILTER_OPERATOR_EQ,
];
public const USER_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [
self::USER_FILTER_LOCAL_ID => Filters\User\LocalIdFilter::class,
self::USER_FILTER_USERNAME => Filters\User\UserNameFilter::class,
self::USER_FILTER_FIRST_NAME => Filters\User\FirstNameFilter::class,
self::USER_FILTER_LAST_NAME => Filters\User\LastNameFilter::class,
self::USER_FILTER_EXTERNAL_ID => Filters\User\ExternalIdFilter::class,
self::USER_FILTER_DISPLAY_NAME => Filters\User\DisplayNameFilter::class,
];
public const USER_FILTER_LOCAL_ID = 'id';
public const USER_FILTER_USERNAME = 'userName';
public const USER_FILTER_FIRST_NAME = 'givenName';
public const USER_FILTER_LAST_NAME = 'familyName';
public const USER_FILTER_EXTERNAL_ID = 'externalId';
public const USER_FILTER_DISPLAY_NAME = 'DisplayName';
public const SCIM_SUPPORTED_RESOURCES = [
self::USER_RESOURCE_PREFIX,
self::GROUP_RESOURCE_PREFIX,
];
public const USER_RESOURCE_PREFIX = 'Users';
public const GROUP_RESOURCE_PREFIX = 'Groups';
public const OUTGOING_SCHEMAS_SUPPORTED = [
self::OUTGOING_CORE_USER,
];
/**
* Outgoing supported schemas
*/
public const OUTGOING_CORE_USER = 'urn:ietf:params:scim:schemas:core:2.0:User';
public const OUTGOING_ERROR = 'urn:ietf:params:scim:api:messages:2.0:Error';
public const OUTGOING_LIST_RESPONSE = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';
public const OUTGOING_CORE_GROUP = 'urn:ietf:params:scim:schemas:core:2.0:Group';
/**
* Groups resource constants
*/
public const GROUP_ATTRIBUTE_DISPLAY_NAME = 'displayName';
public const GROUP_ATTRIBUTE_EXTERNAL_ID = 'externalId';
public const GROUP_ATTRIBUTE_ID = 'id';
public const RESOURCE_TYPE_GROUP = 'Group';
public const GROUP_FILTER_QUERY_NAME = 'filter';
public const GROUP_EXCLUDED_ATTRIBUTES = 'excludedAttributes';
public const GROUP_SUPPORTED_FILTER_ATTRIBUTES = [
self::GROUP_ATTRIBUTE_DISPLAY_NAME,
];
public const GROUP_MEMBERS = 'members';
public const SUPPORTED_PATCH_OPERATIONS = [
self::META_OPERATIONS_ADD,
self::META_OPERATIONS_REPLACE,
self::META_OPERATIONS_REMOVE,
];
public const GROUP_PATCH_ATTRIBUTE_MEMBERS = 'members';
public const GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME = 'displayName';
public const GROUP_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [
self::GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME => Mutators\Attributes\Group\DisplayNameAttr::class,
self::GROUP_PATCH_ATTRIBUTE_MEMBERS => Mutators\Attributes\Group\MembersAttr::class,
];
public const GROUP_FILTER_DISPLAY_NAME = 'displayname';
public const GROUP_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [
self::GROUP_FILTER_DISPLAY_NAME => Filters\Group\DisplayNameFilter::class,
];
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny_jupiter
Sync Changes
Hide This Notification
Code changed:
Hide
19
19
17
Previous Highlighted Error
Next Highlighted Error
SELECT * FROM teams WHERE id = 1;
select * from crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 283;
SELECT * FROM crm_fields WHERE id = 2234;
SELECT * FROM crm_field_values WHERE crm_field_id = 2234;
select * from crm_profiles where user_id = 143;
select * from record_types where crm_configuration_id = 39; # 0121K000001MHElQAO,0121K000001MHEqQAO
select * from business_processes where crm_configuration_id = 39;
# 01941000000H669AAC, 01941000000H66JAAS
select * from record_type_field_values
where record_type_id IN (24);
select * from crm_field_values where id IN (2730);
select * from crm_configurations where id = 39;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce'; #1035
select * from users where team_id = 1; # 222 group 3
SELECT * FROM activities WHERE user_id = 222 order by id desc;
select * from sidekick_settings where team_id = 1;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from activities where crm_configuration_id = 2
and provider = 'ms-teams' and id = 608765;
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id = '59523413338';
select * from sidekick_settings where team_id = 2;
SELECT * FROM activities WHERE id = 608660;
select * from activity_summary_logs where activity_id = 608660;
select * from ai_prompts where transcription_id = 11214;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('ed78a437-2804-450e-ab2f-56ab1c641346') = uuid;
# id: 608818, crm: 59628809737
SELECT * FROM activities WHERE uuid_to_bin('36b06e55-afdd-4782-8dee-c624cd0af191') = uuid;
# id: 608821, crm: 59632069252
SELECT ce.start_time, ce.end_time, a.id, a.uuid, crm_provider_id, calendar_event_id, title,
playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id,
scheduled_start_time, scheduled_end_time, actual_start_time, actual_end_time, a.created_at
FROM activities a
join calendar_events ce on a.calendar_event_id = ce.id
WHERE a.id IN (608818, 608821);
select * from users where team_id = 1;
select * from team_settings where team_id = 1;
select * from crm_profiles where crm_configuration_id = 39 order by user_id;
select * from team_features where team_id = 1;
select * from users where team_id = 2;
SELECT * FROM activities WHERE uuid_to_bin('ec7647e9-5225-458b-b475-f31aa2769204') = uuid; # 612639
# Preslava N. Ivanova, grou id 3
SELECT * FROM opportunities WHERE uuid_to_bin('a2928fe5-aec5-46cb-85d9-7654c89e46a6') = uuid;
select * from activities where opportunity_id = 344 and actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00';
select
a.id,
a.type,
a.scheduled_start_time,
a.actual_start_time,
a.created_at,
a.opportunity_id,
a.status
FROM activities a
WHERE opportunity_id = 344
and status IN ('completed', 'received', 'delivered')
and (
(a.actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')
OR (a.created_at between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')
OR (a.scheduled_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00'))
;
SELECT * FROM users WHERE id = 222;
SELECT * FROM crm_profiles WHERE user_id = 222;
select * from crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 281;
select * from group_deal_risk_types;
select * from opportunities where team_id = 1;
SELECT * FROM opportunities WHERE id = 315;
SELECT * FROM crm_field_data WHERE object_id = 315;
select * from crm_field_data where object_id = 260;
select * from generic_ai_prompts where subject_id = 315;
select * from teams; # 36, 21, 121, [EMAIL]
SELECT * FROM social_accounts WHERE sociable_id = 121 and provider = 'bullhorn';
# [PASSWORD_DOTS]
select * from teams where id = 1;
select * from crm_configurations where id = 39;
select * from users where team_id = 1;
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 1;
# 1 - 00541000004281rAAA
# 204 - 0052g000003freeAAA
# 429 - 0052g000003qGOiAAM
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce';
select * from activities where type = 'softphone'
and created_at > '2024-12-11 15:24:36' order by id desc;
select * from activity_providers where team_id = 1;
select * from activity_provider_users where activity_provider_id = 328;
select * from opportunities where crm_configuration_id = 39
AND account_id = 178 AND is_closed = false
order by created_at DESC;
select * from contacts where id = 3952;
select * from accounts where id = 178;
# [PASSWORD_DOTS]
select * from teams where id = 36;
select * from crm_configurations where id = 21;
select * from users where team_id = 36;
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 36;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 36
and sa.provider = 'bullhorn';
select * from social_accounts where id = 348;
UPDATE social_accounts SET
provider_user_token = '21442_6802599_91:41179a58-21e7-4d7c-ad58-56bb666b2f65',
provider_refresh_token = '21442_6802599_91:01c6b335-3f2a-42e4-85ff-8a08fa65fceb',
expires = 1733998131,
state = 'connected'
WHERE id = 348;
# [PASSWORD_DOTS]
select * from teams where id = 31;
select * from crm_configurations where id = 18;
select * from users where team_id = 31; # 257
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 31;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 31
and sa.provider = 'close';
select * from contacts where crm_configuration_id = 18;
# [PASSWORD_DOTS] NEPTUNE [PASSWORD_DOTS]
select * from teams;
select * from users where id IN (1030, 1035, 1052);
select * from crm_configurations;
select * from users where team_id = 65; # 257
select * from team_settings where team_id = 65; # 257
select * from invitations where team_id = 65; # 257
select * from users where email = '[EMAIL]'; # 257
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 65;
select * from crm_configurations where id = 53;
select * from accounts where crm_configuration_id = 53 order by id desc;
select * from leads where crm_configuration_id = 53 order by id desc;
select * from contacts where crm_configuration_id = 53 order by id desc;
select * from opportunities where crm_configuration_id = 53 order by id desc;
select * from crm_profiles where crm_configuration_id = 53 order by id desc;
select * from crm_fields where crm_configuration_id = 53 order by id desc;
select * from crm_field_values where crm_field_id = 3341 order by id desc;
select * from crm_layouts where crm_configuration_id = 53 order by id desc;
select * from stages where crm_configuration_id = 53 order by id desc;
select * from crm_profiles where crm_configuration_id = 13;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 65
and sa.provider = 'integration-app';
select * from contacts where crm_configuration_id = 13;
select * from social_accounts where sociable_id = 283;
SELECT * FROM opportunities WHERE crm_provider_id = '006O400000E9bzeIAB';
select * from activity_providers where team_id = 65;
SELECT * FROM activities WHERE crm_configuration_id IN (51, 52, 53);
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 65
;
# [PASSWORD_DOTS] STAGING [PASSWORD_DOTS]
SELECT * FROM teams;
SELECT * FROM teams WHERE id = 88;
SELECT * FROM teams WHERE id = 89;
select * from team_settings where team_id = 89;
SELECT * FROM users WHERE team_id = 89;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 89;
select * from users;
SELECT * FROM social_accounts WHERE sociable_id = 1761;
SELECT * FROM crm_configurations WHERE id = 70;
select * from accounts where crm_configuration_id = 70 order by id desc;
select * from leads where crm_configuration_id = 70 order by id desc;
select * from contacts where crm_configuration_id = 70 order by id desc;
select * from opportunities where crm_configuration_id = 70 order by id desc;
select * from crm_profiles where crm_configuration_id = 70 order by id desc;
select * from crm_fields where crm_configuration_id = 70 order by id desc;
select * from crm_field_values where crm_field_id = 3536 order by id desc;
select * from crm_layouts where crm_configuration_id = 70 order by id desc;
select * from stages where crm_configuration_id = 70 order by id desc;
select * from business_processes where crm_configuration_id = 70 order by id desc;
select * from business_process_stages where business_process_id = 34;
select * from contacts where id = 10468;
select * from crm_layouts where crm_configuration_id = 70;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 388;
SELECT * FROM crm_fields WHERE id IN (3533,3534,3535);
select * from activities where crm_configuration_id = 70
and (account_id IS NOT NULL or lead_id IS NOT NULL or contact_id IS NOT NULL or opportunity_id IS NOT NULL) order by id desc;
SELECT * FROM activities WHERE uuid_to_bin('2e10b60f-8a61-41c5-a3d4-28835353dc65') = uuid;
SELECT * FROM activities where crm_configuration_id = 69 ;
SELECT * FROM users WHERE email LIKE '%[EMAIL]%';
SELECT * FROM activities WHERE uuid_to_bin('5a150c93-40fc-42ec-b3bd-c1d328e09f6e') = uuid;
SELECT * FROM opportunities WHERE id = 385;
select * from participants p
join activities a on p.activity_id = a.id
where a.crm_configuration_id = 70
and (p.lead_id IS NOT NULL or p.contact_id IS NOT NULL);
SELECT * FROM participants WHERE id = 1013638;
select * from teams where id = 90;
select * from users where team_id = 90;
select * from social_accounts where social_accounts.sociable_id IN (1960,1760);
SELECT * FROM crm_profiles WHERE crm_configuration_id = 71;
select * from invitations where team_id = 90;
select * from crm_configurations where id = 71;
select * from accounts where crm_configuration_id = 71 order by id desc;
select * from leads where crm_configuration_id = 71 order by id desc;
select * from contacts where crm_configuration_id = 71 order by id desc;
select * from opportunities where crm_configuration_id = 71 order by id desc;
select * from crm_profiles where crm_configuration_id = 71 order by id desc;
select * from crm_fields where crm_configuration_id = 71 order by id desc;
select * from crm_field_values where crm_field_id = 3341 order by id desc;
select * from crm_layouts where crm_configuration_id = 71 order by id desc;
select * from stages where crm_configuration_id = 71 order by id desc;
select * from users order by secondary_email desc;
select u.id, u.email, u.status, sa.id, sa.provider_user_id from social_accounts sa
join users u on sa.sociable_id = u.id
where sa.provider = 'google' and u.email LIKE 'aneliya%';
select * from failed_jobs order by id desc;
select * from users where email = '[EMAIL]' or secondary_email = '[EMAIL]';
select * from teams;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 39;
SELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type = 'task';
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce';
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('c38b3895-fd0f-4b1f-9fb2-c170dba137c6') = uuid;
SELECT * FROM crm_configurations WHERE id = 70;
select * from teams where id = 1;
select * from groups where team_id = 1;
select * from users where team_id = 1;
select o.id, o.name,o.close_date, u.id, u.name, u.group_id, r.id, r.display_name, g.name, g.scope from opportunities o
join users u on o.user_id = u.id
join groups g on u.group_id = g.id
join role_user ru on u.id = ru.user_id
join roles r on ru.role_id = r.id
where o.crm_configuration_id = 39 and close_date > '2024-01-01 00:00:00';
select * from role_user where user_id = 143;
select * from roles;
select * from role_user;
select * from groups where id = 9;
select * from scope_groups where group_id = 9;
# [PASSWORD_DOTS]
select * from teams where id = 36;
select * from crm_configurations;
SELECT * FROM social_accounts WHERE sociable_id = 121;
https://crmsandbox.zoho.com/crm/jiminnyw4/tab/Leads/4776201000005049105
https://crmsandbox.zoho.com/crm/
https://crm.zoho.com/crm/org3469620/tab/Leads/230045000229559080
https://crm.zoho.com/crm/
org3469620
SELECT * FROM activities WHERE uuid_to_bin('03382d20-c8bc-48e7-a3d4-90b52fa5ceab') = uuid;
select * from users where email LIKE "%mobile_automation_%";
select * from social_accounts where sociable_id IN (2228);
select * from crm_profiles where user_id IN (2222,2223,2226,2227);
select * from teams order by id desc;
SELECT * FROM users WHERE id = 2229;
SELECT * FROM crm_profiles WHERE user_id = 2229;
select * from opportunities where crm_configuration_id = 88;
select * from crm_fields where crm_configuration_id = 88;
select * from crm_profiles where crm_configuration_id = 88;
SELECT * FROM teams WHERE id = 1;
SELECT * FROM users WHERE id = 143;
SELECT * FROM users WHERE uuid_to_bin('fde193d3-06a2-4e1a-8895-62b94039215d') = uuid;
SELECT * FROM teams WHERE uuid_to_bin('73385071-a756-42ae-9c73-8b53f2309467') = uuid;
https://app.staging.jiminny.com/ondemand?
min_duration=1
&
only_recorded=1
&
user_id%5B%5D=641f1acb-16b8-42d1-8726-df52979dad0e
&
sequence_number=2
select * from users where team_id = 1 and email like '%stoyan%'
select * from coaching_feedbacks;
select * from teams;
SELECT * FROM users WHERE team_id = 36;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 19
and sa.provider = 'pipedrive';
select * from users where id = 143;
SELECT * FROM users WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
SELECT * FROM teams WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
SELECT * FROM activity_shares WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
select * from users where team_id = 2;
select * from activities where crm_configuration_id = 39
and activities.scheduled_start_time BETWEEN '2025-04-09 00:00:00' AND '2025-04-09 23:59:59'
AND user_id = 143
order by id desc;
# [PASSWORD_DOTS]
select * from teams where id = 142; # 2312, 126
select * from team_settings;
select * from users where team_id = 142; # 21642
SELECT * FROM social_accounts WHERE sociable_id = 21642;
SELECT * FROM crm_profiles cp join users u ON u.id = cp.user_id WHERE team_id = 142;
select * from crm_profiles where id IN (93);
select * from invitations;
select * from team_features where team_id = 1;
SELECT * FROM crm_configurations WHERE id = 126;
select * from accounts where crm_configuration_id = 126 order by id desc;
select * from leads where crm_configuration_id = 126 order by id desc;
select * from contacts where crm_configuration_id = 126 order by id desc;
select * from opportunities where crm_configuration_id = 126 order by id desc;
select * from crm_profiles where crm_configuration_id = 126 order by id desc;
select * from crm_fields where crm_configuration_id = 126 # 11060
# and type IN ('picklist', 'status')
# and object_type = 'task'
order by id desc;
# 5731,5732,5733
select DISTINCT crm_field_id from crm_field_values where crm_field_id IN (11151,12239,12215,12185,12175,12165,12144,12137,12127,12109,12107,12105,12103,12092,12037,12005,12003,11987,11969,11958,11951,11942,11931,11924,11921,11917,11915,11901,11893,11883,11872,11870,11868,11866,11839,11833,11821,11793,11780,11777,11769,11757,11737,11735,11656,11645,11638,11629,11618,11611,11602,11591,11584,11581,11558,11544,11543,11534,11532,11529,11527,11503,11497,11493,11488,11470,11468,11457,11455,11397,11387,11372,11363,11348,11323,11318,11309,11301,11300,11292,11290,11286,11284,11256,11252,11242,11237,11233,11219,11176,11160) order by id desc;
select * from crm_layouts where crm_configuration_id = 126 order by id desc;
SELECT * FROM crm_layout_entities WHERE crm_layout_id in (300,299,298);
select * from stages where crm_configuration_id = 126 order by id desc;
select * from business_processes where crm_configuration_id = 126 order by id desc;
select * from business_process_stages where business_process_id IN (76,75,74,73);
select * from playbooks where team_id = 142;
select * from playbook_layouts where playbook_id IN (108);
SELECT * FROM playbook_categories WHERE playbook_id IN (108);
select * from teams where id = 130;
SELECT * FROM social_accounts WHERE sociable_id = 2291;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 2
and sa.provider = 'hubspot';
SELECT * FROM activities
WHERE crm_configuration_id = 110;
select * from teams;
select * from crm_configurations;
SELECT * FROM activities WHERE id = 628773;
SELECT * FROM crm_profiles WHERE user_id = 1460;
SELECT * FROM social_accounts WHERE sociable_id = 2291;
select * from teams;
select ru.*, pr.*, p.* from users u join role_user ru on ru.user_id = u.id
join permission_role pr on pr.role_id = ru.role_id
join permissions p on p.id = pr.permission_id
where team_id = 495 and p.name IN ('dial');
select * from teams where id = 145;
select * from crm_configurations where id = 129;
select * from social_accounts where sociable_id = 2317;
SELECT * FROM activities WHERE uuid_to_bin('8dbab184-a333-4268-ad57-fb41f8d53a9a') = uuid;
select * from teams where id = 1;
SELECT * FROM crm_layouts WHERE crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 280;
SELECT * FROM crm_layout_entities WHERE id = 5507;
SELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type IN ('event');
select * from teams;
select * from activities where crm_configuration_id = 14;
SELECT * FROM social_accounts where provider = 'copper';
select * from activities where id = 628467;
select * from participants where activity_id = 628467;
SELECT * FROM contacts WHERE id = 3969;
SELECT * FROM accounts WHERE id = 177;
SELECT * FROM activities WHERE uuid_to_bin('4eb54c77-cfa3-2bd4-84a7-9ed46a21c988') = uuid;
# [PASSWORD_DOTS] BH
select * from teams where id = 36;
SELECT * FROM crm_configurations WHERE id = 21;
select * from activities where crm_configuration_id = 21 and id = 607901;
select * from activities where crm_configuration_id = 21;
select * roles;
select * from permissions;
select * from permission_role where permission_id = 226;
select * from migrations order by id desc;
# mercury
# neptune
# earth
select * from teams;
select * from teams where id = 19;
select * from teams where id = 27;
select * from users where team_id = 27;
SELECT * FROM crm_configurations WHERE id = 42;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 19
and sa.provider = 'pipedrive';
select * from activities where id = 631461;
SELECT * FROM crm_field_values WHERE crm_field_id = 180;
select * from teams where id = 2;
SELECT * FROM social_accounts WHERE sociable_id = 89;
SELECT * FROM activities WHERE uuid_to_bin('ba0c029a-bc14-4e17-8603-64174acebcbb') = uuid; # 634273
select * from activity_summary_logs where activity_id = 634273;
select * from sidekick_settings where team_id = 2;
select * from teams; # 2, 2
SELECT * FROM crm_configurations WHERE team_id = 2; # 2
select * from team_features where team_id = 2;
select * from features;
SELECT * FROM opportunities WHERE crm_configuration_id = 2 and crm_provider_id = '51317301383';
SELECT * FROM opportunities WHERE crm_configuration_id = 2 order by id desc;
select * from automated_reports order by id desc;
select * from automated_report_results order by id desc;
select * from users where team_id = 1 and id IN (7160, 3248);
select * from migrations order by id desc;
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 = 1052 and sa.provider = 'hubspot';
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 = 565;
select * from playbooks where team_id = 1;
select * from playbooks where id = 175;
select * from playbook_categories where playbook_id = 175;
select * from users where team_id = 1052;
select * from users where id = 7160;
select * from crm_profiles where user_id = 7160;
select * from features;
select
*
# id, uuid, type, provider, playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id, stage_id,
# crm_configuration_id, crm_provider_id, transcription_id, status
from activities where crm_configuration_id = 1 and type = 'conference'
# and crm_provider_id IS NOT NULL
and provider != 'uploader' and actual_start_time IS NOT NULL
ORDER by id desc;
select * from activities where id = 54747783; # 00UO400000pCzojMAC
select p.id, p.activity_type, pc.id, pc.name
FROM playbooks p
join playbook_categories pc on p.id = pc.playbook_id
where p.team_id = 1 and p.activity_type = 'event';
SELECT * FROM crm_fields WHERE crm_configuration_id = 1 and object_type = 'event';
SELECT * FROM crm_field_values WHERE crm_field_id = 4;
select * from crm_layouts cl join playbook_layouts pl on cl.id = pl.layout_id
where crm_configuration_id = 1 and pl.playbook_id = 175;
select * from teams;
SELECT r.* FROM automated_reports r
join teams t on r.team_id = t.id
WHERE r.frequency = 'daily'
and r.status = 1
AND t.status = 'active'
AND (r.expires_at >= now() OR r.expires_at IS NULL);
select * from automated_report_results where report_id IN (18, 33);
select * from users where team_id = 1 and id = 1047;
SELECT * FROM social_accounts WHERE sociable_id = 1047;
select * from activity_searches where id = 10932;
select * from activity_search_filters where activity_search_id = 10932;
select * from automated_reports order by id desc;
select * from automated_report_results order by id desc;
select * from automated_reports where id IN (55);
select * from automated_report_results where id IN (81);
select * from users where id IN (10633, 13987, 11985);
select * from users where group_id IN (3710);
SELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;
SELECT * FROM automated_report_results WHERE uuid_to_bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;
select * from teams;
select * from accounts where team_id = 1;
select * from automated_report_results where media_type = 'pdf' and status = 2;
SELECT * FROM automated_report_results WHERE uuid_to_bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid;
select * from teams where id = 1029;
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 = 1029 and sa.provider = 'pipedrive';
[
{
"user_id": "23460 (owner)",
"email": "[EMAIL]",
"id": 69,
"sociable_id": 23460,
"provider_user_id": "19555731",
"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,
"refresh_token_expires": null,
"provider": "pipedrive",
"state": "connected",
"auth_scope": "base,deals:full,activities:full,contacts:full,search:read",
"retry_after": null,
"created_at": "2025-04-16 08:23:28",
"updated_at": "2026-05-18 07:13:18",
"provider_user_token_encrypted": "eyJpdiI6Ik9oYzBwcTVteWN4ajBRaDdMb0FjWGc9PSIsInZhbHVlIjoiQUNMbjU5UHR2Q1RnbWRXMEU1TUx6UVpRU3gzdVc5WktmTE4rVlhXa3lRaGhyUUlZMVZRWEJuR0JaWWhZZXNPRlBuanhuYU5MVHZ5TG9NTVVjNjJSUUpZZ2VhbGYxbHg0UzJEdTVmQjNFZnJRZkMwYjd0N2RMZ05GRS9IR3c2K0NoVjBjYTA5UG12SkxHeDlDMGVNN3ptUWUzblFiTngyYzR1eUpHSEYrdEwvZm0yZklGYjBSNEtTR2ZGazhLM1hqT3lVbjFobDNPZ0d3anFlcjhKcXpERlZGOVN1YmFyNDIvM1BFRDFMYnp4WEI4TGVLM2xYcy9CL0RDOWlQNHI3N0NwWnJPMWRtZllmM2ZKeE9TV2NBeDZxL2M1YnlSVzd3ZW96T3F1QmtBYXBHYkUraGcvdCtRajlYZXBjVVBSdFlMUjVPVDVJbDdyenVoWjMrbVJvU3ZZR1dQZ3pqQ3F3aDF2U2xPZWZIN3BCWVFLNXpxQUtDb2pIK0xHc1E3SklSM3Q0VkNSbm9oK2pFK3hLaW54T1dWbEVneUp0RGhhdVBuOFI4MXROc3dZWnFnTUpiaDVMMnZ4QmlRM3k4QWFlMVFWUFYvdGhJQzZBYnhBQmhWa2ZKN1ZhSnhpaExxbmlTemgzUWw3aXJtWjlSMlhmd0lWMDNDN1N3My9Ua0hCL2xqY3RkVFhMSjFJMDRjOE5DWlgrZ3FMVXN6RWlwUE5GWERZdG1xVjVxOFlLRGs2VVJKS3FLeWRxQjYxdDh4Z2JJNXhlWEZ3dkQ4SGtybDNUcndzblFHeVJNRkYraFh2UDFIUTdMQ1BZa3dEU1dBbzk5K0dyT2RNVFBZZUJpRytSck5pYlI1YUZyMmhUNEZCdWxHYmJLREtzbUpjVkhvV0RoejJpbm1SWHlNaXE5M0RhcS94UW9EdFoweWF3bVFVY0dTZWFPSXBmOCtDYndia215cmtyZU1oT0Exam1CV2tPblNhYjY4clVEeUs3anVHUmNHeS9YLzRha1VhbGl3N3lwaDlzZnRhQUZta2s4eFllNHgzRklSRmNyazJ4dlBDMnByNCtBRjNaVjJCTT0iLCJtYWMiOiJkYTQxZDY1OTY2ZTljMTgyZWRhNGEzMGZjZDc2MjBjN2NlNzU2YTViNGQxNWE1NTI2ZmI1MWQyYjQ2ODYxZmEwIiwidGFnIjoiIn0=",
"provider_refresh_token_encrypted": "eyJpdiI6Imt2bGxlSmxUK05GMjF0dEtPaTMrUlE9PSIsInZhbHVlIjoiUXZHTElZRXkreHFxUU02SnZ4eVBacG9WWTRlVkd0USszV3JyVFlpU2ZaY25GSWo2WFcrRzNlbFRlUXRQczNwSXRCcEdvZEpveG9jMzBDSTgwdnZLQnc9PSIsIm1hYyI6ImQxYWI0NzU5Nzg5MDI4YWVhZmQ4Mjg1YzhkZDQzMjRkYWYwYTdhZTY5MDMxMjc0OWNiYjY0Nzc3NDQ0MTEyY2EiLCJ0YWciOiIifQ==",
"encryption_key": "0x01020300786192D9D96DD60D3D1EBC9DFAEE5F0C45EE80165CF3F3D2B3B627026AA7CFC7CA0128DD463535D32EE491ADBADF8B07596B0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040C7FB1319048ECB2EA3F23B995020110802B52D22F5EAD341AB238FBBCB6093156E443876A664BA5555D722565C2B2D04422C868CD7350555E3CC74221",
"sociable_type": "user",
"owner_id": 23460
},
{
"user_id": "23463",
"email": "[EMAIL]",
"id": 72,
"sociable_id": 23463,
"provider_user_id": "23270841",
"provider_user_token": "v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:txqCuWLeVhgwiaFqXIvQWWrtrnFIy_4lT3VCr-sRB4g6_2lK8KcQ_6ka_qFmZhr-IeIAKmAImx6H1iIKx4Ab7XZ5MnKIh03GKbHjI0n0rGT9UYkeH21jKOxJvKaSX_TyLbxFPR6irPQyvqcpBClXI52gVJH01KzZy_dMTHFXhhDLOIhEpSrQXHG7Qo8q7OuBeSPZrU1ALi9kmAm4GTpzGTbzfl-hUt9IAfPunJOCyv3mf2Tl-MT8EyQgOFPrsP3yz9UlSyVhb40zO_bCnUrqNxjwgm_E6vgpVrwULTQbHe-43Dq-TRetjceUzT88GBgVJ0UdxXP5BRBVXcL5ir8-9ZTMaNU",
"provider_refresh_token": "5034113:[TELEGRAM_TOKEN]78ad1",
"expires": 1753837219,
"refresh_token_expires": null,
"provider": "pipedrive",
"state": "full-refresh",
"auth_scope": "base,deals:full,activities:full,contacts:full,search:read",
"retry_after": null,
"created_at": "2025-04-16 10:41:12",
"updated_at": "2025-07-30 01:00:17",
"provider_user_token_encrypted": "eyJpdiI6InVEVEl2SzIxMjd1bkNDWG9lY3YvQ0E9PSIsInZhbHVlIjoiRlJLbDZ3ZHo2dHMxUWQwdGU2YUZjV3lPWHlxQTJ0eWh4S0RTMjlSaThVcktoaWhXcTd2UXl4Mjg4bW5UUnZCZEQ5NXpuQTVKOURiMDNIa3l3K0lSWCt5azRBOEdHbitWQXhxeEpMVUZ1dnF2NVl1TTZLelZOaGNvRlBLeGpIWlpoRGloUEprd2xoNUFPcTlLcUd3WVlUU2svR1NOeXBYQ2NnMWhnK1V2aytOeVVMNzJGdVZXMU1JS3BSaGNCcmxkVjEwQ01mQXNBdWNhS1lMZWZobnZwcHBkN1R4bUVDRUNYdnNtSVJkdG5MdkN3djJBT0hMRDl1MHFGbnl4WU13ejBkUWsrdUljWkZhcTJlN0JDSGdTVzlPY0FGMUJlZi9WRGpkMUk5R20wblYwSk9VR2FuaHpLTzJNeitMbnF1V1NEMUUxRmYzaDRGZDMyaXd3Z0FjQno4SzVoYjUyTmV3UXNpRlF4TGZKNVl3dUFqdGhKVWJjRVlUUXRGalBpaXJvSGJmbS8rd25aQ2Zvc05saHRDRjlHV1VEUFFiRU5xbWRVNkxFSXV0RUZyaUlYNWMwMmhnZ0Y1VUQ4eEFkY2QyWXpnR0NidkVJSWdjVGljUjA3NDdpZW9WUHhtSlpGSGdNU2hRUTA5ZW03RGpiRFdrdytkOHJXSUxlazZNaG9iaUg2NFZYdEc3YklMeFZvblBzWmVRSDcvN2M4WUNtL3h4S2IrUW00cXhialBia3BJcW5XallBNlV5WWdhcE1ZVFBBM3RSSUVBamYvOGZEQWM5a2FJMGwyWkRSU3dlTEtPemZlQ3RXRGNDcEdYRHdMNTlTQVg2SUdUN0hVaXdZT1dUOUlrVzkrZHFBemhwWXg1cm4rSy9UOHUzcnNSM2dISlhBRTEyVUNyTkZYaFJYUlN1a2RKVHhhM2dHckR3a1JGaVZ2Wk9BVnhTclVpSEhwWTVpQTlJbXVkOUxSTGpRbDk0a1VtbE9QMVAvN3VlVEhJUHd2elowd0laNVIzZ3M3N0ZOK0NDakIwQ2FicGxoMDBhTXI0VUppUmFOZHdlWUdGV21NNFQ4RU1nY0dnWT0iLCJtYWMiOiI0ZTU4ZmJkNTdkYmY0NGE4NTJjZjlhNDExNzE2YjhlOWM2NTA5OGY2MDA4OTcyZDVlOTljY2JjZDhmMjBhMDUyIiwidGFnIjoiIn0=",
"provider_refresh_token_encrypted": "eyJpdiI6IkJGMkdRVHRKM2VTcitKNGcvQWJtUGc9PSIsInZhbHVlIjoicmFyRkxPZ1Rybm1ORXlEVjJ2TXFGTzJtM3hWaFhnUVVHN2ZlR1lRM0I5d3ozbnZTcU5EdzJqRkI2elhyNWhlenRTUXV3bjk0N1JXeklDMVAyUzBKcHc9PSIsIm1hYyI6ImJhODVjMGQyZDE3Y2ExNjc2OWVjYWJiNmFjYWVkODIyMTMyNWVhYTExMTgwYTEyMTU0MzUzZGE1YjQ5YzQ5ZjEiLCJ0YWciOiIifQ==",
"encryption_key": "0x01020300788C37CDF66ABE9301A68D5D4866AC0C197E04EEE4D904F20A59991322EBAE252301BEF4B24FF01359E934E5654617E4EEAC0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040CEB00EF45BDEA999A5558889E020110802B925F372F7BEFAF0B45E48686113D1DA430ECFCC07B1F61BA6828CC44235278EDB05C486E8068D0BE737D91",
"sociable_type": "user",
"owner_id": 23460
}
]
Project
Project
New File or Directory…...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
53262
|
1870
|
2
|
2026-05-18T11:59:51.068403+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779105591068_m1.jpg...
|
PhpStorm
|
faVsco.js – Constants.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'...
|
[{"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":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>114 incoming commits<br/>","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":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false}]...
|
-4047408223668449518
|
-8636777727364969024
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
SlackFileEditViewGoHistoryWindowHelpEUDOCKER881DEV (docker)782X t1DOCKER (docker-compose)kibana{"type""log""@timestamp":"2026-05-18T11:59:46Z"sticsearch""tags" : ["warning""ela9200/"},"data"],"pid" :7,message": "Unable torevive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T11:59:46Z", "tags" : ["warning"sticsearch", "data"],"message": "No livingconnections"}kibana1 {"type" : "log".ns","@timestamp" : "2026-05-18T11: 59:46Z""tags": ["error","reporting","queue-worker""error"], "pid":7, "message" : "mpau4y7h00070bdf8646mdeojob querying failed: Error: No Living connections\nsendReqWithConnection (/usr/share/kibana/node_modules/elasticsearch/src/lib/transport.js:266:15)\nat next (/usr/share/kibana/node_modules/elasticsearch/src/lib/connection_pool.js:243:7)\ness._tickCallback (internal/process/next_tick.js:61:11)"}kibana1 {"type" : "log".,"@timestamp" : "2026-05-18T11:59:47Z", "tags" : ["error"icsearch", "data"],"pid":7,"message":"[ConnectionError]: getaddrinfo ENOTFOUND elasticsearchelasticsearch:9200"}kibana{"type" : "log""@timestamp": "2026-05-18T11:59:48Z", "tags" : ["warning", "elasticsearch", "data"],"pid":7,"message":"Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T11:59:48Z", "tags" : ["warning", "elasticsearch", "data"], "pid":7, "message" : "No living connections"}kibanans"1 {"type": "log""@timestamp" : "2026-05-18T11:59:48Z", "tags" : ["error""taskManager""taskManager"], "pid" :7, "message" : "Failed to poll for work: Error: No Living connections"}1 {"type": "log", "@timestamp" : "2026-05-18T11:59:49Z","tags" : ["warning","elasticsearch", "data"], "pid":7, "message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T11:59:49Z", "tags" : ["warning", "elasticsearch", "data"], "pid" :7, "message" : "No living connections"}1 {"type" : "log", "@timestamp" : "2026-05-18T11:59:49Z".,"tags" : ["warning","licensing"], "pid" :7, "message" : "License information could not be obtained fromticsearch due to Error: No Living connections error"}1 {"type" : "log", "@timestamp" : "2026-05-18T11:59:49Z""tags" : ["warning", "monitoring"], "pid" :7, "message": "Unable to revive connection: [URL_WITH_CREDENTIALS] : ["warning"sticsearch", "monitoring"],"pid":7, "message": "No living connections"}I {"type" : "log", "@timestamp" : "2026-05-18T11:59:49Z""tags" : ["warning","licensing"], "pid" :7, "message" : "License information could not beticsearch due to Error: No Living connections error"}1 {"type": "log", "@timestamp": "2026-05-18T11:59:49Z", "tags" : ["error"icsearch", "data"], "pid" :7,"message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}View in Docker Desktop• View ConfigEnable WatchHomeDMsActivityFilesLaterMoreED-Jiminny ...Metrotrtene# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...0 Direct messages. Nikolay YankovR. Aneliya Angelovaão Stefka Stoyanova. Stoyan Tomov€. Vasil Vasilev% Galya DimitrovaLe Todor Stamatov "NMario GeorgievNikolay IvanovLo James Graham *. Stoyan Tanev&. Steliyan Georgiev&e Petko KashinskiLukas Kovalik y...AppsJira CloudToastGoogle Cale...Support Daily - in 1m100% <78• Mon 18 May 14:59:50Support Dailyin 1m - 15:00-15:15= Notes - Support Daily.C Join Google MeetmessagesLe Aaa canvaso riesPreparation for Refinementin 1m - 15:00-16:00= Notes - Preparation for RefinementC7 Join Google Meetпс ме пускаNikolay Yankov 2:17 PMЕй сегаГОТОВОLukas Kovalik 2:26 PMоще ведньж и в СФNikolay Yankov 2:27 PMгТоТОвОLukas Kovalik 2:27 PMработи вечеNikolay Yankov 2:27 PMимаше ли нещо за фиксLukas Kovalik 2:28 PMтрябва да си вързан към SF да работиNikolay Yankov 2:28 PMaxaaaNikolay Yankov 2:41 PMимаме approve на PRда го даваме за QА?Lukas Kovalik 2:42 PMдаMessage Nikolay Yankov...
|
53261
|
NULL
|
NULL
|
NULL
|
|
53227
|
1866
|
12
|
2026-05-18T11:52:28.970041+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779105148970_m1.jpg...
|
PhpStorm
|
faVsco.js – Constants.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
|
[{"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}]...
|
8043719072324535154
|
-8628527368849355612
|
click
|
hybrid
|
NULL
|
Project: faVsco.js, menu
SlackFileEditViewGoHistor Project: faVsco.js, menu
SlackFileEditViewGoHistoryWindowHelpEUDOCKERX t1DOCKER (docker-compose)881DEV (docker)782"@timestamp"'2026-05-18T11:52:19Z",sticsearch","tags" : ["warning","monitoring"],"pid" :7,connections"}{"type" : "log""@timestamp": "2026-05-18T11:52:19Z","tags" : ["warning""licensing"],"pid":7, "message": "License informationcould not be obtained fromError: No Living connections error"}1 {"type" : "log".,"@timestamp" : "2026-05-18T11:52:20Z""tags": ["warning"sticsearch", "data"], "pid" :7,"message" : "Unable torevive connection: [URL_WITH_CREDENTIALS] "2026-05-18T11:52:20Z", "tags" : ["warning", "elasticsearch", "data"],"pid" :7,"message":"No livingconnections "}kibana1 {"type" : "log""@timestamp":"2026-05-18T11:52:20Z""tags" : ["error"ns""taskManager""taskManager"], "pid":7, "message" : "Failed to pollfor work: Error: No Livingconnections"}kibana1 {"type" : "log""@timestamp": "2026-05-18T11:52:21Z", "tags" : ["error","elasticsearch".,"data"],"pid" :7, "message":"[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana"@timestamp": "2026-05-18T11:52:23Z","tags": ["warning","elasticsearch", "data"], "pid":7, "message": "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T11:52:23Z", "tags" : ["warning"sticsearch", "data"],"pid" :7,"message": "No living connections"}kibana1 {"type" : "log","@timestamp": "2026-05-18T11:52:23Z"ns", "tags" : ["error", "plugi, "taskManager""taskManager"],"pid":7, "message": "Failed to poll for work: Error: No Living connections"}kibana1 {"'type": "log", "@timestamp" : "2026-05-18T11:52:23Z" ,"tags" : ["error""elasticsearch", "data"], "pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type" : "log","@timestamp" : "2026-05-18T11:52:24Z","tags" : ["error""elasticsearch", "data"], "pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibanaI {"type" : "log", "@timestamp" : "2026-05-18T11:52:26Z""tags" : ["warning","elasticsearch", "data"], "pid":7, "message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] "2026-05-18T11:52:26Z" , "tags" : ["warning", "elasticsearch", "data"], "pid":7, "message" : "No livingconnections"}kibana1 {"type" : "log"!, "@timestamp" : "2026-05-18T11:52:26Z","tags" : ["error"ns","taskManager", "taskManager"],"pid":7, "message": "Failed to poll for work: Error: No Living connections"}kibana1 {"type": "log", "@timestamp" : "2026-05-18T11:52:26Z", "tags" : ["error","elasticsearch", "data"], "pid" :7,"message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearchelasticsearch:9200"}View in Docker Desktop• View ConfigEnable WatchHomeDMsActivityFilesLaterMoreJiminny ...Metrotrtencee# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...0 Direct messages. Nikolay YankovR. Aneliya Angelovaão Stefka Stoyanova. Stoyan Tomov€. Vasil VasilevGalya DimitrovaLe Todor Stamatov "NMario GeorgievNikolay IvanovLo James Graham *2 Stoyan Tanev&. Steliyan Georgiev&e Petko KashinskiE. Lukas Kovalik y...AppsJira CloudToastSupport Daily • in 8 m100% <78• Mon 18 May 14:52:28Describe what you are looking forNikolay Yankov6 0•Messagest Add canvasO Files+Todayне ме пускаNikolay Yankov 2:17 PMЕй сегаГОТОВОLukas Kovalik 2:26 PMоще ведньж и в СФNikolay Yankov 2:27 PMГТОТОвОLukas Kovalik 2:27 PMработи вечеNikolay Yankov 2:27 PMимаше ли нещо за фиксLukas Kovalik 2:28 PMтрябва да си вързан към SF да работиNikolay Yankov 2:28 PMaxaaaNikolay Yankov 2:41 PMимаме approve на PRда го даваме за QА?Lukas Kovalik 2:42 PMдаMessage Nikolay Yankov...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
53222
|
1867
|
9
|
2026-05-18T11:52:03.719021+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779105123719_m2.jpg...
|
PhpStorm
|
faVsco.js – Constants.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
namespace Jiminny\Component\SCIM;
use Jiminny\Component\SCIM\Builders\Filters;
class Constants
{
/**
* HTTP codes
*/
public const HTTP_OK = 200;
public const HTTP_CREATED = 201;
public const HTTP_NO_CONTENT = 204;
public const HTTP_NOT_FOUND = 404;
public const HTTP_BAD_REQUEST = 400;
public const HTTP_ACCESS_DENIED = 403;
public const HTTP_ERROR = 501;
/**
* Users resource constants
*/
public const USER_FIRST_NAME = 'givenName';
public const USER_FAMILY_NAME = 'familyName';
public const USER_STATUS = 'Active';
public const USER_USERNAME = 'UserName';
public const USER_EXTERNAL_ID = 'externalId';
public const USER_FIELDS = [
self::USER_FIRST_NAME,
self::USER_FAMILY_NAME,
self::USER_STATUS,
self::USER_USERNAME,
];
public const META_OPERATIONS_REPLACE = 'replace';
public const META_OPERATIONS_REPLACE_UPPER = 'Replace';
public const META_OPERATIONS_ADD = 'add';
public const META_OPERATIONS_ADD_UPPER = 'Add';
public const META_OPERATIONS_REMOVE_UPPER = 'Remove';
public const META_OPERATIONS_REMOVE = 'remove';
public const META_ID = 'id';
public const META_PHONE_NUMBERS = 'phoneNumbers';
public const META_TITLE = 'title';
public const META_ROLES = 'roles';
public const META_PATH = 'path';
public const META_ENTERPRISE_SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';
public const META_DEPARTMENT = 'department';
public const META_META = 'meta';
public const META_TYPE = 'type';
public const META_VALUE = 'value';
public const META_OPERATIONS = 'Operations';
public const META_OP = 'op';
public const META_RESOURCE_TYPE = 'resourceType';
public const META_CREATED = 'created';
public const META_LAST_MODIFIED = 'lastModified';
public const META_FORMATTED = 'formatted';
public const META_EMAILS = 'emails';
public const META_USERNAME = 'userName';
public const META_NAME = 'name';
public const META_STATUS = 'active';
public const META_PRIMARY = 'primary';
public const META_ERROR_STATUS = 'status';
public const META_ERROR_DETAIL = 'detail';
public const META_LIST_TOTAL_RESULTS = 'totalResults';
public const META_LIST_RESOURCES = 'Resources';
public const META_LIST_START_INDEX = 'startIndex';
public const META_LIST_COUNT = 'count';
public const META_LIST_ITEMS_PER_PAGE = 'itemsPerPage';
public const META_SCHEMAS = 'schemas';
public const META_FILTER = 'filter';
public const META_TYPE_WORK = 'work';
public const META_PHONE_NUMBER_TYPE_MOBILE = 'mobile';
public const META_EMAIL_TYPE_HOME = 'home';
public const META_CONTAINER_NAME = 'name';
public const META_CONTAINER_EMAILS = 'emails';
public const RESOURCE_TYPE_USER = 'User';
public const USER_PATCH_ATTR_TITLE = 'title';
public const USER_PATCH_ATTR_ACTIVE = 'active';
public const USER_PATCH_ATTR_USERNAME = 'userName';
public const USER_PATCH_ATTR_FIRST_NAME = 'name.givenName';
public const USER_PATCH_ATTR_LAST_NAME = 'name.familyName';
public const USER_PATCH_ATTR_PRIMARY_EMAIL = 'emails[type eq "work"].value';
public const USER_PATCH_ATTR_SECONDARY_EMAIL = 'emails[type eq "home"].value';
public const USER_PATCH_ATTR_PHONE_NUMBER = 'phoneNumbers[type eq "work"].value';
public const USER_PATCH_ATTR_PHONE_NUMBER_MOBILE = 'phoneNumbers[type eq "mobile"].value';
public const USER_PATCH_ATTR_ROLES = 'roles';
public const USER_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [
self::USER_PATCH_ATTR_TITLE => Mutators\Attributes\User\TitleAttr::class,
self::USER_PATCH_ATTR_ACTIVE => Mutators\Attributes\User\ActiveAttr::class,
self::USER_PATCH_ATTR_USERNAME => Mutators\Attributes\User\UsernameAttr::class,
self::USER_PATCH_ATTR_FIRST_NAME => Mutators\Attributes\User\FirstNameAttr::class,
self::USER_PATCH_ATTR_LAST_NAME => Mutators\Attributes\User\LastNameAttr::class,
self::USER_PATCH_ATTR_PRIMARY_EMAIL => Mutators\Attributes\User\PrimaryEmailAttr::class,
self::USER_PATCH_ATTR_SECONDARY_EMAIL => Mutators\Attributes\User\SecondaryEmailAttr::class,
self::USER_PATCH_ATTR_PHONE_NUMBER => Mutators\Attributes\User\PhoneNumberPrimaryAttr::class,
self::USER_PATCH_ATTR_PHONE_NUMBER_MOBILE => Mutators\Attributes\User\PhoneNumberSecondaryAttr::class,
self::USER_PATCH_ATTR_ROLES => Mutators\Attributes\User\RoleAttr::class,
];
public const FILTER_OPERATOR_EQ = 'eq';
public const SUPPORTED_FILTERS_OPERATORS = [
self::FILTER_OPERATOR_EQ,
];
public const USER_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [
self::USER_FILTER_LOCAL_ID => Filters\User\LocalIdFilter::class,
self::USER_FILTER_USERNAME => Filters\User\UserNameFilter::class,
self::USER_FILTER_FIRST_NAME => Filters\User\FirstNameFilter::class,
self::USER_FILTER_LAST_NAME => Filters\User\LastNameFilter::class,
self::USER_FILTER_EXTERNAL_ID => Filters\User\ExternalIdFilter::class,
self::USER_FILTER_DISPLAY_NAME => Filters\User\DisplayNameFilter::class,
];
public const USER_FILTER_LOCAL_ID = 'id';
public const USER_FILTER_USERNAME = 'userName';
public const USER_FILTER_FIRST_NAME = 'givenName';
public const USER_FILTER_LAST_NAME = 'familyName';
public const USER_FILTER_EXTERNAL_ID = 'externalId';
public const USER_FILTER_DISPLAY_NAME = 'DisplayName';
public const SCIM_SUPPORTED_RESOURCES = [
self::USER_RESOURCE_PREFIX,
self::GROUP_RESOURCE_PREFIX,
];
public const USER_RESOURCE_PREFIX = 'Users';
public const GROUP_RESOURCE_PREFIX = 'Groups';
public const OUTGOING_SCHEMAS_SUPPORTED = [
self::OUTGOING_CORE_USER,
];
/**
* Outgoing supported schemas
*/
public const OUTGOING_CORE_USER = 'urn:ietf:params:scim:schemas:core:2.0:User';
public const OUTGOING_ERROR = 'urn:ietf:params:scim:api:messages:2.0:Error';
public const OUTGOING_LIST_RESPONSE = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';
public const OUTGOING_CORE_GROUP = 'urn:ietf:params:scim:schemas:core:2.0:Group';
/**
* Groups resource constants
*/
public const GROUP_ATTRIBUTE_DISPLAY_NAME = 'displayName';
public const GROUP_ATTRIBUTE_EXTERNAL_ID = 'externalId';
public const GROUP_ATTRIBUTE_ID = 'id';
public const RESOURCE_TYPE_GROUP = 'Group';
public const GROUP_FILTER_QUERY_NAME = 'filter';
public const GROUP_EXCLUDED_ATTRIBUTES = 'excludedAttributes';
public const GROUP_SUPPORTED_FILTER_ATTRIBUTES = [
self::GROUP_ATTRIBUTE_DISPLAY_NAME,
];
public const GROUP_MEMBERS = 'members';
public const SUPPORTED_PATCH_OPERATIONS = [
self::META_OPERATIONS_ADD,
self::META_OPERATIONS_REPLACE,
self::META_OPERATIONS_REMOVE,
];
public const GROUP_PATCH_ATTRIBUTE_MEMBERS = 'members';
public const GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME = 'displayName';
public const GROUP_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [
self::GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME => Mutators\Attributes\Group\DisplayNameAttr::class,
self::GROUP_PATCH_ATTRIBUTE_MEMBERS => Mutators\Attributes\Group\MembersAttr::class,
];
public const GROUP_FILTER_DISPLAY_NAME = 'displayname';
public const GROUP_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [
self::GROUP_FILTER_DISPLAY_NAME => Filters\Group\DisplayNameFilter::class,
];
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny_jupiter
Sync Changes
Hide This Notification
Code changed:
Hide
19
19
17
Previous Highlighted Error
Next Highlighted Error
SELECT * FROM teams WHERE id = 1;
select * from crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 283;
SELECT * FROM crm_fields WHERE id = 2234;
SELECT * FROM crm_field_values WHERE crm_field_id = 2234;
select * from crm_profiles where user_id = 143;
select * from record_types where crm_configuration_id = 39; # 0121K000001MHElQAO,0121K000001MHEqQAO
select * from business_processes where crm_configuration_id = 39;
# 01941000000H669AAC, 01941000000H66JAAS
select * from record_type_field_values
where record_type_id IN (24);
select * from crm_field_values where id IN (2730);
select * from crm_configurations where id = 39;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce'; #1035
select * from users where team_id = 1; # 222 group 3
SELECT * FROM activities WHERE user_id = 222 order by id desc;
select * from sidekick_settings where team_id = 1;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from activities where crm_configuration_id = 2
and provider = 'ms-teams' and id = 608765;
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id = '59523413338';
select * from sidekick_settings where team_id = 2;
SELECT * FROM activities WHERE id = 608660;
select * from activity_summary_logs where activity_id = 608660;
select * from ai_prompts where transcription_id = 11214;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('ed78a437-2804-450e-ab2f-56ab1c641346') = uuid;
# id: 608818, crm: 59628809737
SELECT * FROM activities WHERE uuid_to_bin('36b06e55-afdd-4782-8dee-c624cd0af191') = uuid;
# id: 608821, crm: 59632069252
SELECT ce.start_time, ce.end_time, a.id, a.uuid, crm_provider_id, calendar_event_id, title,
playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id,
scheduled_start_time, scheduled_end_time, actual_start_time, actual_end_time, a.created_at
FROM activities a
join calendar_events ce on a.calendar_event_id = ce.id
WHERE a.id IN (608818, 608821);
select * from users where team_id = 1;
select * from team_settings where team_id = 1;
select * from crm_profiles where crm_configuration_id = 39 order by user_id;
select * from team_features where team_id = 1;
select * from users where team_id = 2;
SELECT * FROM activities WHERE uuid_to_bin('ec7647e9-5225-458b-b475-f31aa2769204') = uuid; # 612639
# Preslava N. Ivanova, grou id 3
SELECT * FROM opportunities WHERE uuid_to_bin('a2928fe5-aec5-46cb-85d9-7654c89e46a6') = uuid;
select * from activities where opportunity_id = 344 and actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00';
select
a.id,
a.type,
a.scheduled_start_time,
a.actual_start_time,
a.created_at,
a.opportunity_id,
a.status
FROM activities a
WHERE opportunity_id = 344
and status IN ('completed', 'received', 'delivered')
and (
(a.actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')
OR (a.created_at between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')
OR (a.scheduled_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00'))
;
SELECT * FROM users WHERE id = 222;
SELECT * FROM crm_profiles WHERE user_id = 222;
select * from crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 281;
select * from group_deal_risk_types;
select * from opportunities where team_id = 1;
SELECT * FROM opportunities WHERE id = 315;
SELECT * FROM crm_field_data WHERE object_id = 315;
select * from crm_field_data where object_id = 260;
select * from generic_ai_prompts where subject_id = 315;
select * from teams; # 36, 21, 121, [EMAIL]
SELECT * FROM social_accounts WHERE sociable_id = 121 and provider = 'bullhorn';
# [PASSWORD_DOTS]
select * from teams where id = 1;
select * from crm_configurations where id = 39;
select * from users where team_id = 1;
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 1;
# 1 - 00541000004281rAAA
# 204 - 0052g000003freeAAA
# 429 - 0052g000003qGOiAAM
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce';
select * from activities where type = 'softphone'
and created_at > '2024-12-11 15:24:36' order by id desc;
select * from activity_providers where team_id = 1;
select * from activity_provider_users where activity_provider_id = 328;
select * from opportunities where crm_configuration_id = 39
AND account_id = 178 AND is_closed = false
order by created_at DESC;
select * from contacts where id = 3952;
select * from accounts where id = 178;
# [PASSWORD_DOTS]
select * from teams where id = 36;
select * from crm_configurations where id = 21;
select * from users where team_id = 36;
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 36;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 36
and sa.provider = 'bullhorn';
select * from social_accounts where id = 348;
UPDATE social_accounts SET
provider_user_token = '21442_6802599_91:41179a58-21e7-4d7c-ad58-56bb666b2f65',
provider_refresh_token = '21442_6802599_91:01c6b335-3f2a-42e4-85ff-8a08fa65fceb',
expires = 1733998131,
state = 'connected'
WHERE id = 348;
# [PASSWORD_DOTS]
select * from teams where id = 31;
select * from crm_configurations where id = 18;
select * from users where team_id = 31; # 257
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 31;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 31
and sa.provider = 'close';
select * from contacts where crm_configuration_id = 18;
# [PASSWORD_DOTS] NEPTUNE [PASSWORD_DOTS]
select * from teams;
select * from users where id IN (1030, 1035, 1052);
select * from crm_configurations;
select * from users where team_id = 65; # 257
select * from team_settings where team_id = 65; # 257
select * from invitations where team_id = 65; # 257
select * from users where email = '[EMAIL]'; # 257
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 65;
select * from crm_configurations where id = 53;
select * from accounts where crm_configuration_id = 53 order by id desc;
select * from leads where crm_configuration_id = 53 order by id desc;
select * from contacts where crm_configuration_id = 53 order by id desc;
select * from opportunities where crm_configuration_id = 53 order by id desc;
select * from crm_profiles where crm_configuration_id = 53 order by id desc;
select * from crm_fields where crm_configuration_id = 53 order by id desc;
select * from crm_field_values where crm_field_id = 3341 order by id desc;
select * from crm_layouts where crm_configuration_id = 53 order by id desc;
select * from stages where crm_configuration_id = 53 order by id desc;
select * from crm_profiles where crm_configuration_id = 13;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 65
and sa.provider = 'integration-app';
select * from contacts where crm_configuration_id = 13;
select * from social_accounts where sociable_id = 283;
SELECT * FROM opportunities WHERE crm_provider_id = '006O400000E9bzeIAB';
select * from activity_providers where team_id = 65;
SELECT * FROM activities WHERE crm_configuration_id IN (51, 52, 53);
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 65
;
# [PASSWORD_DOTS] STAGING [PASSWORD_DOTS]
SELECT * FROM teams;
SELECT * FROM teams WHERE id = 88;
SELECT * FROM teams WHERE id = 89;
select * from team_settings where team_id = 89;
SELECT * FROM users WHERE team_id = 89;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 89;
select * from users;
SELECT * FROM social_accounts WHERE sociable_id = 1761;
SELECT * FROM crm_configurations WHERE id = 70;
select * from accounts where crm_configuration_id = 70 order by id desc;
select * from leads where crm_configuration_id = 70 order by id desc;
select * from contacts where crm_configuration_id = 70 order by id desc;
select * from opportunities where crm_configuration_id = 70 order by id desc;
select * from crm_profiles where crm_configuration_id = 70 order by id desc;
select * from crm_fields where crm_configuration_id = 70 order by id desc;
select * from crm_field_values where crm_field_id = 3536 order by id desc;
select * from crm_layouts where crm_configuration_id = 70 order by id desc;
select * from stages where crm_configuration_id = 70 order by id desc;
select * from business_processes where crm_configuration_id = 70 order by id desc;
select * from business_process_stages where business_process_id = 34;
select * from contacts where id = 10468;
select * from crm_layouts where crm_configuration_id = 70;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 388;
SELECT * FROM crm_fields WHERE id IN (3533,3534,3535);
select * from activities where crm_configuration_id = 70
and (account_id IS NOT NULL or lead_id IS NOT NULL or contact_id IS NOT NULL or opportunity_id IS NOT NULL) order by id desc;
SELECT * FROM activities WHERE uuid_to_bin('2e10b60f-8a61-41c5-a3d4-28835353dc65') = uuid;
SELECT * FROM activities where crm_configuration_id = 69 ;
SELECT * FROM users WHERE email LIKE '%[EMAIL]%';
SELECT * FROM activities WHERE uuid_to_bin('5a150c93-40fc-42ec-b3bd-c1d328e09f6e') = uuid;
SELECT * FROM opportunities WHERE id = 385;
select * from participants p
join activities a on p.activity_id = a.id
where a.crm_configuration_id = 70
and (p.lead_id IS NOT NULL or p.contact_id IS NOT NULL);
SELECT * FROM participants WHERE id = 1013638;
select * from teams where id = 90;
select * from users where team_id = 90;
select * from social_accounts where social_accounts.sociable_id IN (1960,1760);
SELECT * FROM crm_profiles WHERE crm_configuration_id = 71;
select * from invitations where team_id = 90;
select * from crm_configurations where id = 71;
select * from accounts where crm_configuration_id = 71 order by id desc;
select * from leads where crm_configuration_id = 71 order by id desc;
select * from contacts where crm_configuration_id = 71 order by id desc;
select * from opportunities where crm_configuration_id = 71 order by id desc;
select * from crm_profiles where crm_configuration_id = 71 order by id desc;
select * from crm_fields where crm_configuration_id = 71 order by id desc;
select * from crm_field_values where crm_field_id = 3341 order by id desc;
select * from crm_layouts where crm_configuration_id = 71 order by id desc;
select * from stages where crm_configuration_id = 71 order by id desc;
select * from users order by secondary_email desc;
select u.id, u.email, u.status, sa.id, sa.provider_user_id from social_accounts sa
join users u on sa.sociable_id = u.id
where sa.provider = 'google' and u.email LIKE 'aneliya%';
select * from failed_jobs order by id desc;
select * from users where email = '[EMAIL]' or secondary_email = '[EMAIL]';
select * from teams;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 39;
SELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type = 'task';
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce';
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('c38b3895-fd0f-4b1f-9fb2-c170dba137c6') = uuid;
SELECT * FROM crm_configurations WHERE id = 70;
select * from teams where id = 1;
select * from groups where team_id = 1;
select * from users where team_id = 1;
select o.id, o.name,o.close_date, u.id, u.name, u.group_id, r.id, r.display_name, g.name, g.scope from opportunities o
join users u on o.user_id = u.id
join groups g on u.group_id = g.id
join role_user ru on u.id = ru.user_id
join roles r on ru.role_id = r.id
where o.crm_configuration_id = 39 and close_date > '2024-01-01 00:00:00';
select * from role_user where user_id = 143;
select * from roles;
select * from role_user;
select * from groups where id = 9;
select * from scope_groups where group_id = 9;
# [PASSWORD_DOTS]
select * from teams where id = 36;
select * from crm_configurations;
SELECT * FROM social_accounts WHERE sociable_id = 121;
https://crmsandbox.zoho.com/crm/jiminnyw4/tab/Leads/4776201000005049105
https://crmsandbox.zoho.com/crm/
https://crm.zoho.com/crm/org3469620/tab/Leads/230045000229559080
https://crm.zoho.com/crm/
org3469620
SELECT * FROM activities WHERE uuid_to_bin('03382d20-c8bc-48e7-a3d4-90b52fa5ceab') = uuid;
select * from users where email LIKE "%mobile_automation_%";
select * from social_accounts where sociable_id IN (2228);
select * from crm_profiles where user_id IN (2222,2223,2226,2227);
select * from teams order by id desc;
SELECT * FROM users WHERE id = 2229;
SELECT * FROM crm_profiles WHERE user_id = 2229;
select * from opportunities where crm_configuration_id = 88;
select * from crm_fields where crm_configuration_id = 88;
select * from crm_profiles where crm_configuration_id = 88;
SELECT * FROM teams WHERE id = 1;
SELECT * FROM users WHERE id = 143;
SELECT * FROM users WHERE uuid_to_bin('fde193d3-06a2-4e1a-8895-62b94039215d') = uuid;
SELECT * FROM teams WHERE uuid_to_bin('73385071-a756-42ae-9c73-8b53f2309467') = uuid;
https://app.staging.jiminny.com/ondemand?
min_duration=1
&
only_recorded=1
&
user_id%5B%5D=641f1acb-16b8-42d1-8726-df52979dad0e
&
sequence_number=2
select * from users where team_id = 1 and email like '%stoyan%'
select * from coaching_feedbacks;
select * from teams;
SELECT * FROM users WHERE team_id = 36;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 19
and sa.provider = 'pipedrive';
select * from users where id = 143;
SELECT * FROM users WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
SELECT * FROM teams WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
SELECT * FROM activity_shares WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
select * from users where team_id = 2;
select * from activities where crm_configuration_id = 39
and activities.scheduled_start_time BETWEEN '2025-04-09 00:00:00' AND '2025-04-09 23:59:59'
AND user_id = 143
order by id desc;
# [PASSWORD_DOTS]
select * from teams where id = 142; # 2312, 126
select * from team_settings;
select * from users where team_id = 142; # 21642
SELECT * FROM social_accounts WHERE sociable_id = 21642;
SELECT * FROM crm_profiles cp join users u ON u.id = cp.user_id WHERE team_id = 142;
select * from crm_profiles where id IN (93);
select * from invitations;
select * from team_features where team_id = 1;
SELECT * FROM crm_configurations WHERE id = 126;
select * from accounts where crm_configuration_id = 126 order by id desc;
select * from leads where crm_configuration_id = 126 order by id desc;
select * from contacts where crm_configuration_id = 126 order by id desc;
select * from opportunities where crm_configuration_id = 126 order by id desc;
select * from crm_profiles where crm_configuration_id = 126 order by id desc;
select * from crm_fields where crm_configuration_id = 126 # 11060
# and type IN ('picklist', 'status')
# and object_type = 'task'
order by id desc;
# 5731,5732,5733
select DISTINCT crm_field_id from crm_field_values where crm_field_id IN (11151,12239,12215,12185,12175,12165,12144,12137,12127,12109,12107,12105,12103,12092,12037,12005,12003,11987,11969,11958,11951,11942,11931,11924,11921,11917,11915,11901,11893,11883,11872,11870,11868,11866,11839,11833,11821,11793,11780,11777,11769,11757,11737,11735,11656,11645,11638,11629,11618,11611,11602,11591,11584,11581,11558,11544,11543,11534,11532,11529,11527,11503,11497,11493,11488,11470,11468,11457,11455,11397,11387,11372,11363,11348,11323,11318,11309,11301,11300,11292,11290,11286,11284,11256,11252,11242,11237,11233,11219,11176,11160) order by id desc;
select * from crm_layouts where crm_configuration_id = 126 order by id desc;
SELECT * FROM crm_layout_entities WHERE crm_layout_id in (300,299,298);
select * from stages where crm_configuration_id = 126 order by id desc;
select * from business_processes where crm_configuration_id = 126 order by id desc;
select * from business_process_stages where business_process_id IN (76,75,74,73);
select * from playbooks where team_id = 142;
select * from playbook_layouts where playbook_id IN (108);
SELECT * FROM playbook_categories WHERE playbook_id IN (108);
select * from teams where id = 130;
SELECT * FROM social_accounts WHERE sociable_id = 2291;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 2
and sa.provider = 'hubspot';
SELECT * FROM activities
WHERE crm_configuration_id = 110;
select * from teams;
select * from crm_configurations;
SELECT * FROM activities WHERE id = 628773;
SELECT * FROM crm_profiles WHERE user_id = 1460;
SELECT * FROM social_accounts WHERE sociable_id = 2291;
select * from teams;
select ru.*, pr.*, p.* from users u join role_user ru on ru.user_id = u.id
join permission_role pr on pr.role_id = ru.role_id
join permissions p on p.id = pr.permission_id
where team_id = 495 and p.name IN ('dial');
select * from teams where id = 145;
select * from crm_configurations where id = 129;
select * from social_accounts where sociable_id = 2317;
SELECT * FROM activities WHERE uuid_to_bin('8dbab184-a333-4268-ad57-fb41f8d53a9a') = uuid;
select * from teams where id = 1;
SELECT * FROM crm_layouts WHERE crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 280;
SELECT * FROM crm_layout_entities WHERE id = 5507;
SELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type IN ('event');
select * from teams;
select * from activities where crm_configuration_id = 14;
SELECT * FROM social_accounts where provider = 'copper';
select * from activities where id = 628467;
select * from participants where activity_id = 628467;
SELECT * FROM contacts WHERE id = 3969;
SELECT * FROM accounts WHERE id = 177;
SELECT * FROM activities WHERE uuid_to_bin('4eb54c77-cfa3-2bd4-84a7-9ed46a21c988') = uuid;
# [PASSWORD_DOTS] BH
select * from teams where id = 36;
SELECT * FROM crm_configurations WHERE id = 21;
select * from activities where crm_configuration_id = 21 and id = 607901;
select * from activities where crm_configuration_id = 21;
select * roles;
select * from permissions;
select * from permission_role where permission_id = 226;
select * from migrations order by id desc;
# mercury
# neptune
# earth
select * from teams;
select * from teams where id = 19;
select * from teams where id = 27;
select * from users where team_id = 27;
SELECT * FROM crm_configurations WHERE id = 42;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 19
and sa.provider = 'pipedrive';
select * from activities where id = 631461;
SELECT * FROM crm_field_values WHERE crm_field_id = 180;
select * from teams where id = 2;
SELECT * FROM social_accounts WHERE sociable_id = 89;
SELECT * FROM activities WHERE uuid_to_bin('ba0c029a-bc14-4e17-8603-64174acebcbb') = uuid; # 634273
select * from activity_summary_logs where activity_id = 634273;
select * from sidekick_settings where team_id = 2;
select * from teams; # 2, 2
SELECT * FROM crm_configurations WHERE team_id = 2; # 2
select * from team_features where team_id = 2;
select * from features;
SELECT * FROM opportunities WHERE crm_configuration_id = 2 and crm_provider_id = '51317301383';
SELECT * FROM opportunities WHERE crm_configuration_id = 2 order by id desc;
select * from automated_reports order by id desc;
select * from automated_report_results order by id desc;
select * from users where team_id = 1 and id IN (7160, 3248);
select * from migrations order by id desc;
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 = 1052 and sa.provider = 'hubspot';
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 = 565;
select * from playbooks where team_id = 1;
select * from playbooks where id = 175;
select * from playbook_categories where playbook_id = 175;
select * from users where team_id = 1052;
select * from users where id = 7160;
select * from crm_profiles where user_id = 7160;
select * from features;
select
*
# id, uuid, type, provider, playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id, stage_id,
# crm_configuration_id, crm_provider_id, transcription_id, status
from activities where crm_configuration_id = 1 and type = 'conference'
# and crm_provider_id IS NOT NULL
and provider != 'uploader' and actual_start_time IS NOT NULL
ORDER by id desc;
select * from activities where id = 54747783; # 00UO400000pCzojMAC
select p.id, p.activity_type, pc.id, pc.name
FROM playbooks p
join playbook_categories pc on p.id = pc.playbook_id
where p.team_id = 1 and p.activity_type = 'event';
SELECT * FROM crm_fields WHERE crm_configuration_id = 1 and object_type = 'event';
SELECT * FROM crm_field_values WHERE crm_field_id = 4;
select * from crm_layouts cl join playbook_layouts pl on cl.id = pl.layout_id
where crm_configuration_id = 1 and pl.playbook_id = 175;
select * from teams;
SELECT r.* FROM automated_reports r
join teams t on r.team_id = t.id
WHERE r.frequency = 'daily'
and r.status = 1
AND t.status = 'active'
AND (r.expires_at >= now() OR r.expires_at IS NULL);
select * from automated_report_results where report_id IN (18, 33);
select * from users where team_id = 1 and id = 1047;
SELECT * FROM social_accounts WHERE sociable_id = 1047;
select * from activity_searches where id = 10932;
select * from activity_search_filters where activity_search_id = 10932;
select * from automated_reports order by id desc;
select * from automated_report_results order by id desc;
select * from automated_reports where id IN (55);
select * from automated_report_results where id IN (81);
select * from users where id IN (10633, 13987, 11985);
select * from users where group_id IN (3710);
SELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;
SELECT * FROM automated_report_results WHERE uuid_to_bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;
select * from teams;
select * from accounts where team_id = 1;
select * from automated_report_results where media_type = 'pdf' and status = 2;
SELECT * FROM automated_report_results WHERE uuid_to_bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid;
select * from teams where id = 1029;
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 = 1029 and sa.provider = 'pipedrive';
[
{
"user_id": "23460 (owner)",
"email": "[EMAIL]",
"id": 69,
"sociable_id": 23460,
"provider_user_id": "19555731",
"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,
"refresh_token_expires": null,
"provider": "pipedrive",
"state": "connected",
"auth_scope": "base,deals:full,activities:full,contacts:full,search:read",
"retry_after": null,
"created_at": "2025-04-16 08:23:28",
"updated_at": "2026-05-18 07:13:18",
"provider_user_token_encrypted": "eyJpdiI6Ik9oYzBwcTVteWN4ajBRaDdMb0FjWGc9PSIsInZhbHVlIjoiQUNMbjU5UHR2Q1RnbWRXMEU1TUx6UVpRU3gzdVc5WktmTE4rVlhXa3lRaGhyUUlZMVZRWEJuR0JaWWhZZXNPRlBuanhuYU5MVHZ5TG9NTVVjNjJSUUpZZ2VhbGYxbHg0UzJEdTVmQjNFZnJRZkMwYjd0N2RMZ05GRS9IR3c2K0NoVjBjYTA5UG12SkxHeDlDMGVNN3ptUWUzblFiTngyYzR1eUpHSEYrdEwvZm0yZklGYjBSNEtTR2ZGazhLM1hqT3lVbjFobDNPZ0d3anFlcjhKcXpERlZGOVN1YmFyNDIvM1BFRDFMYnp4WEI4TGVLM2xYcy9CL0RDOWlQNHI3N0NwWnJPMWRtZllmM2ZKeE9TV2NBeDZxL2M1YnlSVzd3ZW96T3F1QmtBYXBHYkUraGcvdCtRajlYZXBjVVBSdFlMUjVPVDVJbDdyenVoWjMrbVJvU3ZZR1dQZ3pqQ3F3aDF2U2xPZWZIN3BCWVFLNXpxQUtDb2pIK0xHc1E3SklSM3Q0VkNSbm9oK2pFK3hLaW54T1dWbEVneUp0RGhhdVBuOFI4MXROc3dZWnFnTUpiaDVMMnZ4QmlRM3k4QWFlMVFWUFYvdGhJQzZBYnhBQmhWa2ZKN1ZhSnhpaExxbmlTemgzUWw3aXJtWjlSMlhmd0lWMDNDN1N3My9Ua0hCL2xqY3RkVFhMSjFJMDRjOE5DWlgrZ3FMVXN6RWlwUE5GWERZdG1xVjVxOFlLRGs2VVJKS3FLeWRxQjYxdDh4Z2JJNXhlWEZ3dkQ4SGtybDNUcndzblFHeVJNRkYraFh2UDFIUTdMQ1BZa3dEU1dBbzk5K0dyT2RNVFBZZUJpRytSck5pYlI1YUZyMmhUNEZCdWxHYmJLREtzbUpjVkhvV0RoejJpbm1SWHlNaXE5M0RhcS94UW9EdFoweWF3bVFVY0dTZWFPSXBmOCtDYndia215cmtyZU1oT0Exam1CV2tPblNhYjY4clVEeUs3anVHUmNHeS9YLzRha1VhbGl3N3lwaDlzZnRhQUZta2s4eFllNHgzRklSRmNyazJ4dlBDMnByNCtBRjNaVjJCTT0iLCJtYWMiOiJkYTQxZDY1OTY2ZTljMTgyZWRhNGEzMGZjZDc2MjBjN2NlNzU2YTViNGQxNWE1NTI2ZmI1MWQyYjQ2ODYxZmEwIiwidGFnIjoiIn0=",
"provider_refresh_token_encrypted": "eyJpdiI6Imt2bGxlSmxUK05GMjF0dEtPaTMrUlE9PSIsInZhbHVlIjoiUXZHTElZRXkreHFxUU02SnZ4eVBacG9WWTRlVkd0USszV3JyVFlpU2ZaY25GSWo2WFcrRzNlbFRlUXRQczNwSXRCcEdvZEpveG9jMzBDSTgwdnZLQnc9PSIsIm1hYyI6ImQxYWI0NzU5Nzg5MDI4YWVhZmQ4Mjg1YzhkZDQzMjRkYWYwYTdhZTY5MDMxMjc0OWNiYjY0Nzc3NDQ0MTEyY2EiLCJ0YWciOiIifQ==",
"encryption_key": "0x01020300786192D9D96DD60D3D1EBC9DFAEE5F0C45EE80165CF3F3D2B3B627026AA7CFC7CA0128DD463535D32EE491ADBADF8B07596B0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040C7FB1319048ECB2EA3F23B995020110802B52D22F5EAD341AB238FBBCB6093156E443876A664BA5555D722565C2B2D04422C868CD7350555E3CC74221",
"sociable_type": "user",
"owner_id": 23460
},
{
"user_id": "23463",
"email": "[EMAIL]",
"id": 72,
"sociable_id": 23463,
"provider_user_id": "23270841",
"provider_user_token": "v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:txqCuWLeVhgwiaFqXIvQWWrtrnFIy_4lT3VCr-sRB4g6_2lK8KcQ_6ka_qFmZhr-IeIAKmAImx6H1iIKx4Ab7XZ5MnKIh03GKbHjI0n0rGT9UYkeH21jKOxJvKaSX_TyLbxFPR6irPQyvqcpBClXI52gVJH01KzZy_dMTHFXhhDLOIhEpSrQXHG7Qo8q7OuBeSPZrU1ALi9kmAm4GTpzGTbzfl-hUt9IAfPunJOCyv3mf2Tl-MT8EyQgOFPrsP3yz9UlSyVhb40zO_bCnUrqNxjwgm_E6vgpVrwULTQbHe-43Dq-TRetjceUzT88GBgVJ0UdxXP5BRBVXcL5ir8-9ZTMaNU",
"provider_refresh_token": "5034113:[TELEGRAM_TOKEN]78ad1",
"expires": 1753837219,
"refresh_token_expires": null,
"provider": "pipedrive",
"state": "full-refresh",
"auth_scope": "base,deals:full,activities:full,contacts:full,search:read",
"retry_after": null,
"created_at": "2025-04-16 10:41:12",
"updated_at": "2025-07-30 01:00:17",
"provider_user_token_encrypted": "eyJpdiI6InVEVEl2SzIxMjd1bkNDWG9lY3YvQ0E9PSIsInZhbHVlIjoiRlJLbDZ3ZHo2dHMxUWQwdGU2YUZjV3lPWHlxQTJ0eWh4S0RTMjlSaThVcktoaWhXcTd2UXl4Mjg4bW5UUnZCZEQ5NXpuQTVKOURiMDNIa3l3K0lSWCt5azRBOEdHbitWQXhxeEpMVUZ1dnF2NVl1TTZLelZOaGNvRlBLeGpIWlpoRGloUEprd2xoNUFPcTlLcUd3WVlUU2svR1NOeXBYQ2NnMWhnK1V2aytOeVVMNzJGdVZXMU1JS3BSaGNCcmxkVjEwQ01mQXNBdWNhS1lMZWZobnZwcHBkN1R4bUVDRUNYdnNtSVJkdG5MdkN3djJBT0hMRDl1MHFGbnl4WU13ejBkUWsrdUljWkZhcTJlN0JDSGdTVzlPY0FGMUJlZi9WRGpkMUk5R20wblYwSk9VR2FuaHpLTzJNeitMbnF1V1NEMUUxRmYzaDRGZDMyaXd3Z0FjQno4SzVoYjUyTmV3UXNpRlF4TGZKNVl3dUFqdGhKVWJjRVlUUXRGalBpaXJvSGJmbS8rd25aQ2Zvc05saHRDRjlHV1VEUFFiRU5xbWRVNkxFSXV0RUZyaUlYNWMwMmhnZ0Y1VUQ4eEFkY2QyWXpnR0NidkVJSWdjVGljUjA3NDdpZW9WUHhtSlpGSGdNU2hRUTA5ZW03RGpiRFdrdytkOHJXSUxlazZNaG9iaUg2NFZYdEc3YklMeFZvblBzWmVRSDcvN2M4WUNtL3h4S2IrUW00cXhialBia3BJcW5XallBNlV5WWdhcE1ZVFBBM3RSSUVBamYvOGZEQWM5a2FJMGwyWkRSU3dlTEtPemZlQ3RXRGNDcEdYRHdMNTlTQVg2SUdUN0hVaXdZT1dUOUlrVzkrZHFBemhwWXg1cm4rSy9UOHUzcnNSM2dISlhBRTEyVUNyTkZYaFJYUlN1a2RKVHhhM2dHckR3a1JGaVZ2Wk9BVnhTclVpSEhwWTVpQTlJbXVkOUxSTGpRbDk0a1VtbE9QMVAvN3VlVEhJUHd2elowd0laNVIzZ3M3N0ZOK0NDakIwQ2FicGxoMDBhTXI0VUppUmFOZHdlWUdGV21NNFQ4RU1nY0dnWT0iLCJtYWMiOiI0ZTU4ZmJkNTdkYmY0NGE4NTJjZjlhNDExNzE2YjhlOWM2NTA5OGY2MDA4OTcyZDVlOTljY2JjZDhmMjBhMDUyIiwidGFnIjoiIn0=",
"provider_refresh_token_encrypted": "eyJpdiI6IkJGMkdRVHRKM2VTcitKNGcvQWJtUGc9PSIsInZhbHVlIjoicmFyRkxPZ1Rybm1ORXlEVjJ2TXFGTzJtM3hWaFhnUVVHN2ZlR1lRM0I5d3ozbnZTcU5EdzJqRkI2elhyNWhlenRTUXV3bjk0N1JXeklDMVAyUzBKcHc9PSIsIm1hYyI6ImJhODVjMGQyZDE3Y2ExNjc2OWVjYWJiNmFjYWVkODIyMTMyNWVhYTExMTgwYTEyMTU0MzUzZGE1YjQ5YzQ5ZjEiLCJ0YWciOiIifQ==",
"encryption_key": "0x01020300788C37CDF66ABE9301A68D5D4866AC0C197E04EEE4D904F20A59991322EBAE252301BEF4B24FF01359E934E5654617E4EEAC0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040CEB00EF45BDEA999A5558889E020110802B925F372F7BEFAF0B45E48686113D1DA430ECFCC07B1F61BA6828CC44235278EDB05C486E8068D0BE737D91",
"sociable_type": "user",
"owner_id": 23460
}
]
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":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>114 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"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":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Component\\SCIM;\n\nuse Jiminny\\Component\\SCIM\\Builders\\Filters;\n\nclass Constants\n{\n /**\n * HTTP codes\n */\n public const HTTP_OK = 200;\n public const HTTP_CREATED = 201;\n public const HTTP_NO_CONTENT = 204;\n\n public const HTTP_NOT_FOUND = 404;\n public const HTTP_BAD_REQUEST = 400;\n public const HTTP_ACCESS_DENIED = 403;\n\n public const HTTP_ERROR = 501;\n\n /**\n * Users resource constants\n */\n public const USER_FIRST_NAME = 'givenName';\n public const USER_FAMILY_NAME = 'familyName';\n public const USER_STATUS = 'Active';\n public const USER_USERNAME = 'UserName';\n public const USER_EXTERNAL_ID = 'externalId';\n\n public const USER_FIELDS = [\n self::USER_FIRST_NAME,\n self::USER_FAMILY_NAME,\n self::USER_STATUS,\n self::USER_USERNAME,\n ];\n\n public const META_OPERATIONS_REPLACE = 'replace';\n public const META_OPERATIONS_REPLACE_UPPER = 'Replace';\n public const META_OPERATIONS_ADD = 'add';\n public const META_OPERATIONS_ADD_UPPER = 'Add';\n public const META_OPERATIONS_REMOVE_UPPER = 'Remove';\n public const META_OPERATIONS_REMOVE = 'remove';\n\n public const META_ID = 'id';\n public const META_PHONE_NUMBERS = 'phoneNumbers';\n public const META_TITLE = 'title';\n public const META_ROLES = 'roles';\n public const META_PATH = 'path';\n public const META_ENTERPRISE_SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';\n public const META_DEPARTMENT = 'department';\n public const META_META = 'meta';\n public const META_TYPE = 'type';\n public const META_VALUE = 'value';\n public const META_OPERATIONS = 'Operations';\n public const META_OP = 'op';\n public const META_RESOURCE_TYPE = 'resourceType';\n public const META_CREATED = 'created';\n public const META_LAST_MODIFIED = 'lastModified';\n public const META_FORMATTED = 'formatted';\n public const META_EMAILS = 'emails';\n public const META_USERNAME = 'userName';\n public const META_NAME = 'name';\n public const META_STATUS = 'active';\n public const META_PRIMARY = 'primary';\n public const META_ERROR_STATUS = 'status';\n public const META_ERROR_DETAIL = 'detail';\n public const META_LIST_TOTAL_RESULTS = 'totalResults';\n public const META_LIST_RESOURCES = 'Resources';\n public const META_LIST_START_INDEX = 'startIndex';\n public const META_LIST_COUNT = 'count';\n public const META_LIST_ITEMS_PER_PAGE = 'itemsPerPage';\n public const META_SCHEMAS = 'schemas';\n public const META_FILTER = 'filter';\n public const META_TYPE_WORK = 'work';\n public const META_PHONE_NUMBER_TYPE_MOBILE = 'mobile';\n public const META_EMAIL_TYPE_HOME = 'home';\n public const META_CONTAINER_NAME = 'name';\n public const META_CONTAINER_EMAILS = 'emails';\n\n public const RESOURCE_TYPE_USER = 'User';\n\n public const USER_PATCH_ATTR_TITLE = 'title';\n public const USER_PATCH_ATTR_ACTIVE = 'active';\n public const USER_PATCH_ATTR_USERNAME = 'userName';\n public const USER_PATCH_ATTR_FIRST_NAME = 'name.givenName';\n public const USER_PATCH_ATTR_LAST_NAME = 'name.familyName';\n public const USER_PATCH_ATTR_PRIMARY_EMAIL = 'emails[type eq \"work\"].value';\n public const USER_PATCH_ATTR_SECONDARY_EMAIL = 'emails[type eq \"home\"].value';\n public const USER_PATCH_ATTR_PHONE_NUMBER = 'phoneNumbers[type eq \"work\"].value';\n public const USER_PATCH_ATTR_PHONE_NUMBER_MOBILE = 'phoneNumbers[type eq \"mobile\"].value';\n public const USER_PATCH_ATTR_ROLES = 'roles';\n\n public const USER_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [\n self::USER_PATCH_ATTR_TITLE => Mutators\\Attributes\\User\\TitleAttr::class,\n self::USER_PATCH_ATTR_ACTIVE => Mutators\\Attributes\\User\\ActiveAttr::class,\n self::USER_PATCH_ATTR_USERNAME => Mutators\\Attributes\\User\\UsernameAttr::class,\n self::USER_PATCH_ATTR_FIRST_NAME => Mutators\\Attributes\\User\\FirstNameAttr::class,\n self::USER_PATCH_ATTR_LAST_NAME => Mutators\\Attributes\\User\\LastNameAttr::class,\n self::USER_PATCH_ATTR_PRIMARY_EMAIL => Mutators\\Attributes\\User\\PrimaryEmailAttr::class,\n self::USER_PATCH_ATTR_SECONDARY_EMAIL => Mutators\\Attributes\\User\\SecondaryEmailAttr::class,\n self::USER_PATCH_ATTR_PHONE_NUMBER => Mutators\\Attributes\\User\\PhoneNumberPrimaryAttr::class,\n self::USER_PATCH_ATTR_PHONE_NUMBER_MOBILE => Mutators\\Attributes\\User\\PhoneNumberSecondaryAttr::class,\n self::USER_PATCH_ATTR_ROLES => Mutators\\Attributes\\User\\RoleAttr::class,\n ];\n\n public const FILTER_OPERATOR_EQ = 'eq';\n\n public const SUPPORTED_FILTERS_OPERATORS = [\n self::FILTER_OPERATOR_EQ,\n ];\n\n public const USER_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [\n self::USER_FILTER_LOCAL_ID => Filters\\User\\LocalIdFilter::class,\n self::USER_FILTER_USERNAME => Filters\\User\\UserNameFilter::class,\n self::USER_FILTER_FIRST_NAME => Filters\\User\\FirstNameFilter::class,\n self::USER_FILTER_LAST_NAME => Filters\\User\\LastNameFilter::class,\n self::USER_FILTER_EXTERNAL_ID => Filters\\User\\ExternalIdFilter::class,\n self::USER_FILTER_DISPLAY_NAME => Filters\\User\\DisplayNameFilter::class,\n ];\n\n public const USER_FILTER_LOCAL_ID = 'id';\n public const USER_FILTER_USERNAME = 'userName';\n public const USER_FILTER_FIRST_NAME = 'givenName';\n public const USER_FILTER_LAST_NAME = 'familyName';\n public const USER_FILTER_EXTERNAL_ID = 'externalId';\n public const USER_FILTER_DISPLAY_NAME = 'DisplayName';\n\n public const SCIM_SUPPORTED_RESOURCES = [\n self::USER_RESOURCE_PREFIX,\n self::GROUP_RESOURCE_PREFIX,\n ];\n\n public const USER_RESOURCE_PREFIX = 'Users';\n public const GROUP_RESOURCE_PREFIX = 'Groups';\n\n public const OUTGOING_SCHEMAS_SUPPORTED = [\n self::OUTGOING_CORE_USER,\n\n ];\n\n /**\n * Outgoing supported schemas\n */\n public const OUTGOING_CORE_USER = 'urn:ietf:params:scim:schemas:core:2.0:User';\n public const OUTGOING_ERROR = 'urn:ietf:params:scim:api:messages:2.0:Error';\n public const OUTGOING_LIST_RESPONSE = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';\n\n public const OUTGOING_CORE_GROUP = 'urn:ietf:params:scim:schemas:core:2.0:Group';\n\n /**\n * Groups resource constants\n */\n public const GROUP_ATTRIBUTE_DISPLAY_NAME = 'displayName';\n public const GROUP_ATTRIBUTE_EXTERNAL_ID = 'externalId';\n public const GROUP_ATTRIBUTE_ID = 'id';\n public const RESOURCE_TYPE_GROUP = 'Group';\n public const GROUP_FILTER_QUERY_NAME = 'filter';\n public const GROUP_EXCLUDED_ATTRIBUTES = 'excludedAttributes';\n\n public const GROUP_SUPPORTED_FILTER_ATTRIBUTES = [\n self::GROUP_ATTRIBUTE_DISPLAY_NAME,\n ];\n\n public const GROUP_MEMBERS = 'members';\n\n public const SUPPORTED_PATCH_OPERATIONS = [\n self::META_OPERATIONS_ADD,\n self::META_OPERATIONS_REPLACE,\n self::META_OPERATIONS_REMOVE,\n ];\n\n public const GROUP_PATCH_ATTRIBUTE_MEMBERS = 'members';\n public const GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME = 'displayName';\n\n public const GROUP_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [\n self::GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME => Mutators\\Attributes\\Group\\DisplayNameAttr::class,\n self::GROUP_PATCH_ATTRIBUTE_MEMBERS => Mutators\\Attributes\\Group\\MembersAttr::class,\n ];\n\n public const GROUP_FILTER_DISPLAY_NAME = 'displayname';\n\n public const GROUP_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [\n self::GROUP_FILTER_DISPLAY_NAME => Filters\\Group\\DisplayNameFilter::class,\n ];\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Component\\SCIM;\n\nuse Jiminny\\Component\\SCIM\\Builders\\Filters;\n\nclass Constants\n{\n /**\n * HTTP codes\n */\n public const HTTP_OK = 200;\n public const HTTP_CREATED = 201;\n public const HTTP_NO_CONTENT = 204;\n\n public const HTTP_NOT_FOUND = 404;\n public const HTTP_BAD_REQUEST = 400;\n public const HTTP_ACCESS_DENIED = 403;\n\n public const HTTP_ERROR = 501;\n\n /**\n * Users resource constants\n */\n public const USER_FIRST_NAME = 'givenName';\n public const USER_FAMILY_NAME = 'familyName';\n public const USER_STATUS = 'Active';\n public const USER_USERNAME = 'UserName';\n public const USER_EXTERNAL_ID = 'externalId';\n\n public const USER_FIELDS = [\n self::USER_FIRST_NAME,\n self::USER_FAMILY_NAME,\n self::USER_STATUS,\n self::USER_USERNAME,\n ];\n\n public const META_OPERATIONS_REPLACE = 'replace';\n public const META_OPERATIONS_REPLACE_UPPER = 'Replace';\n public const META_OPERATIONS_ADD = 'add';\n public const META_OPERATIONS_ADD_UPPER = 'Add';\n public const META_OPERATIONS_REMOVE_UPPER = 'Remove';\n public const META_OPERATIONS_REMOVE = 'remove';\n\n public const META_ID = 'id';\n public const META_PHONE_NUMBERS = 'phoneNumbers';\n public const META_TITLE = 'title';\n public const META_ROLES = 'roles';\n public const META_PATH = 'path';\n public const META_ENTERPRISE_SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';\n public const META_DEPARTMENT = 'department';\n public const META_META = 'meta';\n public const META_TYPE = 'type';\n public const META_VALUE = 'value';\n public const META_OPERATIONS = 'Operations';\n public const META_OP = 'op';\n public const META_RESOURCE_TYPE = 'resourceType';\n public const META_CREATED = 'created';\n public const META_LAST_MODIFIED = 'lastModified';\n public const META_FORMATTED = 'formatted';\n public const META_EMAILS = 'emails';\n public const META_USERNAME = 'userName';\n public const META_NAME = 'name';\n public const META_STATUS = 'active';\n public const META_PRIMARY = 'primary';\n public const META_ERROR_STATUS = 'status';\n public const META_ERROR_DETAIL = 'detail';\n public const META_LIST_TOTAL_RESULTS = 'totalResults';\n public const META_LIST_RESOURCES = 'Resources';\n public const META_LIST_START_INDEX = 'startIndex';\n public const META_LIST_COUNT = 'count';\n public const META_LIST_ITEMS_PER_PAGE = 'itemsPerPage';\n public const META_SCHEMAS = 'schemas';\n public const META_FILTER = 'filter';\n public const META_TYPE_WORK = 'work';\n public const META_PHONE_NUMBER_TYPE_MOBILE = 'mobile';\n public const META_EMAIL_TYPE_HOME = 'home';\n public const META_CONTAINER_NAME = 'name';\n public const META_CONTAINER_EMAILS = 'emails';\n\n public const RESOURCE_TYPE_USER = 'User';\n\n public const USER_PATCH_ATTR_TITLE = 'title';\n public const USER_PATCH_ATTR_ACTIVE = 'active';\n public const USER_PATCH_ATTR_USERNAME = 'userName';\n public const USER_PATCH_ATTR_FIRST_NAME = 'name.givenName';\n public const USER_PATCH_ATTR_LAST_NAME = 'name.familyName';\n public const USER_PATCH_ATTR_PRIMARY_EMAIL = 'emails[type eq \"work\"].value';\n public const USER_PATCH_ATTR_SECONDARY_EMAIL = 'emails[type eq \"home\"].value';\n public const USER_PATCH_ATTR_PHONE_NUMBER = 'phoneNumbers[type eq \"work\"].value';\n public const USER_PATCH_ATTR_PHONE_NUMBER_MOBILE = 'phoneNumbers[type eq \"mobile\"].value';\n public const USER_PATCH_ATTR_ROLES = 'roles';\n\n public const USER_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [\n self::USER_PATCH_ATTR_TITLE => Mutators\\Attributes\\User\\TitleAttr::class,\n self::USER_PATCH_ATTR_ACTIVE => Mutators\\Attributes\\User\\ActiveAttr::class,\n self::USER_PATCH_ATTR_USERNAME => Mutators\\Attributes\\User\\UsernameAttr::class,\n self::USER_PATCH_ATTR_FIRST_NAME => Mutators\\Attributes\\User\\FirstNameAttr::class,\n self::USER_PATCH_ATTR_LAST_NAME => Mutators\\Attributes\\User\\LastNameAttr::class,\n self::USER_PATCH_ATTR_PRIMARY_EMAIL => Mutators\\Attributes\\User\\PrimaryEmailAttr::class,\n self::USER_PATCH_ATTR_SECONDARY_EMAIL => Mutators\\Attributes\\User\\SecondaryEmailAttr::class,\n self::USER_PATCH_ATTR_PHONE_NUMBER => Mutators\\Attributes\\User\\PhoneNumberPrimaryAttr::class,\n self::USER_PATCH_ATTR_PHONE_NUMBER_MOBILE => Mutators\\Attributes\\User\\PhoneNumberSecondaryAttr::class,\n self::USER_PATCH_ATTR_ROLES => Mutators\\Attributes\\User\\RoleAttr::class,\n ];\n\n public const FILTER_OPERATOR_EQ = 'eq';\n\n public const SUPPORTED_FILTERS_OPERATORS = [\n self::FILTER_OPERATOR_EQ,\n ];\n\n public const USER_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [\n self::USER_FILTER_LOCAL_ID => Filters\\User\\LocalIdFilter::class,\n self::USER_FILTER_USERNAME => Filters\\User\\UserNameFilter::class,\n self::USER_FILTER_FIRST_NAME => Filters\\User\\FirstNameFilter::class,\n self::USER_FILTER_LAST_NAME => Filters\\User\\LastNameFilter::class,\n self::USER_FILTER_EXTERNAL_ID => Filters\\User\\ExternalIdFilter::class,\n self::USER_FILTER_DISPLAY_NAME => Filters\\User\\DisplayNameFilter::class,\n ];\n\n public const USER_FILTER_LOCAL_ID = 'id';\n public const USER_FILTER_USERNAME = 'userName';\n public const USER_FILTER_FIRST_NAME = 'givenName';\n public const USER_FILTER_LAST_NAME = 'familyName';\n public const USER_FILTER_EXTERNAL_ID = 'externalId';\n public const USER_FILTER_DISPLAY_NAME = 'DisplayName';\n\n public const SCIM_SUPPORTED_RESOURCES = [\n self::USER_RESOURCE_PREFIX,\n self::GROUP_RESOURCE_PREFIX,\n ];\n\n public const USER_RESOURCE_PREFIX = 'Users';\n public const GROUP_RESOURCE_PREFIX = 'Groups';\n\n public const OUTGOING_SCHEMAS_SUPPORTED = [\n self::OUTGOING_CORE_USER,\n\n ];\n\n /**\n * Outgoing supported schemas\n */\n public const OUTGOING_CORE_USER = 'urn:ietf:params:scim:schemas:core:2.0:User';\n public const OUTGOING_ERROR = 'urn:ietf:params:scim:api:messages:2.0:Error';\n public const OUTGOING_LIST_RESPONSE = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';\n\n public const OUTGOING_CORE_GROUP = 'urn:ietf:params:scim:schemas:core:2.0:Group';\n\n /**\n * Groups resource constants\n */\n public const GROUP_ATTRIBUTE_DISPLAY_NAME = 'displayName';\n public const GROUP_ATTRIBUTE_EXTERNAL_ID = 'externalId';\n public const GROUP_ATTRIBUTE_ID = 'id';\n public const RESOURCE_TYPE_GROUP = 'Group';\n public const GROUP_FILTER_QUERY_NAME = 'filter';\n public const GROUP_EXCLUDED_ATTRIBUTES = 'excludedAttributes';\n\n public const GROUP_SUPPORTED_FILTER_ATTRIBUTES = [\n self::GROUP_ATTRIBUTE_DISPLAY_NAME,\n ];\n\n public const GROUP_MEMBERS = 'members';\n\n public const SUPPORTED_PATCH_OPERATIONS = [\n self::META_OPERATIONS_ADD,\n self::META_OPERATIONS_REPLACE,\n self::META_OPERATIONS_REMOVE,\n ];\n\n public const GROUP_PATCH_ATTRIBUTE_MEMBERS = 'members';\n public const GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME = 'displayName';\n\n public const GROUP_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [\n self::GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME => Mutators\\Attributes\\Group\\DisplayNameAttr::class,\n self::GROUP_PATCH_ATTRIBUTE_MEMBERS => Mutators\\Attributes\\Group\\MembersAttr::class,\n ];\n\n public const GROUP_FILTER_DISPLAY_NAME = 'displayname';\n\n public const GROUP_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [\n self::GROUP_FILTER_DISPLAY_NAME => Filters\\Group\\DisplayNameFilter::class,\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_jupiter","depth":4,"bounds":{"left":0.69348407,"top":0.09896249,"width":0.04089096,"height":0.01915403},"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":"19","depth":4,"bounds":{"left":0.6871675,"top":0.123703115,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"19","depth":4,"bounds":{"left":0.6988032,"top":0.123703115,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":4,"bounds":{"left":0.71043885,"top":0.123703115,"width":0.00930851,"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 * FROM teams WHERE id = 1;\n\nselect * from crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 283;\nSELECT * FROM crm_fields WHERE id = 2234;\nSELECT * FROM crm_field_values WHERE crm_field_id = 2234;\n\nselect * from crm_profiles where user_id = 143;\n\nselect * from record_types where crm_configuration_id = 39; # 0121K000001MHElQAO,0121K000001MHEqQAO\nselect * from business_processes where crm_configuration_id = 39;\n# 01941000000H669AAC, 01941000000H66JAAS\n\nselect * from record_type_field_values\n where record_type_id IN (24);\n\nselect * from crm_field_values where id IN (2730);\n\nselect * from crm_configurations where id = 39;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce'; #1035\n\n\nselect * from users where team_id = 1; # 222 group 3\nSELECT * FROM activities WHERE user_id = 222 order by id desc;\nselect * from sidekick_settings where team_id = 1;\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\n\nselect * from activities where crm_configuration_id = 2\nand provider = 'ms-teams' and id = 608765;\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id = '59523413338';\n\nselect * from sidekick_settings where team_id = 2;\n\nSELECT * FROM activities WHERE id = 608660;\nselect * from activity_summary_logs where activity_id = 608660;\nselect * from ai_prompts where transcription_id = 11214;\n\n# ********************************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('ed78a437-2804-450e-ab2f-56ab1c641346') = uuid;\n# id: 608818, crm: 59628809737\nSELECT * FROM activities WHERE uuid_to_bin('36b06e55-afdd-4782-8dee-c624cd0af191') = uuid;\n# id: 608821, crm: 59632069252\nSELECT ce.start_time, ce.end_time, a.id, a.uuid, crm_provider_id, calendar_event_id, title,\nplaybook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id,\nscheduled_start_time, scheduled_end_time, actual_start_time, actual_end_time, a.created_at\nFROM activities a\njoin calendar_events ce on a.calendar_event_id = ce.id\nWHERE a.id IN (608818, 608821);\n\nselect * from users where team_id = 1;\nselect * from team_settings where team_id = 1;\nselect * from crm_profiles where crm_configuration_id = 39 order by user_id;\n\nselect * from team_features where team_id = 1;\n\nselect * from users where team_id = 2;\n\nSELECT * FROM activities WHERE uuid_to_bin('ec7647e9-5225-458b-b475-f31aa2769204') = uuid; # 612639\n# Preslava N. Ivanova, grou id 3\n\nSELECT * FROM opportunities WHERE uuid_to_bin('a2928fe5-aec5-46cb-85d9-7654c89e46a6') = uuid;\n\nselect * from activities where opportunity_id = 344 and actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00';\n\nselect\n a.id,\n a.type,\n a.scheduled_start_time,\n a.actual_start_time,\n a.created_at,\n a.opportunity_id,\n a.status\nFROM activities a\nWHERE opportunity_id = 344\nand status IN ('completed', 'received', 'delivered')\nand (\n (a.actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')\nOR (a.created_at between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')\nOR (a.scheduled_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00'))\n;\n\nSELECT * FROM users WHERE id = 222;\n\nSELECT * FROM crm_profiles WHERE user_id = 222;\nselect * from crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 281;\n\nselect * from group_deal_risk_types;\n\nselect * from opportunities where team_id = 1;\n\nSELECT * FROM opportunities WHERE id = 315;\nSELECT * FROM crm_field_data WHERE object_id = 315;\nselect * from crm_field_data where object_id = 260;\n\nselect * from generic_ai_prompts where subject_id = 315;\n\nselect * from teams; # 36, 21, 121, james.graham@bullhorn.jiminny.com\nSELECT * FROM social_accounts WHERE sociable_id = 121 and provider = 'bullhorn';\n\n# ************************************************************************************\nselect * from teams where id = 1;\nselect * from crm_configurations where id = 39;\nselect * from users where team_id = 1;\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 1;\n# 1 - 00541000004281rAAA\n# 204 - 0052g000003freeAAA\n# 429 - 0052g000003qGOiAAM\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce';\n\nselect * from activities where type = 'softphone'\nand created_at > '2024-12-11 15:24:36' order by id desc;\n\nselect * from activity_providers where team_id = 1;\nselect * from activity_provider_users where activity_provider_id = 328;\n\nselect * from opportunities where crm_configuration_id = 39\nAND account_id = 178 AND is_closed = false\norder by created_at DESC;\n\nselect * from contacts where id = 3952;\nselect * from accounts where id = 178;\n\n# ************************************************************************************\nselect * from teams where id = 36;\nselect * from crm_configurations where id = 21;\nselect * from users where team_id = 36;\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 36;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 36\nand sa.provider = 'bullhorn';\n\nselect * from social_accounts where id = 348;\nUPDATE social_accounts SET\nprovider_user_token = '21442_6802599_91:41179a58-21e7-4d7c-ad58-56bb666b2f65',\nprovider_refresh_token = '21442_6802599_91:01c6b335-3f2a-42e4-85ff-8a08fa65fceb',\nexpires = 1733998131,\nstate = 'connected'\nWHERE id = 348;\n\n# ************************************************************************************\nselect * from teams where id = 31;\nselect * from crm_configurations where id = 18;\n\nselect * from users where team_id = 31; # 257\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 31;\n\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 31\nand sa.provider = 'close';\n\nselect * from contacts where crm_configuration_id = 18;\n\n# ********************** NEPTUNE **************************************************************\nselect * from teams;\nselect * from users where id IN (1030, 1035, 1052);\nselect * from crm_configurations;\n\nselect * from users where team_id = 65; # 257\nselect * from team_settings where team_id = 65; # 257\nselect * from invitations where team_id = 65; # 257\nselect * from users where email = 'integration-account@jiminny.com'; # 257\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 65;\n\nselect * from crm_configurations where id = 53;\nselect * from accounts where crm_configuration_id = 53 order by id desc;\nselect * from leads where crm_configuration_id = 53 order by id desc;\nselect * from contacts where crm_configuration_id = 53 order by id desc;\nselect * from opportunities where crm_configuration_id = 53 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 53 order by id desc;\nselect * from crm_fields where crm_configuration_id = 53 order by id desc;\nselect * from crm_field_values where crm_field_id = 3341 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 53 order by id desc;\nselect * from stages where crm_configuration_id = 53 order by id desc;\n\n\nselect * from crm_profiles where crm_configuration_id = 13;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 65\nand sa.provider = 'integration-app';\n\nselect * from contacts where crm_configuration_id = 13;\n\nselect * from social_accounts where sociable_id = 283;\n\nSELECT * FROM opportunities WHERE crm_provider_id = '006O400000E9bzeIAB';\n\nselect * from activity_providers where team_id = 65;\nSELECT * FROM activities WHERE crm_configuration_id IN (51, 52, 53);\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 65\n;\n\n# ***************************** STAGING ********************************************\nSELECT * FROM teams;\nSELECT * FROM teams WHERE id = 88;\nSELECT * FROM teams WHERE id = 89;\nselect * from team_settings where team_id = 89;\nSELECT * FROM users WHERE team_id = 89;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 89;\n\nselect * from users;\nSELECT * FROM social_accounts WHERE sociable_id = 1761;\nSELECT * FROM crm_configurations WHERE id = 70;\nselect * from accounts where crm_configuration_id = 70 order by id desc;\nselect * from leads where crm_configuration_id = 70 order by id desc;\nselect * from contacts where crm_configuration_id = 70 order by id desc;\nselect * from opportunities where crm_configuration_id = 70 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 70 order by id desc;\nselect * from crm_fields where crm_configuration_id = 70 order by id desc;\nselect * from crm_field_values where crm_field_id = 3536 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 70 order by id desc;\nselect * from stages where crm_configuration_id = 70 order by id desc;\nselect * from business_processes where crm_configuration_id = 70 order by id desc;\nselect * from business_process_stages where business_process_id = 34;\n\nselect * from contacts where id = 10468;\n\nselect * from crm_layouts where crm_configuration_id = 70;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 388;\nSELECT * FROM crm_fields WHERE id IN (3533,3534,3535);\n\nselect * from activities where crm_configuration_id = 70\nand (account_id IS NOT NULL or lead_id IS NOT NULL or contact_id IS NOT NULL or opportunity_id IS NOT NULL) order by id desc;\n\nSELECT * FROM activities WHERE uuid_to_bin('2e10b60f-8a61-41c5-a3d4-28835353dc65') = uuid;\nSELECT * FROM activities where crm_configuration_id = 69 ;\n\nSELECT * FROM users WHERE email LIKE '%jiminny_web_sa2@jiminny.com%';\nSELECT * FROM activities WHERE uuid_to_bin('5a150c93-40fc-42ec-b3bd-c1d328e09f6e') = uuid;\nSELECT * FROM opportunities WHERE id = 385;\n\nselect * from participants p\njoin activities a on p.activity_id = a.id\nwhere a.crm_configuration_id = 70\nand (p.lead_id IS NOT NULL or p.contact_id IS NOT NULL);\nSELECT * FROM participants WHERE id = 1013638;\n\nselect * from teams where id = 90;\nselect * from users where team_id = 90;\nselect * from social_accounts where social_accounts.sociable_id IN (1960,1760);\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 71;\nselect * from invitations where team_id = 90;\n\nselect * from crm_configurations where id = 71;\nselect * from accounts where crm_configuration_id = 71 order by id desc;\nselect * from leads where crm_configuration_id = 71 order by id desc;\nselect * from contacts where crm_configuration_id = 71 order by id desc;\nselect * from opportunities where crm_configuration_id = 71 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 71 order by id desc;\nselect * from crm_fields where crm_configuration_id = 71 order by id desc;\nselect * from crm_field_values where crm_field_id = 3341 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 71 order by id desc;\nselect * from stages where crm_configuration_id = 71 order by id desc;\n\nselect * from users order by secondary_email desc;\nselect u.id, u.email, u.status, sa.id, sa.provider_user_id from social_accounts sa\n join users u on sa.sociable_id = u.id\nwhere sa.provider = 'google' and u.email LIKE 'aneliya%';\n\nselect * from failed_jobs order by id desc;\n\nselect * from users where email = 'ben.allwright@learningpeople.co.uk' or secondary_email = 'ben.allwright@learningpeople.co.uk';\n\nselect * from teams;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 39;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type = 'task';\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce';\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('c38b3895-fd0f-4b1f-9fb2-c170dba137c6') = uuid;\nSELECT * FROM crm_configurations WHERE id = 70;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1;\nselect * from users where team_id = 1;\n\nselect o.id, o.name,o.close_date, u.id, u.name, u.group_id, r.id, r.display_name, g.name, g.scope from opportunities o\njoin users u on o.user_id = u.id\njoin groups g on u.group_id = g.id\njoin role_user ru on u.id = ru.user_id\njoin roles r on ru.role_id = r.id\nwhere o.crm_configuration_id = 39 and close_date > '2024-01-01 00:00:00';\n\nselect * from role_user where user_id = 143;\nselect * from roles;\n\nselect * from role_user;\nselect * from groups where id = 9;\nselect * from scope_groups where group_id = 9;\n\n# ************************************************************************************\nselect * from teams where id = 36;\nselect * from crm_configurations;\nSELECT * FROM social_accounts WHERE sociable_id = 121;\n\nhttps://crmsandbox.zoho.com/crm/jiminnyw4/tab/Leads/4776201000005049105\nhttps://crmsandbox.zoho.com/crm/\n\nhttps://crm.zoho.com/crm/org3469620/tab/Leads/230045000229559080\n https://crm.zoho.com/crm/\n org3469620\n\nSELECT * FROM activities WHERE uuid_to_bin('03382d20-c8bc-48e7-a3d4-90b52fa5ceab') = uuid;\n\nselect * from users where email LIKE \"%mobile_automation_%\";\nselect * from social_accounts where sociable_id IN (2228);\nselect * from crm_profiles where user_id IN (2222,2223,2226,2227);\n\nselect * from teams order by id desc;\nSELECT * FROM users WHERE id = 2229;\nSELECT * FROM crm_profiles WHERE user_id = 2229;\nselect * from opportunities where crm_configuration_id = 88;\nselect * from crm_fields where crm_configuration_id = 88;\nselect * from crm_profiles where crm_configuration_id = 88;\n\nSELECT * FROM teams WHERE id = 1;\n\nSELECT * FROM users WHERE id = 143;\nSELECT * FROM users WHERE uuid_to_bin('fde193d3-06a2-4e1a-8895-62b94039215d') = uuid;\nSELECT * FROM teams WHERE uuid_to_bin('73385071-a756-42ae-9c73-8b53f2309467') = uuid;\n\nhttps://app.staging.jiminny.com/ondemand?\n min_duration=1\n &\n only_recorded=1\n &\n user_id%5B%5D=641f1acb-16b8-42d1-8726-df52979dad0e\n &\n sequence_number=2\n\n select * from users where team_id = 1 and email like '%stoyan%'\n\nselect * from coaching_feedbacks;\n\nselect * from teams;\nSELECT * FROM users WHERE team_id = 36;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 19\nand sa.provider = 'pipedrive';\n\nselect * from users where id = 143;\n\nSELECT * FROM users WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\nSELECT * FROM teams WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\nSELECT * FROM activity_shares WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\n\nselect * from users where team_id = 2;\nselect * from activities where crm_configuration_id = 39\nand activities.scheduled_start_time BETWEEN '2025-04-09 00:00:00' AND '2025-04-09 23:59:59'\nAND user_id = 143\norder by id desc;\n\n# ************************************************************************************\nselect * from teams where id = 142; # 2312, 126\nselect * from team_settings;\nselect * from users where team_id = 142; # 21642\nSELECT * FROM social_accounts WHERE sociable_id = 21642;\nSELECT * FROM crm_profiles cp join users u ON u.id = cp.user_id WHERE team_id = 142;\nselect * from crm_profiles where id IN (93);\nselect * from invitations;\nselect * from team_features where team_id = 1;\n\nSELECT * FROM crm_configurations WHERE id = 126;\nselect * from accounts where crm_configuration_id = 126 order by id desc;\nselect * from leads where crm_configuration_id = 126 order by id desc;\nselect * from contacts where crm_configuration_id = 126 order by id desc;\nselect * from opportunities where crm_configuration_id = 126 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 126 order by id desc;\nselect * from crm_fields where crm_configuration_id = 126 # 11060\n# and type IN ('picklist', 'status')\n# and object_type = 'task'\norder by id desc;\n# 5731,5732,5733\nselect DISTINCT crm_field_id from crm_field_values where crm_field_id IN (11151,12239,12215,12185,12175,12165,12144,12137,12127,12109,12107,12105,12103,12092,12037,12005,12003,11987,11969,11958,11951,11942,11931,11924,11921,11917,11915,11901,11893,11883,11872,11870,11868,11866,11839,11833,11821,11793,11780,11777,11769,11757,11737,11735,11656,11645,11638,11629,11618,11611,11602,11591,11584,11581,11558,11544,11543,11534,11532,11529,11527,11503,11497,11493,11488,11470,11468,11457,11455,11397,11387,11372,11363,11348,11323,11318,11309,11301,11300,11292,11290,11286,11284,11256,11252,11242,11237,11233,11219,11176,11160) order by id desc;\nselect * from crm_layouts where crm_configuration_id = 126 order by id desc;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id in (300,299,298);\nselect * from stages where crm_configuration_id = 126 order by id desc;\nselect * from business_processes where crm_configuration_id = 126 order by id desc;\nselect * from business_process_stages where business_process_id IN (76,75,74,73);\nselect * from playbooks where team_id = 142;\nselect * from playbook_layouts where playbook_id IN (108);\nSELECT * FROM playbook_categories WHERE playbook_id IN (108);\n\nselect * from teams where id = 130;\nSELECT * FROM social_accounts WHERE sociable_id = 2291;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 2\nand sa.provider = 'hubspot';\n\nSELECT * FROM activities\n WHERE crm_configuration_id = 110;\n\nselect * from teams;\nselect * from crm_configurations;\n\nSELECT * FROM activities WHERE id = 628773;\nSELECT * FROM crm_profiles WHERE user_id = 1460;\nSELECT * FROM social_accounts WHERE sociable_id = 2291;\n\nselect * from teams;\nselect ru.*, pr.*, p.* from users u join role_user ru on ru.user_id = u.id\njoin permission_role pr on pr.role_id = ru.role_id\n join permissions p on p.id = pr.permission_id\nwhere team_id = 495 and p.name IN ('dial');\n\nselect * from teams where id = 145;\nselect * from crm_configurations where id = 129;\nselect * from social_accounts where sociable_id = 2317;\nSELECT * FROM activities WHERE uuid_to_bin('8dbab184-a333-4268-ad57-fb41f8d53a9a') = uuid;\n\nselect * from teams where id = 1;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 280;\nSELECT * FROM crm_layout_entities WHERE id = 5507;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type IN ('event');\n\nselect * from teams;\nselect * from activities where crm_configuration_id = 14;\n\nSELECT * FROM social_accounts where provider = 'copper';\n\nselect * from activities where id = 628467;\nselect * from participants where activity_id = 628467;\n\nSELECT * FROM contacts WHERE id = 3969;\nSELECT * FROM accounts WHERE id = 177;\n\nSELECT * FROM activities WHERE uuid_to_bin('4eb54c77-cfa3-2bd4-84a7-9ed46a21c988') = uuid;\n\n# ********************* BH\nselect * from teams where id = 36;\nSELECT * FROM crm_configurations WHERE id = 21;\nselect * from activities where crm_configuration_id = 21 and id = 607901;\nselect * from activities where crm_configuration_id = 21;\n\nselect * roles;\nselect * from permissions;\nselect * from permission_role where permission_id = 226;\n\nselect * from migrations order by id desc;\n\n# mercury\n# neptune\n# earth\n\nselect * from teams;\nselect * from teams where id = 19;\nselect * from teams where id = 27;\nselect * from users where team_id = 27;\nSELECT * FROM crm_configurations WHERE id = 42;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 19\nand sa.provider = 'pipedrive';\n\nselect * from activities where id = 631461;\nSELECT * FROM crm_field_values WHERE crm_field_id = 180;\n\nselect * from teams where id = 2;\nSELECT * FROM social_accounts WHERE sociable_id = 89;\n\nSELECT * FROM activities WHERE uuid_to_bin('ba0c029a-bc14-4e17-8603-64174acebcbb') = uuid; # 634273\nselect * from activity_summary_logs where activity_id = 634273;\n\nselect * from sidekick_settings where team_id = 2;\n\nselect * from teams; # 2, 2\nSELECT * FROM crm_configurations WHERE team_id = 2; # 2\nselect * from team_features where team_id = 2;\nselect * from features;\nSELECT * FROM opportunities WHERE crm_configuration_id = 2 and crm_provider_id = '51317301383';\nSELECT * FROM opportunities WHERE crm_configuration_id = 2 order by id desc;\n\nselect * from automated_reports order by id desc;\nselect * from automated_report_results order by id desc;\nselect * from users where team_id = 1 and id IN (7160, 3248);\nselect * from migrations order by id desc;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1052 and sa.provider = 'hubspot';\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 = 565;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 175;\nselect * from playbook_categories where playbook_id = 175;\nselect * from users where team_id = 1052;\nselect * from users where id = 7160;\nselect * from crm_profiles where user_id = 7160;\nselect * from features;\nselect\n *\n# id, uuid, type, provider, playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id, stage_id,\n# crm_configuration_id, crm_provider_id, transcription_id, status\nfrom activities where crm_configuration_id = 1 and type = 'conference'\n# and crm_provider_id IS NOT NULL\nand provider != 'uploader' and actual_start_time IS NOT NULL\nORDER by id desc;\nselect * from activities where id = 54747783; # 00UO400000pCzojMAC\n\nselect p.id, p.activity_type, pc.id, pc.name\nFROM playbooks p\njoin playbook_categories pc on p.id = pc.playbook_id\nwhere p.team_id = 1 and p.activity_type = 'event';\n\nSELECT * FROM crm_fields WHERE crm_configuration_id = 1 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id = 4;\n\nselect * from crm_layouts cl join playbook_layouts pl on cl.id = pl.layout_id\nwhere crm_configuration_id = 1 and pl.playbook_id = 175;\n\nselect * from teams;\nSELECT r.* FROM automated_reports r\njoin teams t on r.team_id = t.id\nWHERE r.frequency = 'daily'\n and r.status = 1\nAND t.status = 'active'\nAND (r.expires_at >= now() OR r.expires_at IS NULL);\n\nselect * from automated_report_results where report_id IN (18, 33);\n\nselect * from users where team_id = 1 and id = 1047;\nSELECT * FROM social_accounts WHERE sociable_id = 1047;\n\nselect * from activity_searches where id = 10932;\nselect * from activity_search_filters where activity_search_id = 10932;\nselect * from automated_reports order by id desc;\nselect * from automated_report_results order by id desc;\nselect * from automated_reports where id IN (55);\nselect * from automated_report_results where id IN (81);\nselect * from users where id IN (10633, 13987, 11985);\nselect * from users where group_id IN (3710);\n\nSELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;\nSELECT * FROM automated_report_results WHERE uuid_to_bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;\n\nselect * from teams;\nselect * from accounts where team_id = 1;\n\nselect * from automated_report_results where media_type = 'pdf' and status = 2;\nSELECT * FROM automated_report_results WHERE uuid_to_bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid;\n\nselect * from teams where id = 1029;\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 = 1029 and sa.provider = 'pipedrive';\n\n[\n {\n \"user_id\": \"23460 (owner)\",\n \"email\": \"integration-account@pipedrive.jiminny.com\",\n \"id\": 69,\n \"sociable_id\": 23460,\n \"provider_user_id\": \"19555731\",\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,\n \"refresh_token_expires\": null,\n \"provider\": \"pipedrive\",\n \"state\": \"connected\",\n \"auth_scope\": \"base,deals:full,activities:full,contacts:full,search:read\",\n \"retry_after\": null,\n \"created_at\": \"2025-04-16 08:23:28\",\n \"updated_at\": \"2026-05-18 07:13:18\",\n \"provider_user_token_encrypted\": \"eyJpdiI6Ik9oYzBwcTVteWN4ajBRaDdMb0FjWGc9PSIsInZhbHVlIjoiQUNMbjU5UHR2Q1RnbWRXMEU1TUx6UVpRU3gzdVc5WktmTE4rVlhXa3lRaGhyUUlZMVZRWEJuR0JaWWhZZXNPRlBuanhuYU5MVHZ5TG9NTVVjNjJSUUpZZ2VhbGYxbHg0UzJEdTVmQjNFZnJRZkMwYjd0N2RMZ05GRS9IR3c2K0NoVjBjYTA5UG12SkxHeDlDMGVNN3ptUWUzblFiTngyYzR1eUpHSEYrdEwvZm0yZklGYjBSNEtTR2ZGazhLM1hqT3lVbjFobDNPZ0d3anFlcjhKcXpERlZGOVN1YmFyNDIvM1BFRDFMYnp4WEI4TGVLM2xYcy9CL0RDOWlQNHI3N0NwWnJPMWRtZllmM2ZKeE9TV2NBeDZxL2M1YnlSVzd3ZW96T3F1QmtBYXBHYkUraGcvdCtRajlYZXBjVVBSdFlMUjVPVDVJbDdyenVoWjMrbVJvU3ZZR1dQZ3pqQ3F3aDF2U2xPZWZIN3BCWVFLNXpxQUtDb2pIK0xHc1E3SklSM3Q0VkNSbm9oK2pFK3hLaW54T1dWbEVneUp0RGhhdVBuOFI4MXROc3dZWnFnTUpiaDVMMnZ4QmlRM3k4QWFlMVFWUFYvdGhJQzZBYnhBQmhWa2ZKN1ZhSnhpaExxbmlTemgzUWw3aXJtWjlSMlhmd0lWMDNDN1N3My9Ua0hCL2xqY3RkVFhMSjFJMDRjOE5DWlgrZ3FMVXN6RWlwUE5GWERZdG1xVjVxOFlLRGs2VVJKS3FLeWRxQjYxdDh4Z2JJNXhlWEZ3dkQ4SGtybDNUcndzblFHeVJNRkYraFh2UDFIUTdMQ1BZa3dEU1dBbzk5K0dyT2RNVFBZZUJpRytSck5pYlI1YUZyMmhUNEZCdWxHYmJLREtzbUpjVkhvV0RoejJpbm1SWHlNaXE5M0RhcS94UW9EdFoweWF3bVFVY0dTZWFPSXBmOCtDYndia215cmtyZU1oT0Exam1CV2tPblNhYjY4clVEeUs3anVHUmNHeS9YLzRha1VhbGl3N3lwaDlzZnRhQUZta2s4eFllNHgzRklSRmNyazJ4dlBDMnByNCtBRjNaVjJCTT0iLCJtYWMiOiJkYTQxZDY1OTY2ZTljMTgyZWRhNGEzMGZjZDc2MjBjN2NlNzU2YTViNGQxNWE1NTI2ZmI1MWQyYjQ2ODYxZmEwIiwidGFnIjoiIn0=\",\n \"provider_refresh_token_encrypted\": \"eyJpdiI6Imt2bGxlSmxUK05GMjF0dEtPaTMrUlE9PSIsInZhbHVlIjoiUXZHTElZRXkreHFxUU02SnZ4eVBacG9WWTRlVkd0USszV3JyVFlpU2ZaY25GSWo2WFcrRzNlbFRlUXRQczNwSXRCcEdvZEpveG9jMzBDSTgwdnZLQnc9PSIsIm1hYyI6ImQxYWI0NzU5Nzg5MDI4YWVhZmQ4Mjg1YzhkZDQzMjRkYWYwYTdhZTY5MDMxMjc0OWNiYjY0Nzc3NDQ0MTEyY2EiLCJ0YWciOiIifQ==\",\n \"encryption_key\": \"0x01020300786192D9D96DD60D3D1EBC9DFAEE5F0C45EE80165CF3F3D2B3B627026AA7CFC7CA0128DD463535D32EE491ADBADF8B07596B0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040C7FB1319048ECB2EA3F23B995020110802B52D22F5EAD341AB238FBBCB6093156E443876A664BA5555D722565C2B2D04422C868CD7350555E3CC74221\",\n \"sociable_type\": \"user\",\n \"owner_id\": 23460\n },\n {\n \"user_id\": \"23463\",\n \"email\": \"jiminny_web_sa@pipedrive.jiminny.com\",\n \"id\": 72,\n \"sociable_id\": 23463,\n \"provider_user_id\": \"23270841\",\n \"provider_user_token\": \"v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:txqCuWLeVhgwiaFqXIvQWWrtrnFIy_4lT3VCr-sRB4g6_2lK8KcQ_6ka_qFmZhr-IeIAKmAImx6H1iIKx4Ab7XZ5MnKIh03GKbHjI0n0rGT9UYkeH21jKOxJvKaSX_TyLbxFPR6irPQyvqcpBClXI52gVJH01KzZy_dMTHFXhhDLOIhEpSrQXHG7Qo8q7OuBeSPZrU1ALi9kmAm4GTpzGTbzfl-hUt9IAfPunJOCyv3mf2Tl-MT8EyQgOFPrsP3yz9UlSyVhb40zO_bCnUrqNxjwgm_E6vgpVrwULTQbHe-43Dq-TRetjceUzT88GBgVJ0UdxXP5BRBVXcL5ir8-9ZTMaNU\",\n \"provider_refresh_token\": \"5034113:23270841:34790b44838f5fd422c2d2c82e00f1ecf2178ad1\",\n \"expires\": 1753837219,\n \"refresh_token_expires\": null,\n \"provider\": \"pipedrive\",\n \"state\": \"full-refresh\",\n \"auth_scope\": \"base,deals:full,activities:full,contacts:full,search:read\",\n \"retry_after\": null,\n \"created_at\": \"2025-04-16 10:41:12\",\n \"updated_at\": \"2025-07-30 01:00:17\",\n \"provider_user_token_encrypted\": \"eyJpdiI6InVEVEl2SzIxMjd1bkNDWG9lY3YvQ0E9PSIsInZhbHVlIjoiRlJLbDZ3ZHo2dHMxUWQwdGU2YUZjV3lPWHlxQTJ0eWh4S0RTMjlSaThVcktoaWhXcTd2UXl4Mjg4bW5UUnZCZEQ5NXpuQTVKOURiMDNIa3l3K0lSWCt5azRBOEdHbitWQXhxeEpMVUZ1dnF2NVl1TTZLelZOaGNvRlBLeGpIWlpoRGloUEprd2xoNUFPcTlLcUd3WVlUU2svR1NOeXBYQ2NnMWhnK1V2aytOeVVMNzJGdVZXMU1JS3BSaGNCcmxkVjEwQ01mQXNBdWNhS1lMZWZobnZwcHBkN1R4bUVDRUNYdnNtSVJkdG5MdkN3djJBT0hMRDl1MHFGbnl4WU13ejBkUWsrdUljWkZhcTJlN0JDSGdTVzlPY0FGMUJlZi9WRGpkMUk5R20wblYwSk9VR2FuaHpLTzJNeitMbnF1V1NEMUUxRmYzaDRGZDMyaXd3Z0FjQno4SzVoYjUyTmV3UXNpRlF4TGZKNVl3dUFqdGhKVWJjRVlUUXRGalBpaXJvSGJmbS8rd25aQ2Zvc05saHRDRjlHV1VEUFFiRU5xbWRVNkxFSXV0RUZyaUlYNWMwMmhnZ0Y1VUQ4eEFkY2QyWXpnR0NidkVJSWdjVGljUjA3NDdpZW9WUHhtSlpGSGdNU2hRUTA5ZW03RGpiRFdrdytkOHJXSUxlazZNaG9iaUg2NFZYdEc3YklMeFZvblBzWmVRSDcvN2M4WUNtL3h4S2IrUW00cXhialBia3BJcW5XallBNlV5WWdhcE1ZVFBBM3RSSUVBamYvOGZEQWM5a2FJMGwyWkRSU3dlTEtPemZlQ3RXRGNDcEdYRHdMNTlTQVg2SUdUN0hVaXdZT1dUOUlrVzkrZHFBemhwWXg1cm4rSy9UOHUzcnNSM2dISlhBRTEyVUNyTkZYaFJYUlN1a2RKVHhhM2dHckR3a1JGaVZ2Wk9BVnhTclVpSEhwWTVpQTlJbXVkOUxSTGpRbDk0a1VtbE9QMVAvN3VlVEhJUHd2elowd0laNVIzZ3M3N0ZOK0NDakIwQ2FicGxoMDBhTXI0VUppUmFOZHdlWUdGV21NNFQ4RU1nY0dnWT0iLCJtYWMiOiI0ZTU4ZmJkNTdkYmY0NGE4NTJjZjlhNDExNzE2YjhlOWM2NTA5OGY2MDA4OTcyZDVlOTljY2JjZDhmMjBhMDUyIiwidGFnIjoiIn0=\",\n \"provider_refresh_token_encrypted\": \"eyJpdiI6IkJGMkdRVHRKM2VTcitKNGcvQWJtUGc9PSIsInZhbHVlIjoicmFyRkxPZ1Rybm1ORXlEVjJ2TXFGTzJtM3hWaFhnUVVHN2ZlR1lRM0I5d3ozbnZTcU5EdzJqRkI2elhyNWhlenRTUXV3bjk0N1JXeklDMVAyUzBKcHc9PSIsIm1hYyI6ImJhODVjMGQyZDE3Y2ExNjc2OWVjYWJiNmFjYWVkODIyMTMyNWVhYTExMTgwYTEyMTU0MzUzZGE1YjQ5YzQ5ZjEiLCJ0YWciOiIifQ==\",\n \"encryption_key\": \"0x01020300788C37CDF66ABE9301A68D5D4866AC0C197E04EEE4D904F20A59991322EBAE252301BEF4B24FF01359E934E5654617E4EEAC0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040CEB00EF45BDEA999A5558889E020110802B925F372F7BEFAF0B45E48686113D1DA430ECFCC07B1F61BA6828CC44235278EDB05C486E8068D0BE737D91\",\n \"sociable_type\": \"user\",\n \"owner_id\": 23460\n }\n]","depth":4,"on_screen":true,"value":"SELECT * FROM teams WHERE id = 1;\n\nselect * from crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 283;\nSELECT * FROM crm_fields WHERE id = 2234;\nSELECT * FROM crm_field_values WHERE crm_field_id = 2234;\n\nselect * from crm_profiles where user_id = 143;\n\nselect * from record_types where crm_configuration_id = 39; # 0121K000001MHElQAO,0121K000001MHEqQAO\nselect * from business_processes where crm_configuration_id = 39;\n# 01941000000H669AAC, 01941000000H66JAAS\n\nselect * from record_type_field_values\n where record_type_id IN (24);\n\nselect * from crm_field_values where id IN (2730);\n\nselect * from crm_configurations where id = 39;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce'; #1035\n\n\nselect * from users where team_id = 1; # 222 group 3\nSELECT * FROM activities WHERE user_id = 222 order by id desc;\nselect * from sidekick_settings where team_id = 1;\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\n\nselect * from activities where crm_configuration_id = 2\nand provider = 'ms-teams' and id = 608765;\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id = '59523413338';\n\nselect * from sidekick_settings where team_id = 2;\n\nSELECT * FROM activities WHERE id = 608660;\nselect * from activity_summary_logs where activity_id = 608660;\nselect * from ai_prompts where transcription_id = 11214;\n\n# ********************************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('ed78a437-2804-450e-ab2f-56ab1c641346') = uuid;\n# id: 608818, crm: 59628809737\nSELECT * FROM activities WHERE uuid_to_bin('36b06e55-afdd-4782-8dee-c624cd0af191') = uuid;\n# id: 608821, crm: 59632069252\nSELECT ce.start_time, ce.end_time, a.id, a.uuid, crm_provider_id, calendar_event_id, title,\nplaybook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id,\nscheduled_start_time, scheduled_end_time, actual_start_time, actual_end_time, a.created_at\nFROM activities a\njoin calendar_events ce on a.calendar_event_id = ce.id\nWHERE a.id IN (608818, 608821);\n\nselect * from users where team_id = 1;\nselect * from team_settings where team_id = 1;\nselect * from crm_profiles where crm_configuration_id = 39 order by user_id;\n\nselect * from team_features where team_id = 1;\n\nselect * from users where team_id = 2;\n\nSELECT * FROM activities WHERE uuid_to_bin('ec7647e9-5225-458b-b475-f31aa2769204') = uuid; # 612639\n# Preslava N. Ivanova, grou id 3\n\nSELECT * FROM opportunities WHERE uuid_to_bin('a2928fe5-aec5-46cb-85d9-7654c89e46a6') = uuid;\n\nselect * from activities where opportunity_id = 344 and actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00';\n\nselect\n a.id,\n a.type,\n a.scheduled_start_time,\n a.actual_start_time,\n a.created_at,\n a.opportunity_id,\n a.status\nFROM activities a\nWHERE opportunity_id = 344\nand status IN ('completed', 'received', 'delivered')\nand (\n (a.actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')\nOR (a.created_at between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')\nOR (a.scheduled_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00'))\n;\n\nSELECT * FROM users WHERE id = 222;\n\nSELECT * FROM crm_profiles WHERE user_id = 222;\nselect * from crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 281;\n\nselect * from group_deal_risk_types;\n\nselect * from opportunities where team_id = 1;\n\nSELECT * FROM opportunities WHERE id = 315;\nSELECT * FROM crm_field_data WHERE object_id = 315;\nselect * from crm_field_data where object_id = 260;\n\nselect * from generic_ai_prompts where subject_id = 315;\n\nselect * from teams; # 36, 21, 121, james.graham@bullhorn.jiminny.com\nSELECT * FROM social_accounts WHERE sociable_id = 121 and provider = 'bullhorn';\n\n# ************************************************************************************\nselect * from teams where id = 1;\nselect * from crm_configurations where id = 39;\nselect * from users where team_id = 1;\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 1;\n# 1 - 00541000004281rAAA\n# 204 - 0052g000003freeAAA\n# 429 - 0052g000003qGOiAAM\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce';\n\nselect * from activities where type = 'softphone'\nand created_at > '2024-12-11 15:24:36' order by id desc;\n\nselect * from activity_providers where team_id = 1;\nselect * from activity_provider_users where activity_provider_id = 328;\n\nselect * from opportunities where crm_configuration_id = 39\nAND account_id = 178 AND is_closed = false\norder by created_at DESC;\n\nselect * from contacts where id = 3952;\nselect * from accounts where id = 178;\n\n# ************************************************************************************\nselect * from teams where id = 36;\nselect * from crm_configurations where id = 21;\nselect * from users where team_id = 36;\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 36;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 36\nand sa.provider = 'bullhorn';\n\nselect * from social_accounts where id = 348;\nUPDATE social_accounts SET\nprovider_user_token = '21442_6802599_91:41179a58-21e7-4d7c-ad58-56bb666b2f65',\nprovider_refresh_token = '21442_6802599_91:01c6b335-3f2a-42e4-85ff-8a08fa65fceb',\nexpires = 1733998131,\nstate = 'connected'\nWHERE id = 348;\n\n# ************************************************************************************\nselect * from teams where id = 31;\nselect * from crm_configurations where id = 18;\n\nselect * from users where team_id = 31; # 257\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 31;\n\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 31\nand sa.provider = 'close';\n\nselect * from contacts where crm_configuration_id = 18;\n\n# ********************** NEPTUNE **************************************************************\nselect * from teams;\nselect * from users where id IN (1030, 1035, 1052);\nselect * from crm_configurations;\n\nselect * from users where team_id = 65; # 257\nselect * from team_settings where team_id = 65; # 257\nselect * from invitations where team_id = 65; # 257\nselect * from users where email = 'integration-account@jiminny.com'; # 257\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 65;\n\nselect * from crm_configurations where id = 53;\nselect * from accounts where crm_configuration_id = 53 order by id desc;\nselect * from leads where crm_configuration_id = 53 order by id desc;\nselect * from contacts where crm_configuration_id = 53 order by id desc;\nselect * from opportunities where crm_configuration_id = 53 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 53 order by id desc;\nselect * from crm_fields where crm_configuration_id = 53 order by id desc;\nselect * from crm_field_values where crm_field_id = 3341 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 53 order by id desc;\nselect * from stages where crm_configuration_id = 53 order by id desc;\n\n\nselect * from crm_profiles where crm_configuration_id = 13;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 65\nand sa.provider = 'integration-app';\n\nselect * from contacts where crm_configuration_id = 13;\n\nselect * from social_accounts where sociable_id = 283;\n\nSELECT * FROM opportunities WHERE crm_provider_id = '006O400000E9bzeIAB';\n\nselect * from activity_providers where team_id = 65;\nSELECT * FROM activities WHERE crm_configuration_id IN (51, 52, 53);\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 65\n;\n\n# ***************************** STAGING ********************************************\nSELECT * FROM teams;\nSELECT * FROM teams WHERE id = 88;\nSELECT * FROM teams WHERE id = 89;\nselect * from team_settings where team_id = 89;\nSELECT * FROM users WHERE team_id = 89;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 89;\n\nselect * from users;\nSELECT * FROM social_accounts WHERE sociable_id = 1761;\nSELECT * FROM crm_configurations WHERE id = 70;\nselect * from accounts where crm_configuration_id = 70 order by id desc;\nselect * from leads where crm_configuration_id = 70 order by id desc;\nselect * from contacts where crm_configuration_id = 70 order by id desc;\nselect * from opportunities where crm_configuration_id = 70 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 70 order by id desc;\nselect * from crm_fields where crm_configuration_id = 70 order by id desc;\nselect * from crm_field_values where crm_field_id = 3536 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 70 order by id desc;\nselect * from stages where crm_configuration_id = 70 order by id desc;\nselect * from business_processes where crm_configuration_id = 70 order by id desc;\nselect * from business_process_stages where business_process_id = 34;\n\nselect * from contacts where id = 10468;\n\nselect * from crm_layouts where crm_configuration_id = 70;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 388;\nSELECT * FROM crm_fields WHERE id IN (3533,3534,3535);\n\nselect * from activities where crm_configuration_id = 70\nand (account_id IS NOT NULL or lead_id IS NOT NULL or contact_id IS NOT NULL or opportunity_id IS NOT NULL) order by id desc;\n\nSELECT * FROM activities WHERE uuid_to_bin('2e10b60f-8a61-41c5-a3d4-28835353dc65') = uuid;\nSELECT * FROM activities where crm_configuration_id = 69 ;\n\nSELECT * FROM users WHERE email LIKE '%jiminny_web_sa2@jiminny.com%';\nSELECT * FROM activities WHERE uuid_to_bin('5a150c93-40fc-42ec-b3bd-c1d328e09f6e') = uuid;\nSELECT * FROM opportunities WHERE id = 385;\n\nselect * from participants p\njoin activities a on p.activity_id = a.id\nwhere a.crm_configuration_id = 70\nand (p.lead_id IS NOT NULL or p.contact_id IS NOT NULL);\nSELECT * FROM participants WHERE id = 1013638;\n\nselect * from teams where id = 90;\nselect * from users where team_id = 90;\nselect * from social_accounts where social_accounts.sociable_id IN (1960,1760);\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 71;\nselect * from invitations where team_id = 90;\n\nselect * from crm_configurations where id = 71;\nselect * from accounts where crm_configuration_id = 71 order by id desc;\nselect * from leads where crm_configuration_id = 71 order by id desc;\nselect * from contacts where crm_configuration_id = 71 order by id desc;\nselect * from opportunities where crm_configuration_id = 71 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 71 order by id desc;\nselect * from crm_fields where crm_configuration_id = 71 order by id desc;\nselect * from crm_field_values where crm_field_id = 3341 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 71 order by id desc;\nselect * from stages where crm_configuration_id = 71 order by id desc;\n\nselect * from users order by secondary_email desc;\nselect u.id, u.email, u.status, sa.id, sa.provider_user_id from social_accounts sa\n join users u on sa.sociable_id = u.id\nwhere sa.provider = 'google' and u.email LIKE 'aneliya%';\n\nselect * from failed_jobs order by id desc;\n\nselect * from users where email = 'ben.allwright@learningpeople.co.uk' or secondary_email = 'ben.allwright@learningpeople.co.uk';\n\nselect * from teams;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 39;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type = 'task';\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce';\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('c38b3895-fd0f-4b1f-9fb2-c170dba137c6') = uuid;\nSELECT * FROM crm_configurations WHERE id = 70;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1;\nselect * from users where team_id = 1;\n\nselect o.id, o.name,o.close_date, u.id, u.name, u.group_id, r.id, r.display_name, g.name, g.scope from opportunities o\njoin users u on o.user_id = u.id\njoin groups g on u.group_id = g.id\njoin role_user ru on u.id = ru.user_id\njoin roles r on ru.role_id = r.id\nwhere o.crm_configuration_id = 39 and close_date > '2024-01-01 00:00:00';\n\nselect * from role_user where user_id = 143;\nselect * from roles;\n\nselect * from role_user;\nselect * from groups where id = 9;\nselect * from scope_groups where group_id = 9;\n\n# ************************************************************************************\nselect * from teams where id = 36;\nselect * from crm_configurations;\nSELECT * FROM social_accounts WHERE sociable_id = 121;\n\nhttps://crmsandbox.zoho.com/crm/jiminnyw4/tab/Leads/4776201000005049105\nhttps://crmsandbox.zoho.com/crm/\n\nhttps://crm.zoho.com/crm/org3469620/tab/Leads/230045000229559080\n https://crm.zoho.com/crm/\n org3469620\n\nSELECT * FROM activities WHERE uuid_to_bin('03382d20-c8bc-48e7-a3d4-90b52fa5ceab') = uuid;\n\nselect * from users where email LIKE \"%mobile_automation_%\";\nselect * from social_accounts where sociable_id IN (2228);\nselect * from crm_profiles where user_id IN (2222,2223,2226,2227);\n\nselect * from teams order by id desc;\nSELECT * FROM users WHERE id = 2229;\nSELECT * FROM crm_profiles WHERE user_id = 2229;\nselect * from opportunities where crm_configuration_id = 88;\nselect * from crm_fields where crm_configuration_id = 88;\nselect * from crm_profiles where crm_configuration_id = 88;\n\nSELECT * FROM teams WHERE id = 1;\n\nSELECT * FROM users WHERE id = 143;\nSELECT * FROM users WHERE uuid_to_bin('fde193d3-06a2-4e1a-8895-62b94039215d') = uuid;\nSELECT * FROM teams WHERE uuid_to_bin('73385071-a756-42ae-9c73-8b53f2309467') = uuid;\n\nhttps://app.staging.jiminny.com/ondemand?\n min_duration=1\n &\n only_recorded=1\n &\n user_id%5B%5D=641f1acb-16b8-42d1-8726-df52979dad0e\n &\n sequence_number=2\n\n select * from users where team_id = 1 and email like '%stoyan%'\n\nselect * from coaching_feedbacks;\n\nselect * from teams;\nSELECT * FROM users WHERE team_id = 36;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 19\nand sa.provider = 'pipedrive';\n\nselect * from users where id = 143;\n\nSELECT * FROM users WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\nSELECT * FROM teams WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\nSELECT * FROM activity_shares WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\n\nselect * from users where team_id = 2;\nselect * from activities where crm_configuration_id = 39\nand activities.scheduled_start_time BETWEEN '2025-04-09 00:00:00' AND '2025-04-09 23:59:59'\nAND user_id = 143\norder by id desc;\n\n# ************************************************************************************\nselect * from teams where id = 142; # 2312, 126\nselect * from team_settings;\nselect * from users where team_id = 142; # 21642\nSELECT * FROM social_accounts WHERE sociable_id = 21642;\nSELECT * FROM crm_profiles cp join users u ON u.id = cp.user_id WHERE team_id = 142;\nselect * from crm_profiles where id IN (93);\nselect * from invitations;\nselect * from team_features where team_id = 1;\n\nSELECT * FROM crm_configurations WHERE id = 126;\nselect * from accounts where crm_configuration_id = 126 order by id desc;\nselect * from leads where crm_configuration_id = 126 order by id desc;\nselect * from contacts where crm_configuration_id = 126 order by id desc;\nselect * from opportunities where crm_configuration_id = 126 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 126 order by id desc;\nselect * from crm_fields where crm_configuration_id = 126 # 11060\n# and type IN ('picklist', 'status')\n# and object_type = 'task'\norder by id desc;\n# 5731,5732,5733\nselect DISTINCT crm_field_id from crm_field_values where crm_field_id IN (11151,12239,12215,12185,12175,12165,12144,12137,12127,12109,12107,12105,12103,12092,12037,12005,12003,11987,11969,11958,11951,11942,11931,11924,11921,11917,11915,11901,11893,11883,11872,11870,11868,11866,11839,11833,11821,11793,11780,11777,11769,11757,11737,11735,11656,11645,11638,11629,11618,11611,11602,11591,11584,11581,11558,11544,11543,11534,11532,11529,11527,11503,11497,11493,11488,11470,11468,11457,11455,11397,11387,11372,11363,11348,11323,11318,11309,11301,11300,11292,11290,11286,11284,11256,11252,11242,11237,11233,11219,11176,11160) order by id desc;\nselect * from crm_layouts where crm_configuration_id = 126 order by id desc;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id in (300,299,298);\nselect * from stages where crm_configuration_id = 126 order by id desc;\nselect * from business_processes where crm_configuration_id = 126 order by id desc;\nselect * from business_process_stages where business_process_id IN (76,75,74,73);\nselect * from playbooks where team_id = 142;\nselect * from playbook_layouts where playbook_id IN (108);\nSELECT * FROM playbook_categories WHERE playbook_id IN (108);\n\nselect * from teams where id = 130;\nSELECT * FROM social_accounts WHERE sociable_id = 2291;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 2\nand sa.provider = 'hubspot';\n\nSELECT * FROM activities\n WHERE crm_configuration_id = 110;\n\nselect * from teams;\nselect * from crm_configurations;\n\nSELECT * FROM activities WHERE id = 628773;\nSELECT * FROM crm_profiles WHERE user_id = 1460;\nSELECT * FROM social_accounts WHERE sociable_id = 2291;\n\nselect * from teams;\nselect ru.*, pr.*, p.* from users u join role_user ru on ru.user_id = u.id\njoin permission_role pr on pr.role_id = ru.role_id\n join permissions p on p.id = pr.permission_id\nwhere team_id = 495 and p.name IN ('dial');\n\nselect * from teams where id = 145;\nselect * from crm_configurations where id = 129;\nselect * from social_accounts where sociable_id = 2317;\nSELECT * FROM activities WHERE uuid_to_bin('8dbab184-a333-4268-ad57-fb41f8d53a9a') = uuid;\n\nselect * from teams where id = 1;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 280;\nSELECT * FROM crm_layout_entities WHERE id = 5507;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type IN ('event');\n\nselect * from teams;\nselect * from activities where crm_configuration_id = 14;\n\nSELECT * FROM social_accounts where provider = 'copper';\n\nselect * from activities where id = 628467;\nselect * from participants where activity_id = 628467;\n\nSELECT * FROM contacts WHERE id = 3969;\nSELECT * FROM accounts WHERE id = 177;\n\nSELECT * FROM activities WHERE uuid_to_bin('4eb54c77-cfa3-2bd4-84a7-9ed46a21c988') = uuid;\n\n# ********************* BH\nselect * from teams where id = 36;\nSELECT * FROM crm_configurations WHERE id = 21;\nselect * from activities where crm_configuration_id = 21 and id = 607901;\nselect * from activities where crm_configuration_id = 21;\n\nselect * roles;\nselect * from permissions;\nselect * from permission_role where permission_id = 226;\n\nselect * from migrations order by id desc;\n\n# mercury\n# neptune\n# earth\n\nselect * from teams;\nselect * from teams where id = 19;\nselect * from teams where id = 27;\nselect * from users where team_id = 27;\nSELECT * FROM crm_configurations WHERE id = 42;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 19\nand sa.provider = 'pipedrive';\n\nselect * from activities where id = 631461;\nSELECT * FROM crm_field_values WHERE crm_field_id = 180;\n\nselect * from teams where id = 2;\nSELECT * FROM social_accounts WHERE sociable_id = 89;\n\nSELECT * FROM activities WHERE uuid_to_bin('ba0c029a-bc14-4e17-8603-64174acebcbb') = uuid; # 634273\nselect * from activity_summary_logs where activity_id = 634273;\n\nselect * from sidekick_settings where team_id = 2;\n\nselect * from teams; # 2, 2\nSELECT * FROM crm_configurations WHERE team_id = 2; # 2\nselect * from team_features where team_id = 2;\nselect * from features;\nSELECT * FROM opportunities WHERE crm_configuration_id = 2 and crm_provider_id = '51317301383';\nSELECT * FROM opportunities WHERE crm_configuration_id = 2 order by id desc;\n\nselect * from automated_reports order by id desc;\nselect * from automated_report_results order by id desc;\nselect * from users where team_id = 1 and id IN (7160, 3248);\nselect * from migrations order by id desc;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1052 and sa.provider = 'hubspot';\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 = 565;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 175;\nselect * from playbook_categories where playbook_id = 175;\nselect * from users where team_id = 1052;\nselect * from users where id = 7160;\nselect * from crm_profiles where user_id = 7160;\nselect * from features;\nselect\n *\n# id, uuid, type, provider, playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id, stage_id,\n# crm_configuration_id, crm_provider_id, transcription_id, status\nfrom activities where crm_configuration_id = 1 and type = 'conference'\n# and crm_provider_id IS NOT NULL\nand provider != 'uploader' and actual_start_time IS NOT NULL\nORDER by id desc;\nselect * from activities where id = 54747783; # 00UO400000pCzojMAC\n\nselect p.id, p.activity_type, pc.id, pc.name\nFROM playbooks p\njoin playbook_categories pc on p.id = pc.playbook_id\nwhere p.team_id = 1 and p.activity_type = 'event';\n\nSELECT * FROM crm_fields WHERE crm_configuration_id = 1 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id = 4;\n\nselect * from crm_layouts cl join playbook_layouts pl on cl.id = pl.layout_id\nwhere crm_configuration_id = 1 and pl.playbook_id = 175;\n\nselect * from teams;\nSELECT r.* FROM automated_reports r\njoin teams t on r.team_id = t.id\nWHERE r.frequency = 'daily'\n and r.status = 1\nAND t.status = 'active'\nAND (r.expires_at >= now() OR r.expires_at IS NULL);\n\nselect * from automated_report_results where report_id IN (18, 33);\n\nselect * from users where team_id = 1 and id = 1047;\nSELECT * FROM social_accounts WHERE sociable_id = 1047;\n\nselect * from activity_searches where id = 10932;\nselect * from activity_search_filters where activity_search_id = 10932;\nselect * from automated_reports order by id desc;\nselect * from automated_report_results order by id desc;\nselect * from automated_reports where id IN (55);\nselect * from automated_report_results where id IN (81);\nselect * from users where id IN (10633, 13987, 11985);\nselect * from users where group_id IN (3710);\n\nSELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;\nSELECT * FROM automated_report_results WHERE uuid_to_bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;\n\nselect * from teams;\nselect * from accounts where team_id = 1;\n\nselect * from automated_report_results where media_type = 'pdf' and status = 2;\nSELECT * FROM automated_report_results WHERE uuid_to_bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid;\n\nselect * from teams where id = 1029;\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 = 1029 and sa.provider = 'pipedrive';\n\n[\n {\n \"user_id\": \"23460 (owner)\",\n \"email\": \"integration-account@pipedrive.jiminny.com\",\n \"id\": 69,\n \"sociable_id\": 23460,\n \"provider_user_id\": \"19555731\",\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,\n \"refresh_token_expires\": null,\n \"provider\": \"pipedrive\",\n \"state\": \"connected\",\n \"auth_scope\": \"base,deals:full,activities:full,contacts:full,search:read\",\n \"retry_after\": null,\n \"created_at\": \"2025-04-16 08:23:28\",\n \"updated_at\": \"2026-05-18 07:13:18\",\n \"provider_user_token_encrypted\": \"eyJpdiI6Ik9oYzBwcTVteWN4ajBRaDdMb0FjWGc9PSIsInZhbHVlIjoiQUNMbjU5UHR2Q1RnbWRXMEU1TUx6UVpRU3gzdVc5WktmTE4rVlhXa3lRaGhyUUlZMVZRWEJuR0JaWWhZZXNPRlBuanhuYU5MVHZ5TG9NTVVjNjJSUUpZZ2VhbGYxbHg0UzJEdTVmQjNFZnJRZkMwYjd0N2RMZ05GRS9IR3c2K0NoVjBjYTA5UG12SkxHeDlDMGVNN3ptUWUzblFiTngyYzR1eUpHSEYrdEwvZm0yZklGYjBSNEtTR2ZGazhLM1hqT3lVbjFobDNPZ0d3anFlcjhKcXpERlZGOVN1YmFyNDIvM1BFRDFMYnp4WEI4TGVLM2xYcy9CL0RDOWlQNHI3N0NwWnJPMWRtZllmM2ZKeE9TV2NBeDZxL2M1YnlSVzd3ZW96T3F1QmtBYXBHYkUraGcvdCtRajlYZXBjVVBSdFlMUjVPVDVJbDdyenVoWjMrbVJvU3ZZR1dQZ3pqQ3F3aDF2U2xPZWZIN3BCWVFLNXpxQUtDb2pIK0xHc1E3SklSM3Q0VkNSbm9oK2pFK3hLaW54T1dWbEVneUp0RGhhdVBuOFI4MXROc3dZWnFnTUpiaDVMMnZ4QmlRM3k4QWFlMVFWUFYvdGhJQzZBYnhBQmhWa2ZKN1ZhSnhpaExxbmlTemgzUWw3aXJtWjlSMlhmd0lWMDNDN1N3My9Ua0hCL2xqY3RkVFhMSjFJMDRjOE5DWlgrZ3FMVXN6RWlwUE5GWERZdG1xVjVxOFlLRGs2VVJKS3FLeWRxQjYxdDh4Z2JJNXhlWEZ3dkQ4SGtybDNUcndzblFHeVJNRkYraFh2UDFIUTdMQ1BZa3dEU1dBbzk5K0dyT2RNVFBZZUJpRytSck5pYlI1YUZyMmhUNEZCdWxHYmJLREtzbUpjVkhvV0RoejJpbm1SWHlNaXE5M0RhcS94UW9EdFoweWF3bVFVY0dTZWFPSXBmOCtDYndia215cmtyZU1oT0Exam1CV2tPblNhYjY4clVEeUs3anVHUmNHeS9YLzRha1VhbGl3N3lwaDlzZnRhQUZta2s4eFllNHgzRklSRmNyazJ4dlBDMnByNCtBRjNaVjJCTT0iLCJtYWMiOiJkYTQxZDY1OTY2ZTljMTgyZWRhNGEzMGZjZDc2MjBjN2NlNzU2YTViNGQxNWE1NTI2ZmI1MWQyYjQ2ODYxZmEwIiwidGFnIjoiIn0=\",\n \"provider_refresh_token_encrypted\": \"eyJpdiI6Imt2bGxlSmxUK05GMjF0dEtPaTMrUlE9PSIsInZhbHVlIjoiUXZHTElZRXkreHFxUU02SnZ4eVBacG9WWTRlVkd0USszV3JyVFlpU2ZaY25GSWo2WFcrRzNlbFRlUXRQczNwSXRCcEdvZEpveG9jMzBDSTgwdnZLQnc9PSIsIm1hYyI6ImQxYWI0NzU5Nzg5MDI4YWVhZmQ4Mjg1YzhkZDQzMjRkYWYwYTdhZTY5MDMxMjc0OWNiYjY0Nzc3NDQ0MTEyY2EiLCJ0YWciOiIifQ==\",\n \"encryption_key\": \"0x01020300786192D9D96DD60D3D1EBC9DFAEE5F0C45EE80165CF3F3D2B3B627026AA7CFC7CA0128DD463535D32EE491ADBADF8B07596B0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040C7FB1319048ECB2EA3F23B995020110802B52D22F5EAD341AB238FBBCB6093156E443876A664BA5555D722565C2B2D04422C868CD7350555E3CC74221\",\n \"sociable_type\": \"user\",\n \"owner_id\": 23460\n },\n {\n \"user_id\": \"23463\",\n \"email\": \"jiminny_web_sa@pipedrive.jiminny.com\",\n \"id\": 72,\n \"sociable_id\": 23463,\n \"provider_user_id\": \"23270841\",\n \"provider_user_token\": \"v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:txqCuWLeVhgwiaFqXIvQWWrtrnFIy_4lT3VCr-sRB4g6_2lK8KcQ_6ka_qFmZhr-IeIAKmAImx6H1iIKx4Ab7XZ5MnKIh03GKbHjI0n0rGT9UYkeH21jKOxJvKaSX_TyLbxFPR6irPQyvqcpBClXI52gVJH01KzZy_dMTHFXhhDLOIhEpSrQXHG7Qo8q7OuBeSPZrU1ALi9kmAm4GTpzGTbzfl-hUt9IAfPunJOCyv3mf2Tl-MT8EyQgOFPrsP3yz9UlSyVhb40zO_bCnUrqNxjwgm_E6vgpVrwULTQbHe-43Dq-TRetjceUzT88GBgVJ0UdxXP5BRBVXcL5ir8-9ZTMaNU\",\n \"provider_refresh_token\": \"5034113:23270841:34790b44838f5fd422c2d2c82e00f1ecf2178ad1\",\n \"expires\": 1753837219,\n \"refresh_token_expires\": null,\n \"provider\": \"pipedrive\",\n \"state\": \"full-refresh\",\n \"auth_scope\": \"base,deals:full,activities:full,contacts:full,search:read\",\n \"retry_after\": null,\n \"created_at\": \"2025-04-16 10:41:12\",\n \"updated_at\": \"2025-07-30 01:00:17\",\n \"provider_user_token_encrypted\": \"eyJpdiI6InVEVEl2SzIxMjd1bkNDWG9lY3YvQ0E9PSIsInZhbHVlIjoiRlJLbDZ3ZHo2dHMxUWQwdGU2YUZjV3lPWHlxQTJ0eWh4S0RTMjlSaThVcktoaWhXcTd2UXl4Mjg4bW5UUnZCZEQ5NXpuQTVKOURiMDNIa3l3K0lSWCt5azRBOEdHbitWQXhxeEpMVUZ1dnF2NVl1TTZLelZOaGNvRlBLeGpIWlpoRGloUEprd2xoNUFPcTlLcUd3WVlUU2svR1NOeXBYQ2NnMWhnK1V2aytOeVVMNzJGdVZXMU1JS3BSaGNCcmxkVjEwQ01mQXNBdWNhS1lMZWZobnZwcHBkN1R4bUVDRUNYdnNtSVJkdG5MdkN3djJBT0hMRDl1MHFGbnl4WU13ejBkUWsrdUljWkZhcTJlN0JDSGdTVzlPY0FGMUJlZi9WRGpkMUk5R20wblYwSk9VR2FuaHpLTzJNeitMbnF1V1NEMUUxRmYzaDRGZDMyaXd3Z0FjQno4SzVoYjUyTmV3UXNpRlF4TGZKNVl3dUFqdGhKVWJjRVlUUXRGalBpaXJvSGJmbS8rd25aQ2Zvc05saHRDRjlHV1VEUFFiRU5xbWRVNkxFSXV0RUZyaUlYNWMwMmhnZ0Y1VUQ4eEFkY2QyWXpnR0NidkVJSWdjVGljUjA3NDdpZW9WUHhtSlpGSGdNU2hRUTA5ZW03RGpiRFdrdytkOHJXSUxlazZNaG9iaUg2NFZYdEc3YklMeFZvblBzWmVRSDcvN2M4WUNtL3h4S2IrUW00cXhialBia3BJcW5XallBNlV5WWdhcE1ZVFBBM3RSSUVBamYvOGZEQWM5a2FJMGwyWkRSU3dlTEtPemZlQ3RXRGNDcEdYRHdMNTlTQVg2SUdUN0hVaXdZT1dUOUlrVzkrZHFBemhwWXg1cm4rSy9UOHUzcnNSM2dISlhBRTEyVUNyTkZYaFJYUlN1a2RKVHhhM2dHckR3a1JGaVZ2Wk9BVnhTclVpSEhwWTVpQTlJbXVkOUxSTGpRbDk0a1VtbE9QMVAvN3VlVEhJUHd2elowd0laNVIzZ3M3N0ZOK0NDakIwQ2FicGxoMDBhTXI0VUppUmFOZHdlWUdGV21NNFQ4RU1nY0dnWT0iLCJtYWMiOiI0ZTU4ZmJkNTdkYmY0NGE4NTJjZjlhNDExNzE2YjhlOWM2NTA5OGY2MDA4OTcyZDVlOTljY2JjZDhmMjBhMDUyIiwidGFnIjoiIn0=\",\n \"provider_refresh_token_encrypted\": \"eyJpdiI6IkJGMkdRVHRKM2VTcitKNGcvQWJtUGc9PSIsInZhbHVlIjoicmFyRkxPZ1Rybm1ORXlEVjJ2TXFGTzJtM3hWaFhnUVVHN2ZlR1lRM0I5d3ozbnZTcU5EdzJqRkI2elhyNWhlenRTUXV3bjk0N1JXeklDMVAyUzBKcHc9PSIsIm1hYyI6ImJhODVjMGQyZDE3Y2ExNjc2OWVjYWJiNmFjYWVkODIyMTMyNWVhYTExMTgwYTEyMTU0MzUzZGE1YjQ5YzQ5ZjEiLCJ0YWciOiIifQ==\",\n \"encryption_key\": \"0x01020300788C37CDF66ABE9301A68D5D4866AC0C197E04EEE4D904F20A59991322EBAE252301BEF4B24FF01359E934E5654617E4EEAC0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040CEB00EF45BDEA999A5558889E020110802B925F372F7BEFAF0B45E48686113D1DA430ECFCC07B1F61BA6828CC44235278EDB05C486E8068D0BE737D91\",\n \"sociable_type\": \"user\",\n \"owner_id\": 23460\n }\n]","role_description":"text entry area","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}]...
|
1292623199131388967
|
6686649177355990093
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
namespace Jiminny\Component\SCIM;
use Jiminny\Component\SCIM\Builders\Filters;
class Constants
{
/**
* HTTP codes
*/
public const HTTP_OK = 200;
public const HTTP_CREATED = 201;
public const HTTP_NO_CONTENT = 204;
public const HTTP_NOT_FOUND = 404;
public const HTTP_BAD_REQUEST = 400;
public const HTTP_ACCESS_DENIED = 403;
public const HTTP_ERROR = 501;
/**
* Users resource constants
*/
public const USER_FIRST_NAME = 'givenName';
public const USER_FAMILY_NAME = 'familyName';
public const USER_STATUS = 'Active';
public const USER_USERNAME = 'UserName';
public const USER_EXTERNAL_ID = 'externalId';
public const USER_FIELDS = [
self::USER_FIRST_NAME,
self::USER_FAMILY_NAME,
self::USER_STATUS,
self::USER_USERNAME,
];
public const META_OPERATIONS_REPLACE = 'replace';
public const META_OPERATIONS_REPLACE_UPPER = 'Replace';
public const META_OPERATIONS_ADD = 'add';
public const META_OPERATIONS_ADD_UPPER = 'Add';
public const META_OPERATIONS_REMOVE_UPPER = 'Remove';
public const META_OPERATIONS_REMOVE = 'remove';
public const META_ID = 'id';
public const META_PHONE_NUMBERS = 'phoneNumbers';
public const META_TITLE = 'title';
public const META_ROLES = 'roles';
public const META_PATH = 'path';
public const META_ENTERPRISE_SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';
public const META_DEPARTMENT = 'department';
public const META_META = 'meta';
public const META_TYPE = 'type';
public const META_VALUE = 'value';
public const META_OPERATIONS = 'Operations';
public const META_OP = 'op';
public const META_RESOURCE_TYPE = 'resourceType';
public const META_CREATED = 'created';
public const META_LAST_MODIFIED = 'lastModified';
public const META_FORMATTED = 'formatted';
public const META_EMAILS = 'emails';
public const META_USERNAME = 'userName';
public const META_NAME = 'name';
public const META_STATUS = 'active';
public const META_PRIMARY = 'primary';
public const META_ERROR_STATUS = 'status';
public const META_ERROR_DETAIL = 'detail';
public const META_LIST_TOTAL_RESULTS = 'totalResults';
public const META_LIST_RESOURCES = 'Resources';
public const META_LIST_START_INDEX = 'startIndex';
public const META_LIST_COUNT = 'count';
public const META_LIST_ITEMS_PER_PAGE = 'itemsPerPage';
public const META_SCHEMAS = 'schemas';
public const META_FILTER = 'filter';
public const META_TYPE_WORK = 'work';
public const META_PHONE_NUMBER_TYPE_MOBILE = 'mobile';
public const META_EMAIL_TYPE_HOME = 'home';
public const META_CONTAINER_NAME = 'name';
public const META_CONTAINER_EMAILS = 'emails';
public const RESOURCE_TYPE_USER = 'User';
public const USER_PATCH_ATTR_TITLE = 'title';
public const USER_PATCH_ATTR_ACTIVE = 'active';
public const USER_PATCH_ATTR_USERNAME = 'userName';
public const USER_PATCH_ATTR_FIRST_NAME = 'name.givenName';
public const USER_PATCH_ATTR_LAST_NAME = 'name.familyName';
public const USER_PATCH_ATTR_PRIMARY_EMAIL = 'emails[type eq "work"].value';
public const USER_PATCH_ATTR_SECONDARY_EMAIL = 'emails[type eq "home"].value';
public const USER_PATCH_ATTR_PHONE_NUMBER = 'phoneNumbers[type eq "work"].value';
public const USER_PATCH_ATTR_PHONE_NUMBER_MOBILE = 'phoneNumbers[type eq "mobile"].value';
public const USER_PATCH_ATTR_ROLES = 'roles';
public const USER_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [
self::USER_PATCH_ATTR_TITLE => Mutators\Attributes\User\TitleAttr::class,
self::USER_PATCH_ATTR_ACTIVE => Mutators\Attributes\User\ActiveAttr::class,
self::USER_PATCH_ATTR_USERNAME => Mutators\Attributes\User\UsernameAttr::class,
self::USER_PATCH_ATTR_FIRST_NAME => Mutators\Attributes\User\FirstNameAttr::class,
self::USER_PATCH_ATTR_LAST_NAME => Mutators\Attributes\User\LastNameAttr::class,
self::USER_PATCH_ATTR_PRIMARY_EMAIL => Mutators\Attributes\User\PrimaryEmailAttr::class,
self::USER_PATCH_ATTR_SECONDARY_EMAIL => Mutators\Attributes\User\SecondaryEmailAttr::class,
self::USER_PATCH_ATTR_PHONE_NUMBER => Mutators\Attributes\User\PhoneNumberPrimaryAttr::class,
self::USER_PATCH_ATTR_PHONE_NUMBER_MOBILE => Mutators\Attributes\User\PhoneNumberSecondaryAttr::class,
self::USER_PATCH_ATTR_ROLES => Mutators\Attributes\User\RoleAttr::class,
];
public const FILTER_OPERATOR_EQ = 'eq';
public const SUPPORTED_FILTERS_OPERATORS = [
self::FILTER_OPERATOR_EQ,
];
public const USER_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [
self::USER_FILTER_LOCAL_ID => Filters\User\LocalIdFilter::class,
self::USER_FILTER_USERNAME => Filters\User\UserNameFilter::class,
self::USER_FILTER_FIRST_NAME => Filters\User\FirstNameFilter::class,
self::USER_FILTER_LAST_NAME => Filters\User\LastNameFilter::class,
self::USER_FILTER_EXTERNAL_ID => Filters\User\ExternalIdFilter::class,
self::USER_FILTER_DISPLAY_NAME => Filters\User\DisplayNameFilter::class,
];
public const USER_FILTER_LOCAL_ID = 'id';
public const USER_FILTER_USERNAME = 'userName';
public const USER_FILTER_FIRST_NAME = 'givenName';
public const USER_FILTER_LAST_NAME = 'familyName';
public const USER_FILTER_EXTERNAL_ID = 'externalId';
public const USER_FILTER_DISPLAY_NAME = 'DisplayName';
public const SCIM_SUPPORTED_RESOURCES = [
self::USER_RESOURCE_PREFIX,
self::GROUP_RESOURCE_PREFIX,
];
public const USER_RESOURCE_PREFIX = 'Users';
public const GROUP_RESOURCE_PREFIX = 'Groups';
public const OUTGOING_SCHEMAS_SUPPORTED = [
self::OUTGOING_CORE_USER,
];
/**
* Outgoing supported schemas
*/
public const OUTGOING_CORE_USER = 'urn:ietf:params:scim:schemas:core:2.0:User';
public const OUTGOING_ERROR = 'urn:ietf:params:scim:api:messages:2.0:Error';
public const OUTGOING_LIST_RESPONSE = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';
public const OUTGOING_CORE_GROUP = 'urn:ietf:params:scim:schemas:core:2.0:Group';
/**
* Groups resource constants
*/
public const GROUP_ATTRIBUTE_DISPLAY_NAME = 'displayName';
public const GROUP_ATTRIBUTE_EXTERNAL_ID = 'externalId';
public const GROUP_ATTRIBUTE_ID = 'id';
public const RESOURCE_TYPE_GROUP = 'Group';
public const GROUP_FILTER_QUERY_NAME = 'filter';
public const GROUP_EXCLUDED_ATTRIBUTES = 'excludedAttributes';
public const GROUP_SUPPORTED_FILTER_ATTRIBUTES = [
self::GROUP_ATTRIBUTE_DISPLAY_NAME,
];
public const GROUP_MEMBERS = 'members';
public const SUPPORTED_PATCH_OPERATIONS = [
self::META_OPERATIONS_ADD,
self::META_OPERATIONS_REPLACE,
self::META_OPERATIONS_REMOVE,
];
public const GROUP_PATCH_ATTRIBUTE_MEMBERS = 'members';
public const GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME = 'displayName';
public const GROUP_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [
self::GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME => Mutators\Attributes\Group\DisplayNameAttr::class,
self::GROUP_PATCH_ATTRIBUTE_MEMBERS => Mutators\Attributes\Group\MembersAttr::class,
];
public const GROUP_FILTER_DISPLAY_NAME = 'displayname';
public const GROUP_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [
self::GROUP_FILTER_DISPLAY_NAME => Filters\Group\DisplayNameFilter::class,
];
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny_jupiter
Sync Changes
Hide This Notification
Code changed:
Hide
19
19
17
Previous Highlighted Error
Next Highlighted Error
SELECT * FROM teams WHERE id = 1;
select * from crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 283;
SELECT * FROM crm_fields WHERE id = 2234;
SELECT * FROM crm_field_values WHERE crm_field_id = 2234;
select * from crm_profiles where user_id = 143;
select * from record_types where crm_configuration_id = 39; # 0121K000001MHElQAO,0121K000001MHEqQAO
select * from business_processes where crm_configuration_id = 39;
# 01941000000H669AAC, 01941000000H66JAAS
select * from record_type_field_values
where record_type_id IN (24);
select * from crm_field_values where id IN (2730);
select * from crm_configurations where id = 39;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce'; #1035
select * from users where team_id = 1; # 222 group 3
SELECT * FROM activities WHERE user_id = 222 order by id desc;
select * from sidekick_settings where team_id = 1;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from activities where crm_configuration_id = 2
and provider = 'ms-teams' and id = 608765;
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id = '59523413338';
select * from sidekick_settings where team_id = 2;
SELECT * FROM activities WHERE id = 608660;
select * from activity_summary_logs where activity_id = 608660;
select * from ai_prompts where transcription_id = 11214;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('ed78a437-2804-450e-ab2f-56ab1c641346') = uuid;
# id: 608818, crm: 59628809737
SELECT * FROM activities WHERE uuid_to_bin('36b06e55-afdd-4782-8dee-c624cd0af191') = uuid;
# id: 608821, crm: 59632069252
SELECT ce.start_time, ce.end_time, a.id, a.uuid, crm_provider_id, calendar_event_id, title,
playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id,
scheduled_start_time, scheduled_end_time, actual_start_time, actual_end_time, a.created_at
FROM activities a
join calendar_events ce on a.calendar_event_id = ce.id
WHERE a.id IN (608818, 608821);
select * from users where team_id = 1;
select * from team_settings where team_id = 1;
select * from crm_profiles where crm_configuration_id = 39 order by user_id;
select * from team_features where team_id = 1;
select * from users where team_id = 2;
SELECT * FROM activities WHERE uuid_to_bin('ec7647e9-5225-458b-b475-f31aa2769204') = uuid; # 612639
# Preslava N. Ivanova, grou id 3
SELECT * FROM opportunities WHERE uuid_to_bin('a2928fe5-aec5-46cb-85d9-7654c89e46a6') = uuid;
select * from activities where opportunity_id = 344 and actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00';
select
a.id,
a.type,
a.scheduled_start_time,
a.actual_start_time,
a.created_at,
a.opportunity_id,
a.status
FROM activities a
WHERE opportunity_id = 344
and status IN ('completed', 'received', 'delivered')
and (
(a.actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')
OR (a.created_at between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')
OR (a.scheduled_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00'))
;
SELECT * FROM users WHERE id = 222;
SELECT * FROM crm_profiles WHERE user_id = 222;
select * from crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 281;
select * from group_deal_risk_types;
select * from opportunities where team_id = 1;
SELECT * FROM opportunities WHERE id = 315;
SELECT * FROM crm_field_data WHERE object_id = 315;
select * from crm_field_data where object_id = 260;
select * from generic_ai_prompts where subject_id = 315;
select * from teams; # 36, 21, 121, [EMAIL]
SELECT * FROM social_accounts WHERE sociable_id = 121 and provider = 'bullhorn';
# [PASSWORD_DOTS]
select * from teams where id = 1;
select * from crm_configurations where id = 39;
select * from users where team_id = 1;
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 1;
# 1 - 00541000004281rAAA
# 204 - 0052g000003freeAAA
# 429 - 0052g000003qGOiAAM
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce';
select * from activities where type = 'softphone'
and created_at > '2024-12-11 15:24:36' order by id desc;
select * from activity_providers where team_id = 1;
select * from activity_provider_users where activity_provider_id = 328;
select * from opportunities where crm_configuration_id = 39
AND account_id = 178 AND is_closed = false
order by created_at DESC;
select * from contacts where id = 3952;
select * from accounts where id = 178;
# [PASSWORD_DOTS]
select * from teams where id = 36;
select * from crm_configurations where id = 21;
select * from users where team_id = 36;
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 36;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 36
and sa.provider = 'bullhorn';
select * from social_accounts where id = 348;
UPDATE social_accounts SET
provider_user_token = '21442_6802599_91:41179a58-21e7-4d7c-ad58-56bb666b2f65',
provider_refresh_token = '21442_6802599_91:01c6b335-3f2a-42e4-85ff-8a08fa65fceb',
expires = 1733998131,
state = 'connected'
WHERE id = 348;
# [PASSWORD_DOTS]
select * from teams where id = 31;
select * from crm_configurations where id = 18;
select * from users where team_id = 31; # 257
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 31;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 31
and sa.provider = 'close';
select * from contacts where crm_configuration_id = 18;
# [PASSWORD_DOTS] NEPTUNE [PASSWORD_DOTS]
select * from teams;
select * from users where id IN (1030, 1035, 1052);
select * from crm_configurations;
select * from users where team_id = 65; # 257
select * from team_settings where team_id = 65; # 257
select * from invitations where team_id = 65; # 257
select * from users where email = '[EMAIL]'; # 257
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 65;
select * from crm_configurations where id = 53;
select * from accounts where crm_configuration_id = 53 order by id desc;
select * from leads where crm_configuration_id = 53 order by id desc;
select * from contacts where crm_configuration_id = 53 order by id desc;
select * from opportunities where crm_configuration_id = 53 order by id desc;
select * from crm_profiles where crm_configuration_id = 53 order by id desc;
select * from crm_fields where crm_configuration_id = 53 order by id desc;
select * from crm_field_values where crm_field_id = 3341 order by id desc;
select * from crm_layouts where crm_configuration_id = 53 order by id desc;
select * from stages where crm_configuration_id = 53 order by id desc;
select * from crm_profiles where crm_configuration_id = 13;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 65
and sa.provider = 'integration-app';
select * from contacts where crm_configuration_id = 13;
select * from social_accounts where sociable_id = 283;
SELECT * FROM opportunities WHERE crm_provider_id = '006O400000E9bzeIAB';
select * from activity_providers where team_id = 65;
SELECT * FROM activities WHERE crm_configuration_id IN (51, 52, 53);
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 65
;
# [PASSWORD_DOTS] STAGING [PASSWORD_DOTS]
SELECT * FROM teams;
SELECT * FROM teams WHERE id = 88;
SELECT * FROM teams WHERE id = 89;
select * from team_settings where team_id = 89;
SELECT * FROM users WHERE team_id = 89;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 89;
select * from users;
SELECT * FROM social_accounts WHERE sociable_id = 1761;
SELECT * FROM crm_configurations WHERE id = 70;
select * from accounts where crm_configuration_id = 70 order by id desc;
select * from leads where crm_configuration_id = 70 order by id desc;
select * from contacts where crm_configuration_id = 70 order by id desc;
select * from opportunities where crm_configuration_id = 70 order by id desc;
select * from crm_profiles where crm_configuration_id = 70 order by id desc;
select * from crm_fields where crm_configuration_id = 70 order by id desc;
select * from crm_field_values where crm_field_id = 3536 order by id desc;
select * from crm_layouts where crm_configuration_id = 70 order by id desc;
select * from stages where crm_configuration_id = 70 order by id desc;
select * from business_processes where crm_configuration_id = 70 order by id desc;
select * from business_process_stages where business_process_id = 34;
select * from contacts where id = 10468;
select * from crm_layouts where crm_configuration_id = 70;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 388;
SELECT * FROM crm_fields WHERE id IN (3533,3534,3535);
select * from activities where crm_configuration_id = 70
and (account_id IS NOT NULL or lead_id IS NOT NULL or contact_id IS NOT NULL or opportunity_id IS NOT NULL) order by id desc;
SELECT * FROM activities WHERE uuid_to_bin('2e10b60f-8a61-41c5-a3d4-28835353dc65') = uuid;
SELECT * FROM activities where crm_configuration_id = 69 ;
SELECT * FROM users WHERE email LIKE '%[EMAIL]%';
SELECT * FROM activities WHERE uuid_to_bin('5a150c93-40fc-42ec-b3bd-c1d328e09f6e') = uuid;
SELECT * FROM opportunities WHERE id = 385;
select * from participants p
join activities a on p.activity_id = a.id
where a.crm_configuration_id = 70
and (p.lead_id IS NOT NULL or p.contact_id IS NOT NULL);
SELECT * FROM participants WHERE id = 1013638;
select * from teams where id = 90;
select * from users where team_id = 90;
select * from social_accounts where social_accounts.sociable_id IN (1960,1760);
SELECT * FROM crm_profiles WHERE crm_configuration_id = 71;
select * from invitations where team_id = 90;
select * from crm_configurations where id = 71;
select * from accounts where crm_configuration_id = 71 order by id desc;
select * from leads where crm_configuration_id = 71 order by id desc;
select * from contacts where crm_configuration_id = 71 order by id desc;
select * from opportunities where crm_configuration_id = 71 order by id desc;
select * from crm_profiles where crm_configuration_id = 71 order by id desc;
select * from crm_fields where crm_configuration_id = 71 order by id desc;
select * from crm_field_values where crm_field_id = 3341 order by id desc;
select * from crm_layouts where crm_configuration_id = 71 order by id desc;
select * from stages where crm_configuration_id = 71 order by id desc;
select * from users order by secondary_email desc;
select u.id, u.email, u.status, sa.id, sa.provider_user_id from social_accounts sa
join users u on sa.sociable_id = u.id
where sa.provider = 'google' and u.email LIKE 'aneliya%';
select * from failed_jobs order by id desc;
select * from users where email = '[EMAIL]' or secondary_email = '[EMAIL]';
select * from teams;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 39;
SELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type = 'task';
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce';
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('c38b3895-fd0f-4b1f-9fb2-c170dba137c6') = uuid;
SELECT * FROM crm_configurations WHERE id = 70;
select * from teams where id = 1;
select * from groups where team_id = 1;
select * from users where team_id = 1;
select o.id, o.name,o.close_date, u.id, u.name, u.group_id, r.id, r.display_name, g.name, g.scope from opportunities o
join users u on o.user_id = u.id
join groups g on u.group_id = g.id
join role_user ru on u.id = ru.user_id
join roles r on ru.role_id = r.id
where o.crm_configuration_id = 39 and close_date > '2024-01-01 00:00:00';
select * from role_user where user_id = 143;
select * from roles;
select * from role_user;
select * from groups where id = 9;
select * from scope_groups where group_id = 9;
# [PASSWORD_DOTS]
select * from teams where id = 36;
select * from crm_configurations;
SELECT * FROM social_accounts WHERE sociable_id = 121;
https://crmsandbox.zoho.com/crm/jiminnyw4/tab/Leads/4776201000005049105
https://crmsandbox.zoho.com/crm/
https://crm.zoho.com/crm/org3469620/tab/Leads/230045000229559080
https://crm.zoho.com/crm/
org3469620
SELECT * FROM activities WHERE uuid_to_bin('03382d20-c8bc-48e7-a3d4-90b52fa5ceab') = uuid;
select * from users where email LIKE "%mobile_automation_%";
select * from social_accounts where sociable_id IN (2228);
select * from crm_profiles where user_id IN (2222,2223,2226,2227);
select * from teams order by id desc;
SELECT * FROM users WHERE id = 2229;
SELECT * FROM crm_profiles WHERE user_id = 2229;
select * from opportunities where crm_configuration_id = 88;
select * from crm_fields where crm_configuration_id = 88;
select * from crm_profiles where crm_configuration_id = 88;
SELECT * FROM teams WHERE id = 1;
SELECT * FROM users WHERE id = 143;
SELECT * FROM users WHERE uuid_to_bin('fde193d3-06a2-4e1a-8895-62b94039215d') = uuid;
SELECT * FROM teams WHERE uuid_to_bin('73385071-a756-42ae-9c73-8b53f2309467') = uuid;
https://app.staging.jiminny.com/ondemand?
min_duration=1
&
only_recorded=1
&
user_id%5B%5D=641f1acb-16b8-42d1-8726-df52979dad0e
&
sequence_number=2
select * from users where team_id = 1 and email like '%stoyan%'
select * from coaching_feedbacks;
select * from teams;
SELECT * FROM users WHERE team_id = 36;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 19
and sa.provider = 'pipedrive';
select * from users where id = 143;
SELECT * FROM users WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
SELECT * FROM teams WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
SELECT * FROM activity_shares WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
select * from users where team_id = 2;
select * from activities where crm_configuration_id = 39
and activities.scheduled_start_time BETWEEN '2025-04-09 00:00:00' AND '2025-04-09 23:59:59'
AND user_id = 143
order by id desc;
# [PASSWORD_DOTS]
select * from teams where id = 142; # 2312, 126
select * from team_settings;
select * from users where team_id = 142; # 21642
SELECT * FROM social_accounts WHERE sociable_id = 21642;
SELECT * FROM crm_profiles cp join users u ON u.id = cp.user_id WHERE team_id = 142;
select * from crm_profiles where id IN (93);
select * from invitations;
select * from team_features where team_id = 1;
SELECT * FROM crm_configurations WHERE id = 126;
select * from accounts where crm_configuration_id = 126 order by id desc;
select * from leads where crm_configuration_id = 126 order by id desc;
select * from contacts where crm_configuration_id = 126 order by id desc;
select * from opportunities where crm_configuration_id = 126 order by id desc;
select * from crm_profiles where crm_configuration_id = 126 order by id desc;
select * from crm_fields where crm_configuration_id = 126 # 11060
# and type IN ('picklist', 'status')
# and object_type = 'task'
order by id desc;
# 5731,5732,5733
select DISTINCT crm_field_id from crm_field_values where crm_field_id IN (11151,12239,12215,12185,12175,12165,12144,12137,12127,12109,12107,12105,12103,12092,12037,12005,12003,11987,11969,11958,11951,11942,11931,11924,11921,11917,11915,11901,11893,11883,11872,11870,11868,11866,11839,11833,11821,11793,11780,11777,11769,11757,11737,11735,11656,11645,11638,11629,11618,11611,11602,11591,11584,11581,11558,11544,11543,11534,11532,11529,11527,11503,11497,11493,11488,11470,11468,11457,11455,11397,11387,11372,11363,11348,11323,11318,11309,11301,11300,11292,11290,11286,11284,11256,11252,11242,11237,11233,11219,11176,11160) order by id desc;
select * from crm_layouts where crm_configuration_id = 126 order by id desc;
SELECT * FROM crm_layout_entities WHERE crm_layout_id in (300,299,298);
select * from stages where crm_configuration_id = 126 order by id desc;
select * from business_processes where crm_configuration_id = 126 order by id desc;
select * from business_process_stages where business_process_id IN (76,75,74,73);
select * from playbooks where team_id = 142;
select * from playbook_layouts where playbook_id IN (108);
SELECT * FROM playbook_categories WHERE playbook_id IN (108);
select * from teams where id = 130;
SELECT * FROM social_accounts WHERE sociable_id = 2291;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 2
and sa.provider = 'hubspot';
SELECT * FROM activities
WHERE crm_configuration_id = 110;
select * from teams;
select * from crm_configurations;
SELECT * FROM activities WHERE id = 628773;
SELECT * FROM crm_profiles WHERE user_id = 1460;
SELECT * FROM social_accounts WHERE sociable_id = 2291;
select * from teams;
select ru.*, pr.*, p.* from users u join role_user ru on ru.user_id = u.id
join permission_role pr on pr.role_id = ru.role_id
join permissions p on p.id = pr.permission_id
where team_id = 495 and p.name IN ('dial');
select * from teams where id = 145;
select * from crm_configurations where id = 129;
select * from social_accounts where sociable_id = 2317;
SELECT * FROM activities WHERE uuid_to_bin('8dbab184-a333-4268-ad57-fb41f8d53a9a') = uuid;
select * from teams where id = 1;
SELECT * FROM crm_layouts WHERE crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 280;
SELECT * FROM crm_layout_entities WHERE id = 5507;
SELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type IN ('event');
select * from teams;
select * from activities where crm_configuration_id = 14;
SELECT * FROM social_accounts where provider = 'copper';
select * from activities where id = 628467;
select * from participants where activity_id = 628467;
SELECT * FROM contacts WHERE id = 3969;
SELECT * FROM accounts WHERE id = 177;
SELECT * FROM activities WHERE uuid_to_bin('4eb54c77-cfa3-2bd4-84a7-9ed46a21c988') = uuid;
# [PASSWORD_DOTS] BH
select * from teams where id = 36;
SELECT * FROM crm_configurations WHERE id = 21;
select * from activities where crm_configuration_id = 21 and id = 607901;
select * from activities where crm_configuration_id = 21;
select * roles;
select * from permissions;
select * from permission_role where permission_id = 226;
select * from migrations order by id desc;
# mercury
# neptune
# earth
select * from teams;
select * from teams where id = 19;
select * from teams where id = 27;
select * from users where team_id = 27;
SELECT * FROM crm_configurations WHERE id = 42;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 19
and sa.provider = 'pipedrive';
select * from activities where id = 631461;
SELECT * FROM crm_field_values WHERE crm_field_id = 180;
select * from teams where id = 2;
SELECT * FROM social_accounts WHERE sociable_id = 89;
SELECT * FROM activities WHERE uuid_to_bin('ba0c029a-bc14-4e17-8603-64174acebcbb') = uuid; # 634273
select * from activity_summary_logs where activity_id = 634273;
select * from sidekick_settings where team_id = 2;
select * from teams; # 2, 2
SELECT * FROM crm_configurations WHERE team_id = 2; # 2
select * from team_features where team_id = 2;
select * from features;
SELECT * FROM opportunities WHERE crm_configuration_id = 2 and crm_provider_id = '51317301383';
SELECT * FROM opportunities WHERE crm_configuration_id = 2 order by id desc;
select * from automated_reports order by id desc;
select * from automated_report_results order by id desc;
select * from users where team_id = 1 and id IN (7160, 3248);
select * from migrations order by id desc;
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 = 1052 and sa.provider = 'hubspot';
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 = 565;
select * from playbooks where team_id = 1;
select * from playbooks where id = 175;
select * from playbook_categories where playbook_id = 175;
select * from users where team_id = 1052;
select * from users where id = 7160;
select * from crm_profiles where user_id = 7160;
select * from features;
select
*
# id, uuid, type, provider, playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id, stage_id,
# crm_configuration_id, crm_provider_id, transcription_id, status
from activities where crm_configuration_id = 1 and type = 'conference'
# and crm_provider_id IS NOT NULL
and provider != 'uploader' and actual_start_time IS NOT NULL
ORDER by id desc;
select * from activities where id = 54747783; # 00UO400000pCzojMAC
select p.id, p.activity_type, pc.id, pc.name
FROM playbooks p
join playbook_categories pc on p.id = pc.playbook_id
where p.team_id = 1 and p.activity_type = 'event';
SELECT * FROM crm_fields WHERE crm_configuration_id = 1 and object_type = 'event';
SELECT * FROM crm_field_values WHERE crm_field_id = 4;
select * from crm_layouts cl join playbook_layouts pl on cl.id = pl.layout_id
where crm_configuration_id = 1 and pl.playbook_id = 175;
select * from teams;
SELECT r.* FROM automated_reports r
join teams t on r.team_id = t.id
WHERE r.frequency = 'daily'
and r.status = 1
AND t.status = 'active'
AND (r.expires_at >= now() OR r.expires_at IS NULL);
select * from automated_report_results where report_id IN (18, 33);
select * from users where team_id = 1 and id = 1047;
SELECT * FROM social_accounts WHERE sociable_id = 1047;
select * from activity_searches where id = 10932;
select * from activity_search_filters where activity_search_id = 10932;
select * from automated_reports order by id desc;
select * from automated_report_results order by id desc;
select * from automated_reports where id IN (55);
select * from automated_report_results where id IN (81);
select * from users where id IN (10633, 13987, 11985);
select * from users where group_id IN (3710);
SELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;
SELECT * FROM automated_report_results WHERE uuid_to_bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;
select * from teams;
select * from accounts where team_id = 1;
select * from automated_report_results where media_type = 'pdf' and status = 2;
SELECT * FROM automated_report_results WHERE uuid_to_bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid;
select * from teams where id = 1029;
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 = 1029 and sa.provider = 'pipedrive';
[
{
"user_id": "23460 (owner)",
"email": "[EMAIL]",
"id": 69,
"sociable_id": 23460,
"provider_user_id": "19555731",
"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,
"refresh_token_expires": null,
"provider": "pipedrive",
"state": "connected",
"auth_scope": "base,deals:full,activities:full,contacts:full,search:read",
"retry_after": null,
"created_at": "2025-04-16 08:23:28",
"updated_at": "2026-05-18 07:13:18",
"provider_user_token_encrypted": "eyJpdiI6Ik9oYzBwcTVteWN4ajBRaDdMb0FjWGc9PSIsInZhbHVlIjoiQUNMbjU5UHR2Q1RnbWRXMEU1TUx6UVpRU3gzdVc5WktmTE4rVlhXa3lRaGhyUUlZMVZRWEJuR0JaWWhZZXNPRlBuanhuYU5MVHZ5TG9NTVVjNjJSUUpZZ2VhbGYxbHg0UzJEdTVmQjNFZnJRZkMwYjd0N2RMZ05GRS9IR3c2K0NoVjBjYTA5UG12SkxHeDlDMGVNN3ptUWUzblFiTngyYzR1eUpHSEYrdEwvZm0yZklGYjBSNEtTR2ZGazhLM1hqT3lVbjFobDNPZ0d3anFlcjhKcXpERlZGOVN1YmFyNDIvM1BFRDFMYnp4WEI4TGVLM2xYcy9CL0RDOWlQNHI3N0NwWnJPMWRtZllmM2ZKeE9TV2NBeDZxL2M1YnlSVzd3ZW96T3F1QmtBYXBHYkUraGcvdCtRajlYZXBjVVBSdFlMUjVPVDVJbDdyenVoWjMrbVJvU3ZZR1dQZ3pqQ3F3aDF2U2xPZWZIN3BCWVFLNXpxQUtDb2pIK0xHc1E3SklSM3Q0VkNSbm9oK2pFK3hLaW54T1dWbEVneUp0RGhhdVBuOFI4MXROc3dZWnFnTUpiaDVMMnZ4QmlRM3k4QWFlMVFWUFYvdGhJQzZBYnhBQmhWa2ZKN1ZhSnhpaExxbmlTemgzUWw3aXJtWjlSMlhmd0lWMDNDN1N3My9Ua0hCL2xqY3RkVFhMSjFJMDRjOE5DWlgrZ3FMVXN6RWlwUE5GWERZdG1xVjVxOFlLRGs2VVJKS3FLeWRxQjYxdDh4Z2JJNXhlWEZ3dkQ4SGtybDNUcndzblFHeVJNRkYraFh2UDFIUTdMQ1BZa3dEU1dBbzk5K0dyT2RNVFBZZUJpRytSck5pYlI1YUZyMmhUNEZCdWxHYmJLREtzbUpjVkhvV0RoejJpbm1SWHlNaXE5M0RhcS94UW9EdFoweWF3bVFVY0dTZWFPSXBmOCtDYndia215cmtyZU1oT0Exam1CV2tPblNhYjY4clVEeUs3anVHUmNHeS9YLzRha1VhbGl3N3lwaDlzZnRhQUZta2s4eFllNHgzRklSRmNyazJ4dlBDMnByNCtBRjNaVjJCTT0iLCJtYWMiOiJkYTQxZDY1OTY2ZTljMTgyZWRhNGEzMGZjZDc2MjBjN2NlNzU2YTViNGQxNWE1NTI2ZmI1MWQyYjQ2ODYxZmEwIiwidGFnIjoiIn0=",
"provider_refresh_token_encrypted": "eyJpdiI6Imt2bGxlSmxUK05GMjF0dEtPaTMrUlE9PSIsInZhbHVlIjoiUXZHTElZRXkreHFxUU02SnZ4eVBacG9WWTRlVkd0USszV3JyVFlpU2ZaY25GSWo2WFcrRzNlbFRlUXRQczNwSXRCcEdvZEpveG9jMzBDSTgwdnZLQnc9PSIsIm1hYyI6ImQxYWI0NzU5Nzg5MDI4YWVhZmQ4Mjg1YzhkZDQzMjRkYWYwYTdhZTY5MDMxMjc0OWNiYjY0Nzc3NDQ0MTEyY2EiLCJ0YWciOiIifQ==",
"encryption_key": "0x01020300786192D9D96DD60D3D1EBC9DFAEE5F0C45EE80165CF3F3D2B3B627026AA7CFC7CA0128DD463535D32EE491ADBADF8B07596B0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040C7FB1319048ECB2EA3F23B995020110802B52D22F5EAD341AB238FBBCB6093156E443876A664BA5555D722565C2B2D04422C868CD7350555E3CC74221",
"sociable_type": "user",
"owner_id": 23460
},
{
"user_id": "23463",
"email": "[EMAIL]",
"id": 72,
"sociable_id": 23463,
"provider_user_id": "23270841",
"provider_user_token": "v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:txqCuWLeVhgwiaFqXIvQWWrtrnFIy_4lT3VCr-sRB4g6_2lK8KcQ_6ka_qFmZhr-IeIAKmAImx6H1iIKx4Ab7XZ5MnKIh03GKbHjI0n0rGT9UYkeH21jKOxJvKaSX_TyLbxFPR6irPQyvqcpBClXI52gVJH01KzZy_dMTHFXhhDLOIhEpSrQXHG7Qo8q7OuBeSPZrU1ALi9kmAm4GTpzGTbzfl-hUt9IAfPunJOCyv3mf2Tl-MT8EyQgOFPrsP3yz9UlSyVhb40zO_bCnUrqNxjwgm_E6vgpVrwULTQbHe-43Dq-TRetjceUzT88GBgVJ0UdxXP5BRBVXcL5ir8-9ZTMaNU",
"provider_refresh_token": "5034113:[TELEGRAM_TOKEN]78ad1",
"expires": 1753837219,
"refresh_token_expires": null,
"provider": "pipedrive",
"state": "full-refresh",
"auth_scope": "base,deals:full,activities:full,contacts:full,search:read",
"retry_after": null,
"created_at": "2025-04-16 10:41:12",
"updated_at": "2025-07-30 01:00:17",
"provider_user_token_encrypted": "eyJpdiI6InVEVEl2SzIxMjd1bkNDWG9lY3YvQ0E9PSIsInZhbHVlIjoiRlJLbDZ3ZHo2dHMxUWQwdGU2YUZjV3lPWHlxQTJ0eWh4S0RTMjlSaThVcktoaWhXcTd2UXl4Mjg4bW5UUnZCZEQ5NXpuQTVKOURiMDNIa3l3K0lSWCt5azRBOEdHbitWQXhxeEpMVUZ1dnF2NVl1TTZLelZOaGNvRlBLeGpIWlpoRGloUEprd2xoNUFPcTlLcUd3WVlUU2svR1NOeXBYQ2NnMWhnK1V2aytOeVVMNzJGdVZXMU1JS3BSaGNCcmxkVjEwQ01mQXNBdWNhS1lMZWZobnZwcHBkN1R4bUVDRUNYdnNtSVJkdG5MdkN3djJBT0hMRDl1MHFGbnl4WU13ejBkUWsrdUljWkZhcTJlN0JDSGdTVzlPY0FGMUJlZi9WRGpkMUk5R20wblYwSk9VR2FuaHpLTzJNeitMbnF1V1NEMUUxRmYzaDRGZDMyaXd3Z0FjQno4SzVoYjUyTmV3UXNpRlF4TGZKNVl3dUFqdGhKVWJjRVlUUXRGalBpaXJvSGJmbS8rd25aQ2Zvc05saHRDRjlHV1VEUFFiRU5xbWRVNkxFSXV0RUZyaUlYNWMwMmhnZ0Y1VUQ4eEFkY2QyWXpnR0NidkVJSWdjVGljUjA3NDdpZW9WUHhtSlpGSGdNU2hRUTA5ZW03RGpiRFdrdytkOHJXSUxlazZNaG9iaUg2NFZYdEc3YklMeFZvblBzWmVRSDcvN2M4WUNtL3h4S2IrUW00cXhialBia3BJcW5XallBNlV5WWdhcE1ZVFBBM3RSSUVBamYvOGZEQWM5a2FJMGwyWkRSU3dlTEtPemZlQ3RXRGNDcEdYRHdMNTlTQVg2SUdUN0hVaXdZT1dUOUlrVzkrZHFBemhwWXg1cm4rSy9UOHUzcnNSM2dISlhBRTEyVUNyTkZYaFJYUlN1a2RKVHhhM2dHckR3a1JGaVZ2Wk9BVnhTclVpSEhwWTVpQTlJbXVkOUxSTGpRbDk0a1VtbE9QMVAvN3VlVEhJUHd2elowd0laNVIzZ3M3N0ZOK0NDakIwQ2FicGxoMDBhTXI0VUppUmFOZHdlWUdGV21NNFQ4RU1nY0dnWT0iLCJtYWMiOiI0ZTU4ZmJkNTdkYmY0NGE4NTJjZjlhNDExNzE2YjhlOWM2NTA5OGY2MDA4OTcyZDVlOTljY2JjZDhmMjBhMDUyIiwidGFnIjoiIn0=",
"provider_refresh_token_encrypted": "eyJpdiI6IkJGMkdRVHRKM2VTcitKNGcvQWJtUGc9PSIsInZhbHVlIjoicmFyRkxPZ1Rybm1ORXlEVjJ2TXFGTzJtM3hWaFhnUVVHN2ZlR1lRM0I5d3ozbnZTcU5EdzJqRkI2elhyNWhlenRTUXV3bjk0N1JXeklDMVAyUzBKcHc9PSIsIm1hYyI6ImJhODVjMGQyZDE3Y2ExNjc2OWVjYWJiNmFjYWVkODIyMTMyNWVhYTExMTgwYTEyMTU0MzUzZGE1YjQ5YzQ5ZjEiLCJ0YWciOiIifQ==",
"encryption_key": "0x01020300788C37CDF66ABE9301A68D5D4866AC0C197E04EEE4D904F20A59991322EBAE252301BEF4B24FF01359E934E5654617E4EEAC0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040CEB00EF45BDEA999A5558889E020110802B925F372F7BEFAF0B45E48686113D1DA430ECFCC07B1F61BA6828CC44235278EDB05C486E8068D0BE737D91",
"sociable_type": "user",
"owner_id": 23460
}
]
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
53220
|
NULL
|
NULL
|
NULL
|
|
53221
|
1866
|
10
|
2026-05-18T11:52:01.203993+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779105121203_m1.jpg...
|
PhpStorm
|
faVsco.js – Constants.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
namespace Jiminny\Component\SCIM;
use Jiminny\Component\SCIM\Builders\Filters;
class Constants
{
/**
* HTTP codes
*/
public const HTTP_OK = 200;
public const HTTP_CREATED = 201;
public const HTTP_NO_CONTENT = 204;
public const HTTP_NOT_FOUND = 404;
public const HTTP_BAD_REQUEST = 400;
public const HTTP_ACCESS_DENIED = 403;
public const HTTP_ERROR = 501;
/**
* Users resource constants
*/
public const USER_FIRST_NAME = 'givenName';
public const USER_FAMILY_NAME = 'familyName';
public const USER_STATUS = 'Active';
public const USER_USERNAME = 'UserName';
public const USER_EXTERNAL_ID = 'externalId';
public const USER_FIELDS = [
self::USER_FIRST_NAME,
self::USER_FAMILY_NAME,
self::USER_STATUS,
self::USER_USERNAME,
];
public const META_OPERATIONS_REPLACE = 'replace';
public const META_OPERATIONS_REPLACE_UPPER = 'Replace';
public const META_OPERATIONS_ADD = 'add';
public const META_OPERATIONS_ADD_UPPER = 'Add';
public const META_OPERATIONS_REMOVE_UPPER = 'Remove';
public const META_OPERATIONS_REMOVE = 'remove';
public const META_ID = 'id';
public const META_PHONE_NUMBERS = 'phoneNumbers';
public const META_TITLE = 'title';
public const META_ROLES = 'roles';
public const META_PATH = 'path';
public const META_ENTERPRISE_SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';
public const META_DEPARTMENT = 'department';
public const META_META = 'meta';
public const META_TYPE = 'type';
public const META_VALUE = 'value';
public const META_OPERATIONS = 'Operations';
public const META_OP = 'op';
public const META_RESOURCE_TYPE = 'resourceType';
public const META_CREATED = 'created';
public const META_LAST_MODIFIED = 'lastModified';
public const META_FORMATTED = 'formatted';
public const META_EMAILS = 'emails';
public const META_USERNAME = 'userName';
public const META_NAME = 'name';
public const META_STATUS = 'active';
public const META_PRIMARY = 'primary';
public const META_ERROR_STATUS = 'status';
public const META_ERROR_DETAIL = 'detail';
public const META_LIST_TOTAL_RESULTS = 'totalResults';
public const META_LIST_RESOURCES = 'Resources';
public const META_LIST_START_INDEX = 'startIndex';
public const META_LIST_COUNT = 'count';
public const META_LIST_ITEMS_PER_PAGE = 'itemsPerPage';
public const META_SCHEMAS = 'schemas';
public const META_FILTER = 'filter';
public const META_TYPE_WORK = 'work';
public const META_PHONE_NUMBER_TYPE_MOBILE = 'mobile';
public const META_EMAIL_TYPE_HOME = 'home';
public const META_CONTAINER_NAME = 'name';
public const META_CONTAINER_EMAILS = 'emails';
public const RESOURCE_TYPE_USER = 'User';
public const USER_PATCH_ATTR_TITLE = 'title';
public const USER_PATCH_ATTR_ACTIVE = 'active';
public const USER_PATCH_ATTR_USERNAME = 'userName';
public const USER_PATCH_ATTR_FIRST_NAME = 'name.givenName';
public const USER_PATCH_ATTR_LAST_NAME = 'name.familyName';
public const USER_PATCH_ATTR_PRIMARY_EMAIL = 'emails[type eq "work"].value';
public const USER_PATCH_ATTR_SECONDARY_EMAIL = 'emails[type eq "home"].value';
public const USER_PATCH_ATTR_PHONE_NUMBER = 'phoneNumbers[type eq "work"].value';
public const USER_PATCH_ATTR_PHONE_NUMBER_MOBILE = 'phoneNumbers[type eq "mobile"].value';
public const USER_PATCH_ATTR_ROLES = 'roles';
public const USER_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [
self::USER_PATCH_ATTR_TITLE => Mutators\Attributes\User\TitleAttr::class,
self::USER_PATCH_ATTR_ACTIVE => Mutators\Attributes\User\ActiveAttr::class,
self::USER_PATCH_ATTR_USERNAME => Mutators\Attributes\User\UsernameAttr::class,
self::USER_PATCH_ATTR_FIRST_NAME => Mutators\Attributes\User\FirstNameAttr::class,
self::USER_PATCH_ATTR_LAST_NAME => Mutators\Attributes\User\LastNameAttr::class,
self::USER_PATCH_ATTR_PRIMARY_EMAIL => Mutators\Attributes\User\PrimaryEmailAttr::class,
self::USER_PATCH_ATTR_SECONDARY_EMAIL => Mutators\Attributes\User\SecondaryEmailAttr::class,
self::USER_PATCH_ATTR_PHONE_NUMBER => Mutators\Attributes\User\PhoneNumberPrimaryAttr::class,
self::USER_PATCH_ATTR_PHONE_NUMBER_MOBILE => Mutators\Attributes\User\PhoneNumberSecondaryAttr::class,
self::USER_PATCH_ATTR_ROLES => Mutators\Attributes\User\RoleAttr::class,
];
public const FILTER_OPERATOR_EQ = 'eq';
public const SUPPORTED_FILTERS_OPERATORS = [
self::FILTER_OPERATOR_EQ,
];
public const USER_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [
self::USER_FILTER_LOCAL_ID => Filters\User\LocalIdFilter::class,
self::USER_FILTER_USERNAME => Filters\User\UserNameFilter::class,
self::USER_FILTER_FIRST_NAME => Filters\User\FirstNameFilter::class,
self::USER_FILTER_LAST_NAME => Filters\User\LastNameFilter::class,
self::USER_FILTER_EXTERNAL_ID => Filters\User\ExternalIdFilter::class,
self::USER_FILTER_DISPLAY_NAME => Filters\User\DisplayNameFilter::class,
];
public const USER_FILTER_LOCAL_ID = 'id';
public const USER_FILTER_USERNAME = 'userName';
public const USER_FILTER_FIRST_NAME = 'givenName';
public const USER_FILTER_LAST_NAME = 'familyName';
public const USER_FILTER_EXTERNAL_ID = 'externalId';
public const USER_FILTER_DISPLAY_NAME = 'DisplayName';
public const SCIM_SUPPORTED_RESOURCES = [
self::USER_RESOURCE_PREFIX,
self::GROUP_RESOURCE_PREFIX,
];
public const USER_RESOURCE_PREFIX = 'Users';
public const GROUP_RESOURCE_PREFIX = 'Groups';
public const OUTGOING_SCHEMAS_SUPPORTED = [
self::OUTGOING_CORE_USER,
];
/**
* Outgoing supported schemas
*/
public const OUTGOING_CORE_USER = 'urn:ietf:params:scim:schemas:core:2.0:User';
public const OUTGOING_ERROR = 'urn:ietf:params:scim:api:messages:2.0:Error';
public const OUTGOING_LIST_RESPONSE = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';
public const OUTGOING_CORE_GROUP = 'urn:ietf:params:scim:schemas:core:2.0:Group';
/**
* Groups resource constants
*/
public const GROUP_ATTRIBUTE_DISPLAY_NAME = 'displayName';
public const GROUP_ATTRIBUTE_EXTERNAL_ID = 'externalId';
public const GROUP_ATTRIBUTE_ID = 'id';
public const RESOURCE_TYPE_GROUP = 'Group';
public const GROUP_FILTER_QUERY_NAME = 'filter';
public const GROUP_EXCLUDED_ATTRIBUTES = 'excludedAttributes';
public const GROUP_SUPPORTED_FILTER_ATTRIBUTES = [
self::GROUP_ATTRIBUTE_DISPLAY_NAME,
];
public const GROUP_MEMBERS = 'members';
public const SUPPORTED_PATCH_OPERATIONS = [
self::META_OPERATIONS_ADD,
self::META_OPERATIONS_REPLACE,
self::META_OPERATIONS_REMOVE,
];
public const GROUP_PATCH_ATTRIBUTE_MEMBERS = 'members';
public const GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME = 'displayName';
public const GROUP_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [
self::GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME => Mutators\Attributes\Group\DisplayNameAttr::class,
self::GROUP_PATCH_ATTRIBUTE_MEMBERS => Mutators\Attributes\Group\MembersAttr::class,
];
public const GROUP_FILTER_DISPLAY_NAME = 'displayname';
public const GROUP_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [
self::GROUP_FILTER_DISPLAY_NAME => Filters\Group\DisplayNameFilter::class,
];
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny_jupiter
Sync Changes
Hide This Notification
Code changed:
Hide
19
19
17
Previous Highlighted Error
Next Highlighted Error
SELECT * FROM teams WHERE id = 1;
select * from crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 283;
SELECT * FROM crm_fields WHERE id = 2234;
SELECT * FROM crm_field_values WHERE crm_field_id = 2234;
select * from crm_profiles where user_id = 143;
select * from record_types where crm_configuration_id = 39; # 0121K000001MHElQAO,0121K000001MHEqQAO
select * from business_processes where crm_configuration_id = 39;
# 01941000000H669AAC, 01941000000H66JAAS
select * from record_type_field_values
where record_type_id IN (24);
select * from crm_field_values where id IN (2730);
select * from crm_configurations where id = 39;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce'; #1035
select * from users where team_id = 1; # 222 group 3
SELECT * FROM activities WHERE user_id = 222 order by id desc;
select * from sidekick_settings where team_id = 1;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from activities where crm_configuration_id = 2
and provider = 'ms-teams' and id = 608765;
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id = '59523413338';
select * from sidekick_settings where team_id = 2;
SELECT * FROM activities WHERE id = 608660;
select * from activity_summary_logs where activity_id = 608660;
select * from ai_prompts where transcription_id = 11214;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('ed78a437-2804-450e-ab2f-56ab1c641346') = uuid;
# id: 608818, crm: 59628809737
SELECT * FROM activities WHERE uuid_to_bin('36b06e55-afdd-4782-8dee-c624cd0af191') = uuid;
# id: 608821, crm: 59632069252
SELECT ce.start_time, ce.end_time, a.id, a.uuid, crm_provider_id, calendar_event_id, title,
playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id,
scheduled_start_time, scheduled_end_time, actual_start_time, actual_end_time, a.created_at
FROM activities a
join calendar_events ce on a.calendar_event_id = ce.id
WHERE a.id IN (608818, 608821);
select * from users where team_id = 1;
select * from team_settings where team_id = 1;
select * from crm_profiles where crm_configuration_id = 39 order by user_id;
select * from team_features where team_id = 1;
select * from users where team_id = 2;
SELECT * FROM activities WHERE uuid_to_bin('ec7647e9-5225-458b-b475-f31aa2769204') = uuid; # 612639
# Preslava N. Ivanova, grou id 3
SELECT * FROM opportunities WHERE uuid_to_bin('a2928fe5-aec5-46cb-85d9-7654c89e46a6') = uuid;
select * from activities where opportunity_id = 344 and actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00';
select
a.id,
a.type,
a.scheduled_start_time,
a.actual_start_time,
a.created_at,
a.opportunity_id,
a.status
FROM activities a
WHERE opportunity_id = 344
and status IN ('completed', 'received', 'delivered')
and (
(a.actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')
OR (a.created_at between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')
OR (a.scheduled_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00'))
;
SELECT * FROM users WHERE id = 222;
SELECT * FROM crm_profiles WHERE user_id = 222;
select * from crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 281;
select * from group_deal_risk_types;
select * from opportunities where team_id = 1;
SELECT * FROM opportunities WHERE id = 315;
SELECT * FROM crm_field_data WHERE object_id = 315;
select * from crm_field_data where object_id = 260;
select * from generic_ai_prompts where subject_id = 315;
select * from teams; # 36, 21, 121, [EMAIL]
SELECT * FROM social_accounts WHERE sociable_id = 121 and provider = 'bullhorn';
# [PASSWORD_DOTS]
select * from teams where id = 1;
select * from crm_configurations where id = 39;
select * from users where team_id = 1;
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 1;
# 1 - 00541000004281rAAA
# 204 - 0052g000003freeAAA
# 429 - 0052g000003qGOiAAM
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce';
select * from activities where type = 'softphone'
and created_at > '2024-12-11 15:24:36' order by id desc;
select * from activity_providers where team_id = 1;
select * from activity_provider_users where activity_provider_id = 328;
select * from opportunities where crm_configuration_id = 39
AND account_id = 178 AND is_closed = false
order by created_at DESC;
select * from contacts where id = 3952;
select * from accounts where id = 178;
# [PASSWORD_DOTS]
select * from teams where id = 36;
select * from crm_configurations where id = 21;
select * from users where team_id = 36;
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 36;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 36
and sa.provider = 'bullhorn';
select * from social_accounts where id = 348;
UPDATE social_accounts SET
provider_user_token = '21442_6802599_91:41179a58-21e7-4d7c-ad58-56bb666b2f65',
provider_refresh_token = '21442_6802599_91:01c6b335-3f2a-42e4-85ff-8a08fa65fceb',
expires = 1733998131,
state = 'connected'
WHERE id = 348;
# [PASSWORD_DOTS]
select * from teams where id = 31;
select * from crm_configurations where id = 18;
select * from users where team_id = 31; # 257
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 31;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 31
and sa.provider = 'close';
select * from contacts where crm_configuration_id = 18;
# [PASSWORD_DOTS] NEPTUNE [PASSWORD_DOTS]
select * from teams;
select * from users where id IN (1030, 1035, 1052);
select * from crm_configurations;
select * from users where team_id = 65; # 257
select * from team_settings where team_id = 65; # 257
select * from invitations where team_id = 65; # 257
select * from users where email = '[EMAIL]'; # 257
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 65;
select * from crm_configurations where id = 53;
select * from accounts where crm_configuration_id = 53 order by id desc;
select * from leads where crm_configuration_id = 53 order by id desc;
select * from contacts where crm_configuration_id = 53 order by id desc;
select * from opportunities where crm_configuration_id = 53 order by id desc;
select * from crm_profiles where crm_configuration_id = 53 order by id desc;
select * from crm_fields where crm_configuration_id = 53 order by id desc;
select * from crm_field_values where crm_field_id = 3341 order by id desc;
select * from crm_layouts where crm_configuration_id = 53 order by id desc;
select * from stages where crm_configuration_id = 53 order by id desc;
select * from crm_profiles where crm_configuration_id = 13;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 65
and sa.provider = 'integration-app';
select * from contacts where crm_configuration_id = 13;
select * from social_accounts where sociable_id = 283;
SELECT * FROM opportunities WHERE crm_provider_id = '006O400000E9bzeIAB';
select * from activity_providers where team_id = 65;
SELECT * FROM activities WHERE crm_configuration_id IN (51, 52, 53);
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 65
;
# [PASSWORD_DOTS] STAGING [PASSWORD_DOTS]
SELECT * FROM teams;
SELECT * FROM teams WHERE id = 88;
SELECT * FROM teams WHERE id = 89;
select * from team_settings where team_id = 89;
SELECT * FROM users WHERE team_id = 89;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 89;
select * from users;
SELECT * FROM social_accounts WHERE sociable_id = 1761;
SELECT * FROM crm_configurations WHERE id = 70;
select * from accounts where crm_configuration_id = 70 order by id desc;
select * from leads where crm_configuration_id = 70 order by id desc;
select * from contacts where crm_configuration_id = 70 order by id desc;
select * from opportunities where crm_configuration_id = 70 order by id desc;
select * from crm_profiles where crm_configuration_id = 70 order by id desc;
select * from crm_fields where crm_configuration_id = 70 order by id desc;
select * from crm_field_values where crm_field_id = 3536 order by id desc;
select * from crm_layouts where crm_configuration_id = 70 order by id desc;
select * from stages where crm_configuration_id = 70 order by id desc;
select * from business_processes where crm_configuration_id = 70 order by id desc;
select * from business_process_stages where business_process_id = 34;
select * from contacts where id = 10468;
select * from crm_layouts where crm_configuration_id = 70;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 388;
SELECT * FROM crm_fields WHERE id IN (3533,3534,3535);
select * from activities where crm_configuration_id = 70
and (account_id IS NOT NULL or lead_id IS NOT NULL or contact_id IS NOT NULL or opportunity_id IS NOT NULL) order by id desc;
SELECT * FROM activities WHERE uuid_to_bin('2e10b60f-8a61-41c5-a3d4-28835353dc65') = uuid;
SELECT * FROM activities where crm_configuration_id = 69 ;
SELECT * FROM users WHERE email LIKE '%[EMAIL]%';
SELECT * FROM activities WHERE uuid_to_bin('5a150c93-40fc-42ec-b3bd-c1d328e09f6e') = uuid;
SELECT * FROM opportunities WHERE id = 385;
select * from participants p
join activities a on p.activity_id = a.id
where a.crm_configuration_id = 70
and (p.lead_id IS NOT NULL or p.contact_id IS NOT NULL);
SELECT * FROM participants WHERE id = 1013638;
select * from teams where id = 90;
select * from users where team_id = 90;
select * from social_accounts where social_accounts.sociable_id IN (1960,1760);
SELECT * FROM crm_profiles WHERE crm_configuration_id = 71;
select * from invitations where team_id = 90;
select * from crm_configurations where id = 71;
select * from accounts where crm_configuration_id = 71 order by id desc;
select * from leads where crm_configuration_id = 71 order by id desc;
select * from contacts where crm_configuration_id = 71 order by id desc;
select * from opportunities where crm_configuration_id = 71 order by id desc;
select * from crm_profiles where crm_configuration_id = 71 order by id desc;
select * from crm_fields where crm_configuration_id = 71 order by id desc;
select * from crm_field_values where crm_field_id = 3341 order by id desc;
select * from crm_layouts where crm_configuration_id = 71 order by id desc;
select * from stages where crm_configuration_id = 71 order by id desc;
select * from users order by secondary_email desc;
select u.id, u.email, u.status, sa.id, sa.provider_user_id from social_accounts sa
join users u on sa.sociable_id = u.id
where sa.provider = 'google' and u.email LIKE 'aneliya%';
select * from failed_jobs order by id desc;
select * from users where email = '[EMAIL]' or secondary_email = '[EMAIL]';
select * from teams;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 39;
SELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type = 'task';
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce';
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('c38b3895-fd0f-4b1f-9fb2-c170dba137c6') = uuid;
SELECT * FROM crm_configurations WHERE id = 70;
select * from teams where id = 1;
select * from groups where team_id = 1;
select * from users where team_id = 1;
select o.id, o.name,o.close_date, u.id, u.name, u.group_id, r.id, r.display_name, g.name, g.scope from opportunities o
join users u on o.user_id = u.id
join groups g on u.group_id = g.id
join role_user ru on u.id = ru.user_id
join roles r on ru.role_id = r.id
where o.crm_configuration_id = 39 and close_date > '2024-01-01 00:00:00';
select * from role_user where user_id = 143;
select * from roles;
select * from role_user;
select * from groups where id = 9;
select * from scope_groups where group_id = 9;
# [PASSWORD_DOTS]
select * from teams where id = 36;
select * from crm_configurations;
SELECT * FROM social_accounts WHERE sociable_id = 121;
https://crmsandbox.zoho.com/crm/jiminnyw4/tab/Leads/4776201000005049105
https://crmsandbox.zoho.com/crm/
https://crm.zoho.com/crm/org3469620/tab/Leads/230045000229559080
https://crm.zoho.com/crm/
org3469620
SELECT * FROM activities WHERE uuid_to_bin('03382d20-c8bc-48e7-a3d4-90b52fa5ceab') = uuid;
select * from users where email LIKE "%mobile_automation_%";
select * from social_accounts where sociable_id IN (2228);
select * from crm_profiles where user_id IN (2222,2223,2226,2227);
select * from teams order by id desc;
SELECT * FROM users WHERE id = 2229;
SELECT * FROM crm_profiles WHERE user_id = 2229;
select * from opportunities where crm_configuration_id = 88;
select * from crm_fields where crm_configuration_id = 88;
select * from crm_profiles where crm_configuration_id = 88;
SELECT * FROM teams WHERE id = 1;
SELECT * FROM users WHERE id = 143;
SELECT * FROM users WHERE uuid_to_bin('fde193d3-06a2-4e1a-8895-62b94039215d') = uuid;
SELECT * FROM teams WHERE uuid_to_bin('73385071-a756-42ae-9c73-8b53f2309467') = uuid;
https://app.staging.jiminny.com/ondemand?
min_duration=1
&
only_recorded=1
&
user_id%5B%5D=641f1acb-16b8-42d1-8726-df52979dad0e
&
sequence_number=2
select * from users where team_id = 1 and email like '%stoyan%'
select * from coaching_feedbacks;
select * from teams;
SELECT * FROM users WHERE team_id = 36;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 19
and sa.provider = 'pipedrive';
select * from users where id = 143;
SELECT * FROM users WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
SELECT * FROM teams WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
SELECT * FROM activity_shares WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
select * from users where team_id = 2;
select * from activities where crm_configuration_id = 39
and activities.scheduled_start_time BETWEEN '2025-04-09 00:00:00' AND '2025-04-09 23:59:59'
AND user_id = 143
order by id desc;
# [PASSWORD_DOTS]
select * from teams where id = 142; # 2312, 126
select * from team_settings;
select * from users where team_id = 142; # 21642
SELECT * FROM social_accounts WHERE sociable_id = 21642;
SELECT * FROM crm_profiles cp join users u ON u.id = cp.user_id WHERE team_id = 142;
select * from crm_profiles where id IN (93);
select * from invitations;
select * from team_features where team_id = 1;
SELECT * FROM crm_configurations WHERE id = 126;
select * from accounts where crm_configuration_id = 126 order by id desc;
select * from leads where crm_configuration_id = 126 order by id desc;
select * from contacts where crm_configuration_id = 126 order by id desc;
select * from opportunities where crm_configuration_id = 126 order by id desc;
select * from crm_profiles where crm_configuration_id = 126 order by id desc;
select * from crm_fields where crm_configuration_id = 126 # 11060
# and type IN ('picklist', 'status')
# and object_type = 'task'
order by id desc;
# 5731,5732,5733
select DISTINCT crm_field_id from crm_field_values where crm_field_id IN (11151,12239,12215,12185,12175,12165,12144,12137,12127,12109,12107,12105,12103,12092,12037,12005,12003,11987,11969,11958,11951,11942,11931,11924,11921,11917,11915,11901,11893,11883,11872,11870,11868,11866,11839,11833,11821,11793,11780,11777,11769,11757,11737,11735,11656,11645,11638,11629,11618,11611,11602,11591,11584,11581,11558,11544,11543,11534,11532,11529,11527,11503,11497,11493,11488,11470,11468,11457,11455,11397,11387,11372,11363,11348,11323,11318,11309,11301,11300,11292,11290,11286,11284,11256,11252,11242,11237,11233,11219,11176,11160) order by id desc;
select * from crm_layouts where crm_configuration_id = 126 order by id desc;
SELECT * FROM crm_layout_entities WHERE crm_layout_id in (300,299,298);
select * from stages where crm_configuration_id = 126 order by id desc;
select * from business_processes where crm_configuration_id = 126 order by id desc;
select * from business_process_stages where business_process_id IN (76,75,74,73);
select * from playbooks where team_id = 142;
select * from playbook_layouts where playbook_id IN (108);
SELECT * FROM playbook_categories WHERE playbook_id IN (108);
select * from teams where id = 130;
SELECT * FROM social_accounts WHERE sociable_id = 2291;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 2
and sa.provider = 'hubspot';
SELECT * FROM activities
WHERE crm_configuration_id = 110;
select * from teams;
select * from crm_configurations;
SELECT * FROM activities WHERE id = 628773;
SELECT * FROM crm_profiles WHERE user_id = 1460;
SELECT * FROM social_accounts WHERE sociable_id = 2291;
select * from teams;
select ru.*, pr.*, p.* from users u join role_user ru on ru.user_id = u.id
join permission_role pr on pr.role_id = ru.role_id
join permissions p on p.id = pr.permission_id
where team_id = 495 and p.name IN ('dial');
select * from teams where id = 145;
select * from crm_configurations where id = 129;
select * from social_accounts where sociable_id = 2317;
SELECT * FROM activities WHERE uuid_to_bin('8dbab184-a333-4268-ad57-fb41f8d53a9a') = uuid;
select * from teams where id = 1;
SELECT * FROM crm_layouts WHERE crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 280;
SELECT * FROM crm_layout_entities WHERE id = 5507;
SELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type IN ('event');
select * from teams;
select * from activities where crm_configuration_id = 14;
SELECT * FROM social_accounts where provider = 'copper';
select * from activities where id = 628467;
select * from participants where activity_id = 628467;
SELECT * FROM contacts WHERE id = 3969;
SELECT * FROM accounts WHERE id = 177;
SELECT * FROM activities WHERE uuid_to_bin('4eb54c77-cfa3-2bd4-84a7-9ed46a21c988') = uuid;
# [PASSWORD_DOTS] BH
select * from teams where id = 36;
SELECT * FROM crm_configurations WHERE id = 21;
select * from activities where crm_configuration_id = 21 and id = 607901;
select * from activities where crm_configuration_id = 21;
select * roles;
select * from permissions;
select * from permission_role where permission_id = 226;
select * from migrations order by id desc;
# mercury
# neptune
# earth
select * from teams;
select * from teams where id = 19;
select * from teams where id = 27;
select * from users where team_id = 27;
SELECT * FROM crm_configurations WHERE id = 42;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 19
and sa.provider = 'pipedrive';
select * from activities where id = 631461;
SELECT * FROM crm_field_values WHERE crm_field_id = 180;
select * from teams where id = 2;
SELECT * FROM social_accounts WHERE sociable_id = 89;
SELECT * FROM activities WHERE uuid_to_bin('ba0c029a-bc14-4e17-8603-64174acebcbb') = uuid; # 634273
select * from activity_summary_logs where activity_id = 634273;
select * from sidekick_settings where team_id = 2;
select * from teams; # 2, 2
SELECT * FROM crm_configurations WHERE team_id = 2; # 2
select * from team_features where team_id = 2;
select * from features;
SELECT * FROM opportunities WHERE crm_configuration_id = 2 and crm_provider_id = '51317301383';
SELECT * FROM opportunities WHERE crm_configuration_id = 2 order by id desc;
select * from automated_reports order by id desc;
select * from automated_report_results order by id desc;
select * from users where team_id = 1 and id IN (7160, 3248);
select * from migrations order by id desc;
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 = 1052 and sa.provider = 'hubspot';
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 = 565;
select * from playbooks where team_id = 1;
select * from playbooks where id = 175;
select * from playbook_categories where playbook_id = 175;
select * from users where team_id = 1052;
select * from users where id = 7160;
select * from crm_profiles where user_id = 7160;
select * from features;
select
*
# id, uuid, type, provider, playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id, stage_id,
# crm_configuration_id, crm_provider_id, transcription_id, status
from activities where crm_configuration_id = 1 and type = 'conference'
# and crm_provider_id IS NOT NULL
and provider != 'uploader' and actual_start_time IS NOT NULL
ORDER by id desc;
select * from activities where id = 54747783; # 00UO400000pCzojMAC
select p.id, p.activity_type, pc.id, pc.name
FROM playbooks p
join playbook_categories pc on p.id = pc.playbook_id
where p.team_id = 1 and p.activity_type = 'event';
SELECT * FROM crm_fields WHERE crm_configuration_id = 1 and object_type = 'event';
SELECT * FROM crm_field_values WHERE crm_field_id = 4;
select * from crm_layouts cl join playbook_layouts pl on cl.id = pl.layout_id
where crm_configuration_id = 1 and pl.playbook_id = 175;
select * from teams;
SELECT r.* FROM automated_reports r
join teams t on r.team_id = t.id
WHERE r.frequency = 'daily'
and r.status = 1
AND t.status = 'active'
AND (r.expires_at >= now() OR r.expires_at IS NULL);
select * from automated_report_results where report_id IN (18, 33);
select * from users where team_id = 1 and id = 1047;
SELECT * FROM social_accounts WHERE sociable_id = 1047;
select * from activity_searches where id = 10932;
select * from activity_search_filters where activity_search_id = 10932;
select * from automated_reports order by id desc;
select * from automated_report_results order by id desc;
select * from automated_reports where id IN (55);
select * from automated_report_results where id IN (81);
select * from users where id IN (10633, 13987, 11985);
select * from users where group_id IN (3710);
SELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;
SELECT * FROM automated_report_results WHERE uuid_to_bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;
select * from teams;
select * from accounts where team_id = 1;
select * from automated_report_results where media_type = 'pdf' and status = 2;
SELECT * FROM automated_report_results WHERE uuid_to_bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid;
select * from teams where id = 1029;
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 = 1029 and sa.provider = 'pipedrive';
[
{
"user_id": "23460 (owner)",
"email": "[EMAIL]",
"id": 69,
"sociable_id": 23460,
"provider_user_id": "19555731",
"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,
"refresh_token_expires": null,
"provider": "pipedrive",
"state": "connected",
"auth_scope": "base,deals:full,activities:full,contacts:full,search:read",
"retry_after": null,
"created_at": "2025-04-16 08:23:28",
"updated_at": "2026-05-18 07:13:18",
"provider_user_token_encrypted": "eyJpdiI6Ik9oYzBwcTVteWN4ajBRaDdMb0FjWGc9PSIsInZhbHVlIjoiQUNMbjU5UHR2Q1RnbWRXMEU1TUx6UVpRU3gzdVc5WktmTE4rVlhXa3lRaGhyUUlZMVZRWEJuR0JaWWhZZXNPRlBuanhuYU5MVHZ5TG9NTVVjNjJSUUpZZ2VhbGYxbHg0UzJEdTVmQjNFZnJRZkMwYjd0N2RMZ05GRS9IR3c2K0NoVjBjYTA5UG12SkxHeDlDMGVNN3ptUWUzblFiTngyYzR1eUpHSEYrdEwvZm0yZklGYjBSNEtTR2ZGazhLM1hqT3lVbjFobDNPZ0d3anFlcjhKcXpERlZGOVN1YmFyNDIvM1BFRDFMYnp4WEI4TGVLM2xYcy9CL0RDOWlQNHI3N0NwWnJPMWRtZllmM2ZKeE9TV2NBeDZxL2M1YnlSVzd3ZW96T3F1QmtBYXBHYkUraGcvdCtRajlYZXBjVVBSdFlMUjVPVDVJbDdyenVoWjMrbVJvU3ZZR1dQZ3pqQ3F3aDF2U2xPZWZIN3BCWVFLNXpxQUtDb2pIK0xHc1E3SklSM3Q0VkNSbm9oK2pFK3hLaW54T1dWbEVneUp0RGhhdVBuOFI4MXROc3dZWnFnTUpiaDVMMnZ4QmlRM3k4QWFlMVFWUFYvdGhJQzZBYnhBQmhWa2ZKN1ZhSnhpaExxbmlTemgzUWw3aXJtWjlSMlhmd0lWMDNDN1N3My9Ua0hCL2xqY3RkVFhMSjFJMDRjOE5DWlgrZ3FMVXN6RWlwUE5GWERZdG1xVjVxOFlLRGs2VVJKS3FLeWRxQjYxdDh4Z2JJNXhlWEZ3dkQ4SGtybDNUcndzblFHeVJNRkYraFh2UDFIUTdMQ1BZa3dEU1dBbzk5K0dyT2RNVFBZZUJpRytSck5pYlI1YUZyMmhUNEZCdWxHYmJLREtzbUpjVkhvV0RoejJpbm1SWHlNaXE5M0RhcS94UW9EdFoweWF3bVFVY0dTZWFPSXBmOCtDYndia215cmtyZU1oT0Exam1CV2tPblNhYjY4clVEeUs3anVHUmNHeS9YLzRha1VhbGl3N3lwaDlzZnRhQUZta2s4eFllNHgzRklSRmNyazJ4dlBDMnByNCtBRjNaVjJCTT0iLCJtYWMiOiJkYTQxZDY1OTY2ZTljMTgyZWRhNGEzMGZjZDc2MjBjN2NlNzU2YTViNGQxNWE1NTI2ZmI1MWQyYjQ2ODYxZmEwIiwidGFnIjoiIn0=",
"provider_refresh_token_encrypted": "eyJpdiI6Imt2bGxlSmxUK05GMjF0dEtPaTMrUlE9PSIsInZhbHVlIjoiUXZHTElZRXkreHFxUU02SnZ4eVBacG9WWTRlVkd0USszV3JyVFlpU2ZaY25GSWo2WFcrRzNlbFRlUXRQczNwSXRCcEdvZEpveG9jMzBDSTgwdnZLQnc9PSIsIm1hYyI6ImQxYWI0NzU5Nzg5MDI4YWVhZmQ4Mjg1YzhkZDQzMjRkYWYwYTdhZTY5MDMxMjc0OWNiYjY0Nzc3NDQ0MTEyY2EiLCJ0YWciOiIifQ==",
"encryption_key": "0x01020300786192D9D96DD60D3D1EBC9DFAEE5F0C45EE80165CF3F3D2B3B627026AA7CFC7CA0128DD463535D32EE491ADBADF8B07596B0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040C7FB1319048ECB2EA3F23B995020110802B52D22F5EAD341AB238FBBCB6093156E443876A664BA5555D722565C2B2D04422C868CD7350555E3CC74221",
"sociable_type": "user",
"owner_id": 23460
},
{
"user_id": "23463",
"email": "[EMAIL]",
"id": 72,
"sociable_id": 23463,
"provider_user_id": "23270841",
"provider_user_token": "v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:txqCuWLeVhgwiaFqXIvQWWrtrnFIy_4lT3VCr-sRB4g6_2lK8KcQ_6ka_qFmZhr-IeIAKmAImx6H1iIKx4Ab7XZ5MnKIh03GKbHjI0n0rGT9UYkeH21jKOxJvKaSX_TyLbxFPR6irPQyvqcpBClXI52gVJH01KzZy_dMTHFXhhDLOIhEpSrQXHG7Qo8q7OuBeSPZrU1ALi9kmAm4GTpzGTbzfl-hUt9IAfPunJOCyv3mf2Tl-MT8EyQgOFPrsP3yz9UlSyVhb40zO_bCnUrqNxjwgm_E6vgpVrwULTQbHe-43Dq-TRetjceUzT88GBgVJ0UdxXP5BRBVXcL5ir8-9ZTMaNU",
"provider_refresh_token": "5034113:[TELEGRAM_TOKEN]78ad1",
"expires": 1753837219,
"refresh_token_expires": null,
"provider": "pipedrive",
"state": "full-refresh",
"auth_scope": "base,deals:full,activities:full,contacts:full,search:read",
"retry_after": null,
"created_at": "2025-04-16 10:41:12",
"updated_at": "2025-07-30 01:00:17",
"provider_user_token_encrypted": "eyJpdiI6InVEVEl2SzIxMjd1bkNDWG9lY3YvQ0E9PSIsInZhbHVlIjoiRlJLbDZ3ZHo2dHMxUWQwdGU2YUZjV3lPWHlxQTJ0eWh4S0RTMjlSaThVcktoaWhXcTd2UXl4Mjg4bW5UUnZCZEQ5NXpuQTVKOURiMDNIa3l3K0lSWCt5azRBOEdHbitWQXhxeEpMVUZ1dnF2NVl1TTZLelZOaGNvRlBLeGpIWlpoRGloUEprd2xoNUFPcTlLcUd3WVlUU2svR1NOeXBYQ2NnMWhnK1V2aytOeVVMNzJGdVZXMU1JS3BSaGNCcmxkVjEwQ01mQXNBdWNhS1lMZWZobnZwcHBkN1R4bUVDRUNYdnNtSVJkdG5MdkN3djJBT0hMRDl1MHFGbnl4WU13ejBkUWsrdUljWkZhcTJlN0JDSGdTVzlPY0FGMUJlZi9WRGpkMUk5R20wblYwSk9VR2FuaHpLTzJNeitMbnF1V1NEMUUxRmYzaDRGZDMyaXd3Z0FjQno4SzVoYjUyTmV3UXNpRlF4TGZKNVl3dUFqdGhKVWJjRVlUUXRGalBpaXJvSGJmbS8rd25aQ2Zvc05saHRDRjlHV1VEUFFiRU5xbWRVNkxFSXV0RUZyaUlYNWMwMmhnZ0Y1VUQ4eEFkY2QyWXpnR0NidkVJSWdjVGljUjA3NDdpZW9WUHhtSlpGSGdNU2hRUTA5ZW03RGpiRFdrdytkOHJXSUxlazZNaG9iaUg2NFZYdEc3YklMeFZvblBzWmVRSDcvN2M4WUNtL3h4S2IrUW00cXhialBia3BJcW5XallBNlV5WWdhcE1ZVFBBM3RSSUVBamYvOGZEQWM5a2FJMGwyWkRSU3dlTEtPemZlQ3RXRGNDcEdYRHdMNTlTQVg2SUdUN0hVaXdZT1dUOUlrVzkrZHFBemhwWXg1cm4rSy9UOHUzcnNSM2dISlhBRTEyVUNyTkZYaFJYUlN1a2RKVHhhM2dHckR3a1JGaVZ2Wk9BVnhTclVpSEhwWTVpQTlJbXVkOUxSTGpRbDk0a1VtbE9QMVAvN3VlVEhJUHd2elowd0laNVIzZ3M3N0ZOK0NDakIwQ2FicGxoMDBhTXI0VUppUmFOZHdlWUdGV21NNFQ4RU1nY0dnWT0iLCJtYWMiOiI0ZTU4ZmJkNTdkYmY0NGE4NTJjZjlhNDExNzE2YjhlOWM2NTA5OGY2MDA4OTcyZDVlOTljY2JjZDhmMjBhMDUyIiwidGFnIjoiIn0=",
"provider_refresh_token_encrypted": "eyJpdiI6IkJGMkdRVHRKM2VTcitKNGcvQWJtUGc9PSIsInZhbHVlIjoicmFyRkxPZ1Rybm1ORXlEVjJ2TXFGTzJtM3hWaFhnUVVHN2ZlR1lRM0I5d3ozbnZTcU5EdzJqRkI2elhyNWhlenRTUXV3bjk0N1JXeklDMVAyUzBKcHc9PSIsIm1hYyI6ImJhODVjMGQyZDE3Y2ExNjc2OWVjYWJiNmFjYWVkODIyMTMyNWVhYTExMTgwYTEyMTU0MzUzZGE1YjQ5YzQ5ZjEiLCJ0YWciOiIifQ==",
"encryption_key": "0x01020300788C37CDF66ABE9301A68D5D4866AC0C197E04EEE4D904F20A59991322EBAE252301BEF4B24FF01359E934E5654617E4EEAC0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040CEB00EF45BDEA999A5558889E020110802B925F372F7BEFAF0B45E48686113D1DA430ECFCC07B1F61BA6828CC44235278EDB05C486E8068D0BE737D91",
"sociable_type": "user",
"owner_id": 23460
}
]
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
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":"master, menu","depth":5,"on_screen":true,"help_text":"Git Branch: master<br/>114 incoming commits<br/>","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":"AskJiminnyReportActivityServiceTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","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":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Component\\SCIM;\n\nuse Jiminny\\Component\\SCIM\\Builders\\Filters;\n\nclass Constants\n{\n /**\n * HTTP codes\n */\n public const HTTP_OK = 200;\n public const HTTP_CREATED = 201;\n public const HTTP_NO_CONTENT = 204;\n\n public const HTTP_NOT_FOUND = 404;\n public const HTTP_BAD_REQUEST = 400;\n public const HTTP_ACCESS_DENIED = 403;\n\n public const HTTP_ERROR = 501;\n\n /**\n * Users resource constants\n */\n public const USER_FIRST_NAME = 'givenName';\n public const USER_FAMILY_NAME = 'familyName';\n public const USER_STATUS = 'Active';\n public const USER_USERNAME = 'UserName';\n public const USER_EXTERNAL_ID = 'externalId';\n\n public const USER_FIELDS = [\n self::USER_FIRST_NAME,\n self::USER_FAMILY_NAME,\n self::USER_STATUS,\n self::USER_USERNAME,\n ];\n\n public const META_OPERATIONS_REPLACE = 'replace';\n public const META_OPERATIONS_REPLACE_UPPER = 'Replace';\n public const META_OPERATIONS_ADD = 'add';\n public const META_OPERATIONS_ADD_UPPER = 'Add';\n public const META_OPERATIONS_REMOVE_UPPER = 'Remove';\n public const META_OPERATIONS_REMOVE = 'remove';\n\n public const META_ID = 'id';\n public const META_PHONE_NUMBERS = 'phoneNumbers';\n public const META_TITLE = 'title';\n public const META_ROLES = 'roles';\n public const META_PATH = 'path';\n public const META_ENTERPRISE_SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';\n public const META_DEPARTMENT = 'department';\n public const META_META = 'meta';\n public const META_TYPE = 'type';\n public const META_VALUE = 'value';\n public const META_OPERATIONS = 'Operations';\n public const META_OP = 'op';\n public const META_RESOURCE_TYPE = 'resourceType';\n public const META_CREATED = 'created';\n public const META_LAST_MODIFIED = 'lastModified';\n public const META_FORMATTED = 'formatted';\n public const META_EMAILS = 'emails';\n public const META_USERNAME = 'userName';\n public const META_NAME = 'name';\n public const META_STATUS = 'active';\n public const META_PRIMARY = 'primary';\n public const META_ERROR_STATUS = 'status';\n public const META_ERROR_DETAIL = 'detail';\n public const META_LIST_TOTAL_RESULTS = 'totalResults';\n public const META_LIST_RESOURCES = 'Resources';\n public const META_LIST_START_INDEX = 'startIndex';\n public const META_LIST_COUNT = 'count';\n public const META_LIST_ITEMS_PER_PAGE = 'itemsPerPage';\n public const META_SCHEMAS = 'schemas';\n public const META_FILTER = 'filter';\n public const META_TYPE_WORK = 'work';\n public const META_PHONE_NUMBER_TYPE_MOBILE = 'mobile';\n public const META_EMAIL_TYPE_HOME = 'home';\n public const META_CONTAINER_NAME = 'name';\n public const META_CONTAINER_EMAILS = 'emails';\n\n public const RESOURCE_TYPE_USER = 'User';\n\n public const USER_PATCH_ATTR_TITLE = 'title';\n public const USER_PATCH_ATTR_ACTIVE = 'active';\n public const USER_PATCH_ATTR_USERNAME = 'userName';\n public const USER_PATCH_ATTR_FIRST_NAME = 'name.givenName';\n public const USER_PATCH_ATTR_LAST_NAME = 'name.familyName';\n public const USER_PATCH_ATTR_PRIMARY_EMAIL = 'emails[type eq \"work\"].value';\n public const USER_PATCH_ATTR_SECONDARY_EMAIL = 'emails[type eq \"home\"].value';\n public const USER_PATCH_ATTR_PHONE_NUMBER = 'phoneNumbers[type eq \"work\"].value';\n public const USER_PATCH_ATTR_PHONE_NUMBER_MOBILE = 'phoneNumbers[type eq \"mobile\"].value';\n public const USER_PATCH_ATTR_ROLES = 'roles';\n\n public const USER_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [\n self::USER_PATCH_ATTR_TITLE => Mutators\\Attributes\\User\\TitleAttr::class,\n self::USER_PATCH_ATTR_ACTIVE => Mutators\\Attributes\\User\\ActiveAttr::class,\n self::USER_PATCH_ATTR_USERNAME => Mutators\\Attributes\\User\\UsernameAttr::class,\n self::USER_PATCH_ATTR_FIRST_NAME => Mutators\\Attributes\\User\\FirstNameAttr::class,\n self::USER_PATCH_ATTR_LAST_NAME => Mutators\\Attributes\\User\\LastNameAttr::class,\n self::USER_PATCH_ATTR_PRIMARY_EMAIL => Mutators\\Attributes\\User\\PrimaryEmailAttr::class,\n self::USER_PATCH_ATTR_SECONDARY_EMAIL => Mutators\\Attributes\\User\\SecondaryEmailAttr::class,\n self::USER_PATCH_ATTR_PHONE_NUMBER => Mutators\\Attributes\\User\\PhoneNumberPrimaryAttr::class,\n self::USER_PATCH_ATTR_PHONE_NUMBER_MOBILE => Mutators\\Attributes\\User\\PhoneNumberSecondaryAttr::class,\n self::USER_PATCH_ATTR_ROLES => Mutators\\Attributes\\User\\RoleAttr::class,\n ];\n\n public const FILTER_OPERATOR_EQ = 'eq';\n\n public const SUPPORTED_FILTERS_OPERATORS = [\n self::FILTER_OPERATOR_EQ,\n ];\n\n public const USER_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [\n self::USER_FILTER_LOCAL_ID => Filters\\User\\LocalIdFilter::class,\n self::USER_FILTER_USERNAME => Filters\\User\\UserNameFilter::class,\n self::USER_FILTER_FIRST_NAME => Filters\\User\\FirstNameFilter::class,\n self::USER_FILTER_LAST_NAME => Filters\\User\\LastNameFilter::class,\n self::USER_FILTER_EXTERNAL_ID => Filters\\User\\ExternalIdFilter::class,\n self::USER_FILTER_DISPLAY_NAME => Filters\\User\\DisplayNameFilter::class,\n ];\n\n public const USER_FILTER_LOCAL_ID = 'id';\n public const USER_FILTER_USERNAME = 'userName';\n public const USER_FILTER_FIRST_NAME = 'givenName';\n public const USER_FILTER_LAST_NAME = 'familyName';\n public const USER_FILTER_EXTERNAL_ID = 'externalId';\n public const USER_FILTER_DISPLAY_NAME = 'DisplayName';\n\n public const SCIM_SUPPORTED_RESOURCES = [\n self::USER_RESOURCE_PREFIX,\n self::GROUP_RESOURCE_PREFIX,\n ];\n\n public const USER_RESOURCE_PREFIX = 'Users';\n public const GROUP_RESOURCE_PREFIX = 'Groups';\n\n public const OUTGOING_SCHEMAS_SUPPORTED = [\n self::OUTGOING_CORE_USER,\n\n ];\n\n /**\n * Outgoing supported schemas\n */\n public const OUTGOING_CORE_USER = 'urn:ietf:params:scim:schemas:core:2.0:User';\n public const OUTGOING_ERROR = 'urn:ietf:params:scim:api:messages:2.0:Error';\n public const OUTGOING_LIST_RESPONSE = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';\n\n public const OUTGOING_CORE_GROUP = 'urn:ietf:params:scim:schemas:core:2.0:Group';\n\n /**\n * Groups resource constants\n */\n public const GROUP_ATTRIBUTE_DISPLAY_NAME = 'displayName';\n public const GROUP_ATTRIBUTE_EXTERNAL_ID = 'externalId';\n public const GROUP_ATTRIBUTE_ID = 'id';\n public const RESOURCE_TYPE_GROUP = 'Group';\n public const GROUP_FILTER_QUERY_NAME = 'filter';\n public const GROUP_EXCLUDED_ATTRIBUTES = 'excludedAttributes';\n\n public const GROUP_SUPPORTED_FILTER_ATTRIBUTES = [\n self::GROUP_ATTRIBUTE_DISPLAY_NAME,\n ];\n\n public const GROUP_MEMBERS = 'members';\n\n public const SUPPORTED_PATCH_OPERATIONS = [\n self::META_OPERATIONS_ADD,\n self::META_OPERATIONS_REPLACE,\n self::META_OPERATIONS_REMOVE,\n ];\n\n public const GROUP_PATCH_ATTRIBUTE_MEMBERS = 'members';\n public const GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME = 'displayName';\n\n public const GROUP_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [\n self::GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME => Mutators\\Attributes\\Group\\DisplayNameAttr::class,\n self::GROUP_PATCH_ATTRIBUTE_MEMBERS => Mutators\\Attributes\\Group\\MembersAttr::class,\n ];\n\n public const GROUP_FILTER_DISPLAY_NAME = 'displayname';\n\n public const GROUP_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [\n self::GROUP_FILTER_DISPLAY_NAME => Filters\\Group\\DisplayNameFilter::class,\n ];\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Component\\SCIM;\n\nuse Jiminny\\Component\\SCIM\\Builders\\Filters;\n\nclass Constants\n{\n /**\n * HTTP codes\n */\n public const HTTP_OK = 200;\n public const HTTP_CREATED = 201;\n public const HTTP_NO_CONTENT = 204;\n\n public const HTTP_NOT_FOUND = 404;\n public const HTTP_BAD_REQUEST = 400;\n public const HTTP_ACCESS_DENIED = 403;\n\n public const HTTP_ERROR = 501;\n\n /**\n * Users resource constants\n */\n public const USER_FIRST_NAME = 'givenName';\n public const USER_FAMILY_NAME = 'familyName';\n public const USER_STATUS = 'Active';\n public const USER_USERNAME = 'UserName';\n public const USER_EXTERNAL_ID = 'externalId';\n\n public const USER_FIELDS = [\n self::USER_FIRST_NAME,\n self::USER_FAMILY_NAME,\n self::USER_STATUS,\n self::USER_USERNAME,\n ];\n\n public const META_OPERATIONS_REPLACE = 'replace';\n public const META_OPERATIONS_REPLACE_UPPER = 'Replace';\n public const META_OPERATIONS_ADD = 'add';\n public const META_OPERATIONS_ADD_UPPER = 'Add';\n public const META_OPERATIONS_REMOVE_UPPER = 'Remove';\n public const META_OPERATIONS_REMOVE = 'remove';\n\n public const META_ID = 'id';\n public const META_PHONE_NUMBERS = 'phoneNumbers';\n public const META_TITLE = 'title';\n public const META_ROLES = 'roles';\n public const META_PATH = 'path';\n public const META_ENTERPRISE_SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';\n public const META_DEPARTMENT = 'department';\n public const META_META = 'meta';\n public const META_TYPE = 'type';\n public const META_VALUE = 'value';\n public const META_OPERATIONS = 'Operations';\n public const META_OP = 'op';\n public const META_RESOURCE_TYPE = 'resourceType';\n public const META_CREATED = 'created';\n public const META_LAST_MODIFIED = 'lastModified';\n public const META_FORMATTED = 'formatted';\n public const META_EMAILS = 'emails';\n public const META_USERNAME = 'userName';\n public const META_NAME = 'name';\n public const META_STATUS = 'active';\n public const META_PRIMARY = 'primary';\n public const META_ERROR_STATUS = 'status';\n public const META_ERROR_DETAIL = 'detail';\n public const META_LIST_TOTAL_RESULTS = 'totalResults';\n public const META_LIST_RESOURCES = 'Resources';\n public const META_LIST_START_INDEX = 'startIndex';\n public const META_LIST_COUNT = 'count';\n public const META_LIST_ITEMS_PER_PAGE = 'itemsPerPage';\n public const META_SCHEMAS = 'schemas';\n public const META_FILTER = 'filter';\n public const META_TYPE_WORK = 'work';\n public const META_PHONE_NUMBER_TYPE_MOBILE = 'mobile';\n public const META_EMAIL_TYPE_HOME = 'home';\n public const META_CONTAINER_NAME = 'name';\n public const META_CONTAINER_EMAILS = 'emails';\n\n public const RESOURCE_TYPE_USER = 'User';\n\n public const USER_PATCH_ATTR_TITLE = 'title';\n public const USER_PATCH_ATTR_ACTIVE = 'active';\n public const USER_PATCH_ATTR_USERNAME = 'userName';\n public const USER_PATCH_ATTR_FIRST_NAME = 'name.givenName';\n public const USER_PATCH_ATTR_LAST_NAME = 'name.familyName';\n public const USER_PATCH_ATTR_PRIMARY_EMAIL = 'emails[type eq \"work\"].value';\n public const USER_PATCH_ATTR_SECONDARY_EMAIL = 'emails[type eq \"home\"].value';\n public const USER_PATCH_ATTR_PHONE_NUMBER = 'phoneNumbers[type eq \"work\"].value';\n public const USER_PATCH_ATTR_PHONE_NUMBER_MOBILE = 'phoneNumbers[type eq \"mobile\"].value';\n public const USER_PATCH_ATTR_ROLES = 'roles';\n\n public const USER_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [\n self::USER_PATCH_ATTR_TITLE => Mutators\\Attributes\\User\\TitleAttr::class,\n self::USER_PATCH_ATTR_ACTIVE => Mutators\\Attributes\\User\\ActiveAttr::class,\n self::USER_PATCH_ATTR_USERNAME => Mutators\\Attributes\\User\\UsernameAttr::class,\n self::USER_PATCH_ATTR_FIRST_NAME => Mutators\\Attributes\\User\\FirstNameAttr::class,\n self::USER_PATCH_ATTR_LAST_NAME => Mutators\\Attributes\\User\\LastNameAttr::class,\n self::USER_PATCH_ATTR_PRIMARY_EMAIL => Mutators\\Attributes\\User\\PrimaryEmailAttr::class,\n self::USER_PATCH_ATTR_SECONDARY_EMAIL => Mutators\\Attributes\\User\\SecondaryEmailAttr::class,\n self::USER_PATCH_ATTR_PHONE_NUMBER => Mutators\\Attributes\\User\\PhoneNumberPrimaryAttr::class,\n self::USER_PATCH_ATTR_PHONE_NUMBER_MOBILE => Mutators\\Attributes\\User\\PhoneNumberSecondaryAttr::class,\n self::USER_PATCH_ATTR_ROLES => Mutators\\Attributes\\User\\RoleAttr::class,\n ];\n\n public const FILTER_OPERATOR_EQ = 'eq';\n\n public const SUPPORTED_FILTERS_OPERATORS = [\n self::FILTER_OPERATOR_EQ,\n ];\n\n public const USER_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [\n self::USER_FILTER_LOCAL_ID => Filters\\User\\LocalIdFilter::class,\n self::USER_FILTER_USERNAME => Filters\\User\\UserNameFilter::class,\n self::USER_FILTER_FIRST_NAME => Filters\\User\\FirstNameFilter::class,\n self::USER_FILTER_LAST_NAME => Filters\\User\\LastNameFilter::class,\n self::USER_FILTER_EXTERNAL_ID => Filters\\User\\ExternalIdFilter::class,\n self::USER_FILTER_DISPLAY_NAME => Filters\\User\\DisplayNameFilter::class,\n ];\n\n public const USER_FILTER_LOCAL_ID = 'id';\n public const USER_FILTER_USERNAME = 'userName';\n public const USER_FILTER_FIRST_NAME = 'givenName';\n public const USER_FILTER_LAST_NAME = 'familyName';\n public const USER_FILTER_EXTERNAL_ID = 'externalId';\n public const USER_FILTER_DISPLAY_NAME = 'DisplayName';\n\n public const SCIM_SUPPORTED_RESOURCES = [\n self::USER_RESOURCE_PREFIX,\n self::GROUP_RESOURCE_PREFIX,\n ];\n\n public const USER_RESOURCE_PREFIX = 'Users';\n public const GROUP_RESOURCE_PREFIX = 'Groups';\n\n public const OUTGOING_SCHEMAS_SUPPORTED = [\n self::OUTGOING_CORE_USER,\n\n ];\n\n /**\n * Outgoing supported schemas\n */\n public const OUTGOING_CORE_USER = 'urn:ietf:params:scim:schemas:core:2.0:User';\n public const OUTGOING_ERROR = 'urn:ietf:params:scim:api:messages:2.0:Error';\n public const OUTGOING_LIST_RESPONSE = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';\n\n public const OUTGOING_CORE_GROUP = 'urn:ietf:params:scim:schemas:core:2.0:Group';\n\n /**\n * Groups resource constants\n */\n public const GROUP_ATTRIBUTE_DISPLAY_NAME = 'displayName';\n public const GROUP_ATTRIBUTE_EXTERNAL_ID = 'externalId';\n public const GROUP_ATTRIBUTE_ID = 'id';\n public const RESOURCE_TYPE_GROUP = 'Group';\n public const GROUP_FILTER_QUERY_NAME = 'filter';\n public const GROUP_EXCLUDED_ATTRIBUTES = 'excludedAttributes';\n\n public const GROUP_SUPPORTED_FILTER_ATTRIBUTES = [\n self::GROUP_ATTRIBUTE_DISPLAY_NAME,\n ];\n\n public const GROUP_MEMBERS = 'members';\n\n public const SUPPORTED_PATCH_OPERATIONS = [\n self::META_OPERATIONS_ADD,\n self::META_OPERATIONS_REPLACE,\n self::META_OPERATIONS_REMOVE,\n ];\n\n public const GROUP_PATCH_ATTRIBUTE_MEMBERS = 'members';\n public const GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME = 'displayName';\n\n public const GROUP_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [\n self::GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME => Mutators\\Attributes\\Group\\DisplayNameAttr::class,\n self::GROUP_PATCH_ATTRIBUTE_MEMBERS => Mutators\\Attributes\\Group\\MembersAttr::class,\n ];\n\n public const GROUP_FILTER_DISPLAY_NAME = 'displayname';\n\n public const GROUP_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [\n self::GROUP_FILTER_DISPLAY_NAME => Filters\\Group\\DisplayNameFilter::class,\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_jupiter","depth":4,"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":"19","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"19","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"17","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":"SELECT * FROM teams WHERE id = 1;\n\nselect * from crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 283;\nSELECT * FROM crm_fields WHERE id = 2234;\nSELECT * FROM crm_field_values WHERE crm_field_id = 2234;\n\nselect * from crm_profiles where user_id = 143;\n\nselect * from record_types where crm_configuration_id = 39; # 0121K000001MHElQAO,0121K000001MHEqQAO\nselect * from business_processes where crm_configuration_id = 39;\n# 01941000000H669AAC, 01941000000H66JAAS\n\nselect * from record_type_field_values\n where record_type_id IN (24);\n\nselect * from crm_field_values where id IN (2730);\n\nselect * from crm_configurations where id = 39;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce'; #1035\n\n\nselect * from users where team_id = 1; # 222 group 3\nSELECT * FROM activities WHERE user_id = 222 order by id desc;\nselect * from sidekick_settings where team_id = 1;\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\n\nselect * from activities where crm_configuration_id = 2\nand provider = 'ms-teams' and id = 608765;\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id = '59523413338';\n\nselect * from sidekick_settings where team_id = 2;\n\nSELECT * FROM activities WHERE id = 608660;\nselect * from activity_summary_logs where activity_id = 608660;\nselect * from ai_prompts where transcription_id = 11214;\n\n# ********************************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('ed78a437-2804-450e-ab2f-56ab1c641346') = uuid;\n# id: 608818, crm: 59628809737\nSELECT * FROM activities WHERE uuid_to_bin('36b06e55-afdd-4782-8dee-c624cd0af191') = uuid;\n# id: 608821, crm: 59632069252\nSELECT ce.start_time, ce.end_time, a.id, a.uuid, crm_provider_id, calendar_event_id, title,\nplaybook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id,\nscheduled_start_time, scheduled_end_time, actual_start_time, actual_end_time, a.created_at\nFROM activities a\njoin calendar_events ce on a.calendar_event_id = ce.id\nWHERE a.id IN (608818, 608821);\n\nselect * from users where team_id = 1;\nselect * from team_settings where team_id = 1;\nselect * from crm_profiles where crm_configuration_id = 39 order by user_id;\n\nselect * from team_features where team_id = 1;\n\nselect * from users where team_id = 2;\n\nSELECT * FROM activities WHERE uuid_to_bin('ec7647e9-5225-458b-b475-f31aa2769204') = uuid; # 612639\n# Preslava N. Ivanova, grou id 3\n\nSELECT * FROM opportunities WHERE uuid_to_bin('a2928fe5-aec5-46cb-85d9-7654c89e46a6') = uuid;\n\nselect * from activities where opportunity_id = 344 and actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00';\n\nselect\n a.id,\n a.type,\n a.scheduled_start_time,\n a.actual_start_time,\n a.created_at,\n a.opportunity_id,\n a.status\nFROM activities a\nWHERE opportunity_id = 344\nand status IN ('completed', 'received', 'delivered')\nand (\n (a.actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')\nOR (a.created_at between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')\nOR (a.scheduled_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00'))\n;\n\nSELECT * FROM users WHERE id = 222;\n\nSELECT * FROM crm_profiles WHERE user_id = 222;\nselect * from crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 281;\n\nselect * from group_deal_risk_types;\n\nselect * from opportunities where team_id = 1;\n\nSELECT * FROM opportunities WHERE id = 315;\nSELECT * FROM crm_field_data WHERE object_id = 315;\nselect * from crm_field_data where object_id = 260;\n\nselect * from generic_ai_prompts where subject_id = 315;\n\nselect * from teams; # 36, 21, 121, james.graham@bullhorn.jiminny.com\nSELECT * FROM social_accounts WHERE sociable_id = 121 and provider = 'bullhorn';\n\n# ************************************************************************************\nselect * from teams where id = 1;\nselect * from crm_configurations where id = 39;\nselect * from users where team_id = 1;\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 1;\n# 1 - 00541000004281rAAA\n# 204 - 0052g000003freeAAA\n# 429 - 0052g000003qGOiAAM\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce';\n\nselect * from activities where type = 'softphone'\nand created_at > '2024-12-11 15:24:36' order by id desc;\n\nselect * from activity_providers where team_id = 1;\nselect * from activity_provider_users where activity_provider_id = 328;\n\nselect * from opportunities where crm_configuration_id = 39\nAND account_id = 178 AND is_closed = false\norder by created_at DESC;\n\nselect * from contacts where id = 3952;\nselect * from accounts where id = 178;\n\n# ************************************************************************************\nselect * from teams where id = 36;\nselect * from crm_configurations where id = 21;\nselect * from users where team_id = 36;\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 36;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 36\nand sa.provider = 'bullhorn';\n\nselect * from social_accounts where id = 348;\nUPDATE social_accounts SET\nprovider_user_token = '21442_6802599_91:41179a58-21e7-4d7c-ad58-56bb666b2f65',\nprovider_refresh_token = '21442_6802599_91:01c6b335-3f2a-42e4-85ff-8a08fa65fceb',\nexpires = 1733998131,\nstate = 'connected'\nWHERE id = 348;\n\n# ************************************************************************************\nselect * from teams where id = 31;\nselect * from crm_configurations where id = 18;\n\nselect * from users where team_id = 31; # 257\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 31;\n\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 31\nand sa.provider = 'close';\n\nselect * from contacts where crm_configuration_id = 18;\n\n# ********************** NEPTUNE **************************************************************\nselect * from teams;\nselect * from users where id IN (1030, 1035, 1052);\nselect * from crm_configurations;\n\nselect * from users where team_id = 65; # 257\nselect * from team_settings where team_id = 65; # 257\nselect * from invitations where team_id = 65; # 257\nselect * from users where email = 'integration-account@jiminny.com'; # 257\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 65;\n\nselect * from crm_configurations where id = 53;\nselect * from accounts where crm_configuration_id = 53 order by id desc;\nselect * from leads where crm_configuration_id = 53 order by id desc;\nselect * from contacts where crm_configuration_id = 53 order by id desc;\nselect * from opportunities where crm_configuration_id = 53 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 53 order by id desc;\nselect * from crm_fields where crm_configuration_id = 53 order by id desc;\nselect * from crm_field_values where crm_field_id = 3341 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 53 order by id desc;\nselect * from stages where crm_configuration_id = 53 order by id desc;\n\n\nselect * from crm_profiles where crm_configuration_id = 13;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 65\nand sa.provider = 'integration-app';\n\nselect * from contacts where crm_configuration_id = 13;\n\nselect * from social_accounts where sociable_id = 283;\n\nSELECT * FROM opportunities WHERE crm_provider_id = '006O400000E9bzeIAB';\n\nselect * from activity_providers where team_id = 65;\nSELECT * FROM activities WHERE crm_configuration_id IN (51, 52, 53);\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 65\n;\n\n# ***************************** STAGING ********************************************\nSELECT * FROM teams;\nSELECT * FROM teams WHERE id = 88;\nSELECT * FROM teams WHERE id = 89;\nselect * from team_settings where team_id = 89;\nSELECT * FROM users WHERE team_id = 89;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 89;\n\nselect * from users;\nSELECT * FROM social_accounts WHERE sociable_id = 1761;\nSELECT * FROM crm_configurations WHERE id = 70;\nselect * from accounts where crm_configuration_id = 70 order by id desc;\nselect * from leads where crm_configuration_id = 70 order by id desc;\nselect * from contacts where crm_configuration_id = 70 order by id desc;\nselect * from opportunities where crm_configuration_id = 70 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 70 order by id desc;\nselect * from crm_fields where crm_configuration_id = 70 order by id desc;\nselect * from crm_field_values where crm_field_id = 3536 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 70 order by id desc;\nselect * from stages where crm_configuration_id = 70 order by id desc;\nselect * from business_processes where crm_configuration_id = 70 order by id desc;\nselect * from business_process_stages where business_process_id = 34;\n\nselect * from contacts where id = 10468;\n\nselect * from crm_layouts where crm_configuration_id = 70;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 388;\nSELECT * FROM crm_fields WHERE id IN (3533,3534,3535);\n\nselect * from activities where crm_configuration_id = 70\nand (account_id IS NOT NULL or lead_id IS NOT NULL or contact_id IS NOT NULL or opportunity_id IS NOT NULL) order by id desc;\n\nSELECT * FROM activities WHERE uuid_to_bin('2e10b60f-8a61-41c5-a3d4-28835353dc65') = uuid;\nSELECT * FROM activities where crm_configuration_id = 69 ;\n\nSELECT * FROM users WHERE email LIKE '%jiminny_web_sa2@jiminny.com%';\nSELECT * FROM activities WHERE uuid_to_bin('5a150c93-40fc-42ec-b3bd-c1d328e09f6e') = uuid;\nSELECT * FROM opportunities WHERE id = 385;\n\nselect * from participants p\njoin activities a on p.activity_id = a.id\nwhere a.crm_configuration_id = 70\nand (p.lead_id IS NOT NULL or p.contact_id IS NOT NULL);\nSELECT * FROM participants WHERE id = 1013638;\n\nselect * from teams where id = 90;\nselect * from users where team_id = 90;\nselect * from social_accounts where social_accounts.sociable_id IN (1960,1760);\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 71;\nselect * from invitations where team_id = 90;\n\nselect * from crm_configurations where id = 71;\nselect * from accounts where crm_configuration_id = 71 order by id desc;\nselect * from leads where crm_configuration_id = 71 order by id desc;\nselect * from contacts where crm_configuration_id = 71 order by id desc;\nselect * from opportunities where crm_configuration_id = 71 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 71 order by id desc;\nselect * from crm_fields where crm_configuration_id = 71 order by id desc;\nselect * from crm_field_values where crm_field_id = 3341 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 71 order by id desc;\nselect * from stages where crm_configuration_id = 71 order by id desc;\n\nselect * from users order by secondary_email desc;\nselect u.id, u.email, u.status, sa.id, sa.provider_user_id from social_accounts sa\n join users u on sa.sociable_id = u.id\nwhere sa.provider = 'google' and u.email LIKE 'aneliya%';\n\nselect * from failed_jobs order by id desc;\n\nselect * from users where email = 'ben.allwright@learningpeople.co.uk' or secondary_email = 'ben.allwright@learningpeople.co.uk';\n\nselect * from teams;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 39;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type = 'task';\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce';\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('c38b3895-fd0f-4b1f-9fb2-c170dba137c6') = uuid;\nSELECT * FROM crm_configurations WHERE id = 70;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1;\nselect * from users where team_id = 1;\n\nselect o.id, o.name,o.close_date, u.id, u.name, u.group_id, r.id, r.display_name, g.name, g.scope from opportunities o\njoin users u on o.user_id = u.id\njoin groups g on u.group_id = g.id\njoin role_user ru on u.id = ru.user_id\njoin roles r on ru.role_id = r.id\nwhere o.crm_configuration_id = 39 and close_date > '2024-01-01 00:00:00';\n\nselect * from role_user where user_id = 143;\nselect * from roles;\n\nselect * from role_user;\nselect * from groups where id = 9;\nselect * from scope_groups where group_id = 9;\n\n# ************************************************************************************\nselect * from teams where id = 36;\nselect * from crm_configurations;\nSELECT * FROM social_accounts WHERE sociable_id = 121;\n\nhttps://crmsandbox.zoho.com/crm/jiminnyw4/tab/Leads/4776201000005049105\nhttps://crmsandbox.zoho.com/crm/\n\nhttps://crm.zoho.com/crm/org3469620/tab/Leads/230045000229559080\n https://crm.zoho.com/crm/\n org3469620\n\nSELECT * FROM activities WHERE uuid_to_bin('03382d20-c8bc-48e7-a3d4-90b52fa5ceab') = uuid;\n\nselect * from users where email LIKE \"%mobile_automation_%\";\nselect * from social_accounts where sociable_id IN (2228);\nselect * from crm_profiles where user_id IN (2222,2223,2226,2227);\n\nselect * from teams order by id desc;\nSELECT * FROM users WHERE id = 2229;\nSELECT * FROM crm_profiles WHERE user_id = 2229;\nselect * from opportunities where crm_configuration_id = 88;\nselect * from crm_fields where crm_configuration_id = 88;\nselect * from crm_profiles where crm_configuration_id = 88;\n\nSELECT * FROM teams WHERE id = 1;\n\nSELECT * FROM users WHERE id = 143;\nSELECT * FROM users WHERE uuid_to_bin('fde193d3-06a2-4e1a-8895-62b94039215d') = uuid;\nSELECT * FROM teams WHERE uuid_to_bin('73385071-a756-42ae-9c73-8b53f2309467') = uuid;\n\nhttps://app.staging.jiminny.com/ondemand?\n min_duration=1\n &\n only_recorded=1\n &\n user_id%5B%5D=641f1acb-16b8-42d1-8726-df52979dad0e\n &\n sequence_number=2\n\n select * from users where team_id = 1 and email like '%stoyan%'\n\nselect * from coaching_feedbacks;\n\nselect * from teams;\nSELECT * FROM users WHERE team_id = 36;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 19\nand sa.provider = 'pipedrive';\n\nselect * from users where id = 143;\n\nSELECT * FROM users WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\nSELECT * FROM teams WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\nSELECT * FROM activity_shares WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\n\nselect * from users where team_id = 2;\nselect * from activities where crm_configuration_id = 39\nand activities.scheduled_start_time BETWEEN '2025-04-09 00:00:00' AND '2025-04-09 23:59:59'\nAND user_id = 143\norder by id desc;\n\n# ************************************************************************************\nselect * from teams where id = 142; # 2312, 126\nselect * from team_settings;\nselect * from users where team_id = 142; # 21642\nSELECT * FROM social_accounts WHERE sociable_id = 21642;\nSELECT * FROM crm_profiles cp join users u ON u.id = cp.user_id WHERE team_id = 142;\nselect * from crm_profiles where id IN (93);\nselect * from invitations;\nselect * from team_features where team_id = 1;\n\nSELECT * FROM crm_configurations WHERE id = 126;\nselect * from accounts where crm_configuration_id = 126 order by id desc;\nselect * from leads where crm_configuration_id = 126 order by id desc;\nselect * from contacts where crm_configuration_id = 126 order by id desc;\nselect * from opportunities where crm_configuration_id = 126 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 126 order by id desc;\nselect * from crm_fields where crm_configuration_id = 126 # 11060\n# and type IN ('picklist', 'status')\n# and object_type = 'task'\norder by id desc;\n# 5731,5732,5733\nselect DISTINCT crm_field_id from crm_field_values where crm_field_id IN (11151,12239,12215,12185,12175,12165,12144,12137,12127,12109,12107,12105,12103,12092,12037,12005,12003,11987,11969,11958,11951,11942,11931,11924,11921,11917,11915,11901,11893,11883,11872,11870,11868,11866,11839,11833,11821,11793,11780,11777,11769,11757,11737,11735,11656,11645,11638,11629,11618,11611,11602,11591,11584,11581,11558,11544,11543,11534,11532,11529,11527,11503,11497,11493,11488,11470,11468,11457,11455,11397,11387,11372,11363,11348,11323,11318,11309,11301,11300,11292,11290,11286,11284,11256,11252,11242,11237,11233,11219,11176,11160) order by id desc;\nselect * from crm_layouts where crm_configuration_id = 126 order by id desc;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id in (300,299,298);\nselect * from stages where crm_configuration_id = 126 order by id desc;\nselect * from business_processes where crm_configuration_id = 126 order by id desc;\nselect * from business_process_stages where business_process_id IN (76,75,74,73);\nselect * from playbooks where team_id = 142;\nselect * from playbook_layouts where playbook_id IN (108);\nSELECT * FROM playbook_categories WHERE playbook_id IN (108);\n\nselect * from teams where id = 130;\nSELECT * FROM social_accounts WHERE sociable_id = 2291;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 2\nand sa.provider = 'hubspot';\n\nSELECT * FROM activities\n WHERE crm_configuration_id = 110;\n\nselect * from teams;\nselect * from crm_configurations;\n\nSELECT * FROM activities WHERE id = 628773;\nSELECT * FROM crm_profiles WHERE user_id = 1460;\nSELECT * FROM social_accounts WHERE sociable_id = 2291;\n\nselect * from teams;\nselect ru.*, pr.*, p.* from users u join role_user ru on ru.user_id = u.id\njoin permission_role pr on pr.role_id = ru.role_id\n join permissions p on p.id = pr.permission_id\nwhere team_id = 495 and p.name IN ('dial');\n\nselect * from teams where id = 145;\nselect * from crm_configurations where id = 129;\nselect * from social_accounts where sociable_id = 2317;\nSELECT * FROM activities WHERE uuid_to_bin('8dbab184-a333-4268-ad57-fb41f8d53a9a') = uuid;\n\nselect * from teams where id = 1;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 280;\nSELECT * FROM crm_layout_entities WHERE id = 5507;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type IN ('event');\n\nselect * from teams;\nselect * from activities where crm_configuration_id = 14;\n\nSELECT * FROM social_accounts where provider = 'copper';\n\nselect * from activities where id = 628467;\nselect * from participants where activity_id = 628467;\n\nSELECT * FROM contacts WHERE id = 3969;\nSELECT * FROM accounts WHERE id = 177;\n\nSELECT * FROM activities WHERE uuid_to_bin('4eb54c77-cfa3-2bd4-84a7-9ed46a21c988') = uuid;\n\n# ********************* BH\nselect * from teams where id = 36;\nSELECT * FROM crm_configurations WHERE id = 21;\nselect * from activities where crm_configuration_id = 21 and id = 607901;\nselect * from activities where crm_configuration_id = 21;\n\nselect * roles;\nselect * from permissions;\nselect * from permission_role where permission_id = 226;\n\nselect * from migrations order by id desc;\n\n# mercury\n# neptune\n# earth\n\nselect * from teams;\nselect * from teams where id = 19;\nselect * from teams where id = 27;\nselect * from users where team_id = 27;\nSELECT * FROM crm_configurations WHERE id = 42;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 19\nand sa.provider = 'pipedrive';\n\nselect * from activities where id = 631461;\nSELECT * FROM crm_field_values WHERE crm_field_id = 180;\n\nselect * from teams where id = 2;\nSELECT * FROM social_accounts WHERE sociable_id = 89;\n\nSELECT * FROM activities WHERE uuid_to_bin('ba0c029a-bc14-4e17-8603-64174acebcbb') = uuid; # 634273\nselect * from activity_summary_logs where activity_id = 634273;\n\nselect * from sidekick_settings where team_id = 2;\n\nselect * from teams; # 2, 2\nSELECT * FROM crm_configurations WHERE team_id = 2; # 2\nselect * from team_features where team_id = 2;\nselect * from features;\nSELECT * FROM opportunities WHERE crm_configuration_id = 2 and crm_provider_id = '51317301383';\nSELECT * FROM opportunities WHERE crm_configuration_id = 2 order by id desc;\n\nselect * from automated_reports order by id desc;\nselect * from automated_report_results order by id desc;\nselect * from users where team_id = 1 and id IN (7160, 3248);\nselect * from migrations order by id desc;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1052 and sa.provider = 'hubspot';\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 = 565;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 175;\nselect * from playbook_categories where playbook_id = 175;\nselect * from users where team_id = 1052;\nselect * from users where id = 7160;\nselect * from crm_profiles where user_id = 7160;\nselect * from features;\nselect\n *\n# id, uuid, type, provider, playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id, stage_id,\n# crm_configuration_id, crm_provider_id, transcription_id, status\nfrom activities where crm_configuration_id = 1 and type = 'conference'\n# and crm_provider_id IS NOT NULL\nand provider != 'uploader' and actual_start_time IS NOT NULL\nORDER by id desc;\nselect * from activities where id = 54747783; # 00UO400000pCzojMAC\n\nselect p.id, p.activity_type, pc.id, pc.name\nFROM playbooks p\njoin playbook_categories pc on p.id = pc.playbook_id\nwhere p.team_id = 1 and p.activity_type = 'event';\n\nSELECT * FROM crm_fields WHERE crm_configuration_id = 1 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id = 4;\n\nselect * from crm_layouts cl join playbook_layouts pl on cl.id = pl.layout_id\nwhere crm_configuration_id = 1 and pl.playbook_id = 175;\n\nselect * from teams;\nSELECT r.* FROM automated_reports r\njoin teams t on r.team_id = t.id\nWHERE r.frequency = 'daily'\n and r.status = 1\nAND t.status = 'active'\nAND (r.expires_at >= now() OR r.expires_at IS NULL);\n\nselect * from automated_report_results where report_id IN (18, 33);\n\nselect * from users where team_id = 1 and id = 1047;\nSELECT * FROM social_accounts WHERE sociable_id = 1047;\n\nselect * from activity_searches where id = 10932;\nselect * from activity_search_filters where activity_search_id = 10932;\nselect * from automated_reports order by id desc;\nselect * from automated_report_results order by id desc;\nselect * from automated_reports where id IN (55);\nselect * from automated_report_results where id IN (81);\nselect * from users where id IN (10633, 13987, 11985);\nselect * from users where group_id IN (3710);\n\nSELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;\nSELECT * FROM automated_report_results WHERE uuid_to_bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;\n\nselect * from teams;\nselect * from accounts where team_id = 1;\n\nselect * from automated_report_results where media_type = 'pdf' and status = 2;\nSELECT * FROM automated_report_results WHERE uuid_to_bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid;\n\nselect * from teams where id = 1029;\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 = 1029 and sa.provider = 'pipedrive';\n\n[\n {\n \"user_id\": \"23460 (owner)\",\n \"email\": \"integration-account@pipedrive.jiminny.com\",\n \"id\": 69,\n \"sociable_id\": 23460,\n \"provider_user_id\": \"19555731\",\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,\n \"refresh_token_expires\": null,\n \"provider\": \"pipedrive\",\n \"state\": \"connected\",\n \"auth_scope\": \"base,deals:full,activities:full,contacts:full,search:read\",\n \"retry_after\": null,\n \"created_at\": \"2025-04-16 08:23:28\",\n \"updated_at\": \"2026-05-18 07:13:18\",\n \"provider_user_token_encrypted\": \"eyJpdiI6Ik9oYzBwcTVteWN4ajBRaDdMb0FjWGc9PSIsInZhbHVlIjoiQUNMbjU5UHR2Q1RnbWRXMEU1TUx6UVpRU3gzdVc5WktmTE4rVlhXa3lRaGhyUUlZMVZRWEJuR0JaWWhZZXNPRlBuanhuYU5MVHZ5TG9NTVVjNjJSUUpZZ2VhbGYxbHg0UzJEdTVmQjNFZnJRZkMwYjd0N2RMZ05GRS9IR3c2K0NoVjBjYTA5UG12SkxHeDlDMGVNN3ptUWUzblFiTngyYzR1eUpHSEYrdEwvZm0yZklGYjBSNEtTR2ZGazhLM1hqT3lVbjFobDNPZ0d3anFlcjhKcXpERlZGOVN1YmFyNDIvM1BFRDFMYnp4WEI4TGVLM2xYcy9CL0RDOWlQNHI3N0NwWnJPMWRtZllmM2ZKeE9TV2NBeDZxL2M1YnlSVzd3ZW96T3F1QmtBYXBHYkUraGcvdCtRajlYZXBjVVBSdFlMUjVPVDVJbDdyenVoWjMrbVJvU3ZZR1dQZ3pqQ3F3aDF2U2xPZWZIN3BCWVFLNXpxQUtDb2pIK0xHc1E3SklSM3Q0VkNSbm9oK2pFK3hLaW54T1dWbEVneUp0RGhhdVBuOFI4MXROc3dZWnFnTUpiaDVMMnZ4QmlRM3k4QWFlMVFWUFYvdGhJQzZBYnhBQmhWa2ZKN1ZhSnhpaExxbmlTemgzUWw3aXJtWjlSMlhmd0lWMDNDN1N3My9Ua0hCL2xqY3RkVFhMSjFJMDRjOE5DWlgrZ3FMVXN6RWlwUE5GWERZdG1xVjVxOFlLRGs2VVJKS3FLeWRxQjYxdDh4Z2JJNXhlWEZ3dkQ4SGtybDNUcndzblFHeVJNRkYraFh2UDFIUTdMQ1BZa3dEU1dBbzk5K0dyT2RNVFBZZUJpRytSck5pYlI1YUZyMmhUNEZCdWxHYmJLREtzbUpjVkhvV0RoejJpbm1SWHlNaXE5M0RhcS94UW9EdFoweWF3bVFVY0dTZWFPSXBmOCtDYndia215cmtyZU1oT0Exam1CV2tPblNhYjY4clVEeUs3anVHUmNHeS9YLzRha1VhbGl3N3lwaDlzZnRhQUZta2s4eFllNHgzRklSRmNyazJ4dlBDMnByNCtBRjNaVjJCTT0iLCJtYWMiOiJkYTQxZDY1OTY2ZTljMTgyZWRhNGEzMGZjZDc2MjBjN2NlNzU2YTViNGQxNWE1NTI2ZmI1MWQyYjQ2ODYxZmEwIiwidGFnIjoiIn0=\",\n \"provider_refresh_token_encrypted\": \"eyJpdiI6Imt2bGxlSmxUK05GMjF0dEtPaTMrUlE9PSIsInZhbHVlIjoiUXZHTElZRXkreHFxUU02SnZ4eVBacG9WWTRlVkd0USszV3JyVFlpU2ZaY25GSWo2WFcrRzNlbFRlUXRQczNwSXRCcEdvZEpveG9jMzBDSTgwdnZLQnc9PSIsIm1hYyI6ImQxYWI0NzU5Nzg5MDI4YWVhZmQ4Mjg1YzhkZDQzMjRkYWYwYTdhZTY5MDMxMjc0OWNiYjY0Nzc3NDQ0MTEyY2EiLCJ0YWciOiIifQ==\",\n \"encryption_key\": \"0x01020300786192D9D96DD60D3D1EBC9DFAEE5F0C45EE80165CF3F3D2B3B627026AA7CFC7CA0128DD463535D32EE491ADBADF8B07596B0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040C7FB1319048ECB2EA3F23B995020110802B52D22F5EAD341AB238FBBCB6093156E443876A664BA5555D722565C2B2D04422C868CD7350555E3CC74221\",\n \"sociable_type\": \"user\",\n \"owner_id\": 23460\n },\n {\n \"user_id\": \"23463\",\n \"email\": \"jiminny_web_sa@pipedrive.jiminny.com\",\n \"id\": 72,\n \"sociable_id\": 23463,\n \"provider_user_id\": \"23270841\",\n \"provider_user_token\": \"v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:txqCuWLeVhgwiaFqXIvQWWrtrnFIy_4lT3VCr-sRB4g6_2lK8KcQ_6ka_qFmZhr-IeIAKmAImx6H1iIKx4Ab7XZ5MnKIh03GKbHjI0n0rGT9UYkeH21jKOxJvKaSX_TyLbxFPR6irPQyvqcpBClXI52gVJH01KzZy_dMTHFXhhDLOIhEpSrQXHG7Qo8q7OuBeSPZrU1ALi9kmAm4GTpzGTbzfl-hUt9IAfPunJOCyv3mf2Tl-MT8EyQgOFPrsP3yz9UlSyVhb40zO_bCnUrqNxjwgm_E6vgpVrwULTQbHe-43Dq-TRetjceUzT88GBgVJ0UdxXP5BRBVXcL5ir8-9ZTMaNU\",\n \"provider_refresh_token\": \"5034113:23270841:34790b44838f5fd422c2d2c82e00f1ecf2178ad1\",\n \"expires\": 1753837219,\n \"refresh_token_expires\": null,\n \"provider\": \"pipedrive\",\n \"state\": \"full-refresh\",\n \"auth_scope\": \"base,deals:full,activities:full,contacts:full,search:read\",\n \"retry_after\": null,\n \"created_at\": \"2025-04-16 10:41:12\",\n \"updated_at\": \"2025-07-30 01:00:17\",\n \"provider_user_token_encrypted\": \"eyJpdiI6InVEVEl2SzIxMjd1bkNDWG9lY3YvQ0E9PSIsInZhbHVlIjoiRlJLbDZ3ZHo2dHMxUWQwdGU2YUZjV3lPWHlxQTJ0eWh4S0RTMjlSaThVcktoaWhXcTd2UXl4Mjg4bW5UUnZCZEQ5NXpuQTVKOURiMDNIa3l3K0lSWCt5azRBOEdHbitWQXhxeEpMVUZ1dnF2NVl1TTZLelZOaGNvRlBLeGpIWlpoRGloUEprd2xoNUFPcTlLcUd3WVlUU2svR1NOeXBYQ2NnMWhnK1V2aytOeVVMNzJGdVZXMU1JS3BSaGNCcmxkVjEwQ01mQXNBdWNhS1lMZWZobnZwcHBkN1R4bUVDRUNYdnNtSVJkdG5MdkN3djJBT0hMRDl1MHFGbnl4WU13ejBkUWsrdUljWkZhcTJlN0JDSGdTVzlPY0FGMUJlZi9WRGpkMUk5R20wblYwSk9VR2FuaHpLTzJNeitMbnF1V1NEMUUxRmYzaDRGZDMyaXd3Z0FjQno4SzVoYjUyTmV3UXNpRlF4TGZKNVl3dUFqdGhKVWJjRVlUUXRGalBpaXJvSGJmbS8rd25aQ2Zvc05saHRDRjlHV1VEUFFiRU5xbWRVNkxFSXV0RUZyaUlYNWMwMmhnZ0Y1VUQ4eEFkY2QyWXpnR0NidkVJSWdjVGljUjA3NDdpZW9WUHhtSlpGSGdNU2hRUTA5ZW03RGpiRFdrdytkOHJXSUxlazZNaG9iaUg2NFZYdEc3YklMeFZvblBzWmVRSDcvN2M4WUNtL3h4S2IrUW00cXhialBia3BJcW5XallBNlV5WWdhcE1ZVFBBM3RSSUVBamYvOGZEQWM5a2FJMGwyWkRSU3dlTEtPemZlQ3RXRGNDcEdYRHdMNTlTQVg2SUdUN0hVaXdZT1dUOUlrVzkrZHFBemhwWXg1cm4rSy9UOHUzcnNSM2dISlhBRTEyVUNyTkZYaFJYUlN1a2RKVHhhM2dHckR3a1JGaVZ2Wk9BVnhTclVpSEhwWTVpQTlJbXVkOUxSTGpRbDk0a1VtbE9QMVAvN3VlVEhJUHd2elowd0laNVIzZ3M3N0ZOK0NDakIwQ2FicGxoMDBhTXI0VUppUmFOZHdlWUdGV21NNFQ4RU1nY0dnWT0iLCJtYWMiOiI0ZTU4ZmJkNTdkYmY0NGE4NTJjZjlhNDExNzE2YjhlOWM2NTA5OGY2MDA4OTcyZDVlOTljY2JjZDhmMjBhMDUyIiwidGFnIjoiIn0=\",\n \"provider_refresh_token_encrypted\": \"eyJpdiI6IkJGMkdRVHRKM2VTcitKNGcvQWJtUGc9PSIsInZhbHVlIjoicmFyRkxPZ1Rybm1ORXlEVjJ2TXFGTzJtM3hWaFhnUVVHN2ZlR1lRM0I5d3ozbnZTcU5EdzJqRkI2elhyNWhlenRTUXV3bjk0N1JXeklDMVAyUzBKcHc9PSIsIm1hYyI6ImJhODVjMGQyZDE3Y2ExNjc2OWVjYWJiNmFjYWVkODIyMTMyNWVhYTExMTgwYTEyMTU0MzUzZGE1YjQ5YzQ5ZjEiLCJ0YWciOiIifQ==\",\n \"encryption_key\": \"0x01020300788C37CDF66ABE9301A68D5D4866AC0C197E04EEE4D904F20A59991322EBAE252301BEF4B24FF01359E934E5654617E4EEAC0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040CEB00EF45BDEA999A5558889E020110802B925F372F7BEFAF0B45E48686113D1DA430ECFCC07B1F61BA6828CC44235278EDB05C486E8068D0BE737D91\",\n \"sociable_type\": \"user\",\n \"owner_id\": 23460\n }\n]","depth":4,"on_screen":true,"value":"SELECT * FROM teams WHERE id = 1;\n\nselect * from crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 283;\nSELECT * FROM crm_fields WHERE id = 2234;\nSELECT * FROM crm_field_values WHERE crm_field_id = 2234;\n\nselect * from crm_profiles where user_id = 143;\n\nselect * from record_types where crm_configuration_id = 39; # 0121K000001MHElQAO,0121K000001MHEqQAO\nselect * from business_processes where crm_configuration_id = 39;\n# 01941000000H669AAC, 01941000000H66JAAS\n\nselect * from record_type_field_values\n where record_type_id IN (24);\n\nselect * from crm_field_values where id IN (2730);\n\nselect * from crm_configurations where id = 39;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce'; #1035\n\n\nselect * from users where team_id = 1; # 222 group 3\nSELECT * FROM activities WHERE user_id = 222 order by id desc;\nselect * from sidekick_settings where team_id = 1;\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\n\nselect * from activities where crm_configuration_id = 2\nand provider = 'ms-teams' and id = 608765;\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id = '59523413338';\n\nselect * from sidekick_settings where team_id = 2;\n\nSELECT * FROM activities WHERE id = 608660;\nselect * from activity_summary_logs where activity_id = 608660;\nselect * from ai_prompts where transcription_id = 11214;\n\n# ********************************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('ed78a437-2804-450e-ab2f-56ab1c641346') = uuid;\n# id: 608818, crm: 59628809737\nSELECT * FROM activities WHERE uuid_to_bin('36b06e55-afdd-4782-8dee-c624cd0af191') = uuid;\n# id: 608821, crm: 59632069252\nSELECT ce.start_time, ce.end_time, a.id, a.uuid, crm_provider_id, calendar_event_id, title,\nplaybook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id,\nscheduled_start_time, scheduled_end_time, actual_start_time, actual_end_time, a.created_at\nFROM activities a\njoin calendar_events ce on a.calendar_event_id = ce.id\nWHERE a.id IN (608818, 608821);\n\nselect * from users where team_id = 1;\nselect * from team_settings where team_id = 1;\nselect * from crm_profiles where crm_configuration_id = 39 order by user_id;\n\nselect * from team_features where team_id = 1;\n\nselect * from users where team_id = 2;\n\nSELECT * FROM activities WHERE uuid_to_bin('ec7647e9-5225-458b-b475-f31aa2769204') = uuid; # 612639\n# Preslava N. Ivanova, grou id 3\n\nSELECT * FROM opportunities WHERE uuid_to_bin('a2928fe5-aec5-46cb-85d9-7654c89e46a6') = uuid;\n\nselect * from activities where opportunity_id = 344 and actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00';\n\nselect\n a.id,\n a.type,\n a.scheduled_start_time,\n a.actual_start_time,\n a.created_at,\n a.opportunity_id,\n a.status\nFROM activities a\nWHERE opportunity_id = 344\nand status IN ('completed', 'received', 'delivered')\nand (\n (a.actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')\nOR (a.created_at between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')\nOR (a.scheduled_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00'))\n;\n\nSELECT * FROM users WHERE id = 222;\n\nSELECT * FROM crm_profiles WHERE user_id = 222;\nselect * from crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 281;\n\nselect * from group_deal_risk_types;\n\nselect * from opportunities where team_id = 1;\n\nSELECT * FROM opportunities WHERE id = 315;\nSELECT * FROM crm_field_data WHERE object_id = 315;\nselect * from crm_field_data where object_id = 260;\n\nselect * from generic_ai_prompts where subject_id = 315;\n\nselect * from teams; # 36, 21, 121, james.graham@bullhorn.jiminny.com\nSELECT * FROM social_accounts WHERE sociable_id = 121 and provider = 'bullhorn';\n\n# ************************************************************************************\nselect * from teams where id = 1;\nselect * from crm_configurations where id = 39;\nselect * from users where team_id = 1;\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 1;\n# 1 - 00541000004281rAAA\n# 204 - 0052g000003freeAAA\n# 429 - 0052g000003qGOiAAM\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce';\n\nselect * from activities where type = 'softphone'\nand created_at > '2024-12-11 15:24:36' order by id desc;\n\nselect * from activity_providers where team_id = 1;\nselect * from activity_provider_users where activity_provider_id = 328;\n\nselect * from opportunities where crm_configuration_id = 39\nAND account_id = 178 AND is_closed = false\norder by created_at DESC;\n\nselect * from contacts where id = 3952;\nselect * from accounts where id = 178;\n\n# ************************************************************************************\nselect * from teams where id = 36;\nselect * from crm_configurations where id = 21;\nselect * from users where team_id = 36;\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 36;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 36\nand sa.provider = 'bullhorn';\n\nselect * from social_accounts where id = 348;\nUPDATE social_accounts SET\nprovider_user_token = '21442_6802599_91:41179a58-21e7-4d7c-ad58-56bb666b2f65',\nprovider_refresh_token = '21442_6802599_91:01c6b335-3f2a-42e4-85ff-8a08fa65fceb',\nexpires = 1733998131,\nstate = 'connected'\nWHERE id = 348;\n\n# ************************************************************************************\nselect * from teams where id = 31;\nselect * from crm_configurations where id = 18;\n\nselect * from users where team_id = 31; # 257\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 31;\n\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 31\nand sa.provider = 'close';\n\nselect * from contacts where crm_configuration_id = 18;\n\n# ********************** NEPTUNE **************************************************************\nselect * from teams;\nselect * from users where id IN (1030, 1035, 1052);\nselect * from crm_configurations;\n\nselect * from users where team_id = 65; # 257\nselect * from team_settings where team_id = 65; # 257\nselect * from invitations where team_id = 65; # 257\nselect * from users where email = 'integration-account@jiminny.com'; # 257\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 65;\n\nselect * from crm_configurations where id = 53;\nselect * from accounts where crm_configuration_id = 53 order by id desc;\nselect * from leads where crm_configuration_id = 53 order by id desc;\nselect * from contacts where crm_configuration_id = 53 order by id desc;\nselect * from opportunities where crm_configuration_id = 53 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 53 order by id desc;\nselect * from crm_fields where crm_configuration_id = 53 order by id desc;\nselect * from crm_field_values where crm_field_id = 3341 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 53 order by id desc;\nselect * from stages where crm_configuration_id = 53 order by id desc;\n\n\nselect * from crm_profiles where crm_configuration_id = 13;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 65\nand sa.provider = 'integration-app';\n\nselect * from contacts where crm_configuration_id = 13;\n\nselect * from social_accounts where sociable_id = 283;\n\nSELECT * FROM opportunities WHERE crm_provider_id = '006O400000E9bzeIAB';\n\nselect * from activity_providers where team_id = 65;\nSELECT * FROM activities WHERE crm_configuration_id IN (51, 52, 53);\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 65\n;\n\n# ***************************** STAGING ********************************************\nSELECT * FROM teams;\nSELECT * FROM teams WHERE id = 88;\nSELECT * FROM teams WHERE id = 89;\nselect * from team_settings where team_id = 89;\nSELECT * FROM users WHERE team_id = 89;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 89;\n\nselect * from users;\nSELECT * FROM social_accounts WHERE sociable_id = 1761;\nSELECT * FROM crm_configurations WHERE id = 70;\nselect * from accounts where crm_configuration_id = 70 order by id desc;\nselect * from leads where crm_configuration_id = 70 order by id desc;\nselect * from contacts where crm_configuration_id = 70 order by id desc;\nselect * from opportunities where crm_configuration_id = 70 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 70 order by id desc;\nselect * from crm_fields where crm_configuration_id = 70 order by id desc;\nselect * from crm_field_values where crm_field_id = 3536 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 70 order by id desc;\nselect * from stages where crm_configuration_id = 70 order by id desc;\nselect * from business_processes where crm_configuration_id = 70 order by id desc;\nselect * from business_process_stages where business_process_id = 34;\n\nselect * from contacts where id = 10468;\n\nselect * from crm_layouts where crm_configuration_id = 70;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 388;\nSELECT * FROM crm_fields WHERE id IN (3533,3534,3535);\n\nselect * from activities where crm_configuration_id = 70\nand (account_id IS NOT NULL or lead_id IS NOT NULL or contact_id IS NOT NULL or opportunity_id IS NOT NULL) order by id desc;\n\nSELECT * FROM activities WHERE uuid_to_bin('2e10b60f-8a61-41c5-a3d4-28835353dc65') = uuid;\nSELECT * FROM activities where crm_configuration_id = 69 ;\n\nSELECT * FROM users WHERE email LIKE '%jiminny_web_sa2@jiminny.com%';\nSELECT * FROM activities WHERE uuid_to_bin('5a150c93-40fc-42ec-b3bd-c1d328e09f6e') = uuid;\nSELECT * FROM opportunities WHERE id = 385;\n\nselect * from participants p\njoin activities a on p.activity_id = a.id\nwhere a.crm_configuration_id = 70\nand (p.lead_id IS NOT NULL or p.contact_id IS NOT NULL);\nSELECT * FROM participants WHERE id = 1013638;\n\nselect * from teams where id = 90;\nselect * from users where team_id = 90;\nselect * from social_accounts where social_accounts.sociable_id IN (1960,1760);\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 71;\nselect * from invitations where team_id = 90;\n\nselect * from crm_configurations where id = 71;\nselect * from accounts where crm_configuration_id = 71 order by id desc;\nselect * from leads where crm_configuration_id = 71 order by id desc;\nselect * from contacts where crm_configuration_id = 71 order by id desc;\nselect * from opportunities where crm_configuration_id = 71 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 71 order by id desc;\nselect * from crm_fields where crm_configuration_id = 71 order by id desc;\nselect * from crm_field_values where crm_field_id = 3341 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 71 order by id desc;\nselect * from stages where crm_configuration_id = 71 order by id desc;\n\nselect * from users order by secondary_email desc;\nselect u.id, u.email, u.status, sa.id, sa.provider_user_id from social_accounts sa\n join users u on sa.sociable_id = u.id\nwhere sa.provider = 'google' and u.email LIKE 'aneliya%';\n\nselect * from failed_jobs order by id desc;\n\nselect * from users where email = 'ben.allwright@learningpeople.co.uk' or secondary_email = 'ben.allwright@learningpeople.co.uk';\n\nselect * from teams;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 39;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type = 'task';\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce';\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('c38b3895-fd0f-4b1f-9fb2-c170dba137c6') = uuid;\nSELECT * FROM crm_configurations WHERE id = 70;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1;\nselect * from users where team_id = 1;\n\nselect o.id, o.name,o.close_date, u.id, u.name, u.group_id, r.id, r.display_name, g.name, g.scope from opportunities o\njoin users u on o.user_id = u.id\njoin groups g on u.group_id = g.id\njoin role_user ru on u.id = ru.user_id\njoin roles r on ru.role_id = r.id\nwhere o.crm_configuration_id = 39 and close_date > '2024-01-01 00:00:00';\n\nselect * from role_user where user_id = 143;\nselect * from roles;\n\nselect * from role_user;\nselect * from groups where id = 9;\nselect * from scope_groups where group_id = 9;\n\n# ************************************************************************************\nselect * from teams where id = 36;\nselect * from crm_configurations;\nSELECT * FROM social_accounts WHERE sociable_id = 121;\n\nhttps://crmsandbox.zoho.com/crm/jiminnyw4/tab/Leads/4776201000005049105\nhttps://crmsandbox.zoho.com/crm/\n\nhttps://crm.zoho.com/crm/org3469620/tab/Leads/230045000229559080\n https://crm.zoho.com/crm/\n org3469620\n\nSELECT * FROM activities WHERE uuid_to_bin('03382d20-c8bc-48e7-a3d4-90b52fa5ceab') = uuid;\n\nselect * from users where email LIKE \"%mobile_automation_%\";\nselect * from social_accounts where sociable_id IN (2228);\nselect * from crm_profiles where user_id IN (2222,2223,2226,2227);\n\nselect * from teams order by id desc;\nSELECT * FROM users WHERE id = 2229;\nSELECT * FROM crm_profiles WHERE user_id = 2229;\nselect * from opportunities where crm_configuration_id = 88;\nselect * from crm_fields where crm_configuration_id = 88;\nselect * from crm_profiles where crm_configuration_id = 88;\n\nSELECT * FROM teams WHERE id = 1;\n\nSELECT * FROM users WHERE id = 143;\nSELECT * FROM users WHERE uuid_to_bin('fde193d3-06a2-4e1a-8895-62b94039215d') = uuid;\nSELECT * FROM teams WHERE uuid_to_bin('73385071-a756-42ae-9c73-8b53f2309467') = uuid;\n\nhttps://app.staging.jiminny.com/ondemand?\n min_duration=1\n &\n only_recorded=1\n &\n user_id%5B%5D=641f1acb-16b8-42d1-8726-df52979dad0e\n &\n sequence_number=2\n\n select * from users where team_id = 1 and email like '%stoyan%'\n\nselect * from coaching_feedbacks;\n\nselect * from teams;\nSELECT * FROM users WHERE team_id = 36;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 19\nand sa.provider = 'pipedrive';\n\nselect * from users where id = 143;\n\nSELECT * FROM users WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\nSELECT * FROM teams WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\nSELECT * FROM activity_shares WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\n\nselect * from users where team_id = 2;\nselect * from activities where crm_configuration_id = 39\nand activities.scheduled_start_time BETWEEN '2025-04-09 00:00:00' AND '2025-04-09 23:59:59'\nAND user_id = 143\norder by id desc;\n\n# ************************************************************************************\nselect * from teams where id = 142; # 2312, 126\nselect * from team_settings;\nselect * from users where team_id = 142; # 21642\nSELECT * FROM social_accounts WHERE sociable_id = 21642;\nSELECT * FROM crm_profiles cp join users u ON u.id = cp.user_id WHERE team_id = 142;\nselect * from crm_profiles where id IN (93);\nselect * from invitations;\nselect * from team_features where team_id = 1;\n\nSELECT * FROM crm_configurations WHERE id = 126;\nselect * from accounts where crm_configuration_id = 126 order by id desc;\nselect * from leads where crm_configuration_id = 126 order by id desc;\nselect * from contacts where crm_configuration_id = 126 order by id desc;\nselect * from opportunities where crm_configuration_id = 126 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 126 order by id desc;\nselect * from crm_fields where crm_configuration_id = 126 # 11060\n# and type IN ('picklist', 'status')\n# and object_type = 'task'\norder by id desc;\n# 5731,5732,5733\nselect DISTINCT crm_field_id from crm_field_values where crm_field_id IN (11151,12239,12215,12185,12175,12165,12144,12137,12127,12109,12107,12105,12103,12092,12037,12005,12003,11987,11969,11958,11951,11942,11931,11924,11921,11917,11915,11901,11893,11883,11872,11870,11868,11866,11839,11833,11821,11793,11780,11777,11769,11757,11737,11735,11656,11645,11638,11629,11618,11611,11602,11591,11584,11581,11558,11544,11543,11534,11532,11529,11527,11503,11497,11493,11488,11470,11468,11457,11455,11397,11387,11372,11363,11348,11323,11318,11309,11301,11300,11292,11290,11286,11284,11256,11252,11242,11237,11233,11219,11176,11160) order by id desc;\nselect * from crm_layouts where crm_configuration_id = 126 order by id desc;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id in (300,299,298);\nselect * from stages where crm_configuration_id = 126 order by id desc;\nselect * from business_processes where crm_configuration_id = 126 order by id desc;\nselect * from business_process_stages where business_process_id IN (76,75,74,73);\nselect * from playbooks where team_id = 142;\nselect * from playbook_layouts where playbook_id IN (108);\nSELECT * FROM playbook_categories WHERE playbook_id IN (108);\n\nselect * from teams where id = 130;\nSELECT * FROM social_accounts WHERE sociable_id = 2291;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 2\nand sa.provider = 'hubspot';\n\nSELECT * FROM activities\n WHERE crm_configuration_id = 110;\n\nselect * from teams;\nselect * from crm_configurations;\n\nSELECT * FROM activities WHERE id = 628773;\nSELECT * FROM crm_profiles WHERE user_id = 1460;\nSELECT * FROM social_accounts WHERE sociable_id = 2291;\n\nselect * from teams;\nselect ru.*, pr.*, p.* from users u join role_user ru on ru.user_id = u.id\njoin permission_role pr on pr.role_id = ru.role_id\n join permissions p on p.id = pr.permission_id\nwhere team_id = 495 and p.name IN ('dial');\n\nselect * from teams where id = 145;\nselect * from crm_configurations where id = 129;\nselect * from social_accounts where sociable_id = 2317;\nSELECT * FROM activities WHERE uuid_to_bin('8dbab184-a333-4268-ad57-fb41f8d53a9a') = uuid;\n\nselect * from teams where id = 1;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 280;\nSELECT * FROM crm_layout_entities WHERE id = 5507;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type IN ('event');\n\nselect * from teams;\nselect * from activities where crm_configuration_id = 14;\n\nSELECT * FROM social_accounts where provider = 'copper';\n\nselect * from activities where id = 628467;\nselect * from participants where activity_id = 628467;\n\nSELECT * FROM contacts WHERE id = 3969;\nSELECT * FROM accounts WHERE id = 177;\n\nSELECT * FROM activities WHERE uuid_to_bin('4eb54c77-cfa3-2bd4-84a7-9ed46a21c988') = uuid;\n\n# ********************* BH\nselect * from teams where id = 36;\nSELECT * FROM crm_configurations WHERE id = 21;\nselect * from activities where crm_configuration_id = 21 and id = 607901;\nselect * from activities where crm_configuration_id = 21;\n\nselect * roles;\nselect * from permissions;\nselect * from permission_role where permission_id = 226;\n\nselect * from migrations order by id desc;\n\n# mercury\n# neptune\n# earth\n\nselect * from teams;\nselect * from teams where id = 19;\nselect * from teams where id = 27;\nselect * from users where team_id = 27;\nSELECT * FROM crm_configurations WHERE id = 42;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 19\nand sa.provider = 'pipedrive';\n\nselect * from activities where id = 631461;\nSELECT * FROM crm_field_values WHERE crm_field_id = 180;\n\nselect * from teams where id = 2;\nSELECT * FROM social_accounts WHERE sociable_id = 89;\n\nSELECT * FROM activities WHERE uuid_to_bin('ba0c029a-bc14-4e17-8603-64174acebcbb') = uuid; # 634273\nselect * from activity_summary_logs where activity_id = 634273;\n\nselect * from sidekick_settings where team_id = 2;\n\nselect * from teams; # 2, 2\nSELECT * FROM crm_configurations WHERE team_id = 2; # 2\nselect * from team_features where team_id = 2;\nselect * from features;\nSELECT * FROM opportunities WHERE crm_configuration_id = 2 and crm_provider_id = '51317301383';\nSELECT * FROM opportunities WHERE crm_configuration_id = 2 order by id desc;\n\nselect * from automated_reports order by id desc;\nselect * from automated_report_results order by id desc;\nselect * from users where team_id = 1 and id IN (7160, 3248);\nselect * from migrations order by id desc;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1052 and sa.provider = 'hubspot';\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 = 565;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 175;\nselect * from playbook_categories where playbook_id = 175;\nselect * from users where team_id = 1052;\nselect * from users where id = 7160;\nselect * from crm_profiles where user_id = 7160;\nselect * from features;\nselect\n *\n# id, uuid, type, provider, playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id, stage_id,\n# crm_configuration_id, crm_provider_id, transcription_id, status\nfrom activities where crm_configuration_id = 1 and type = 'conference'\n# and crm_provider_id IS NOT NULL\nand provider != 'uploader' and actual_start_time IS NOT NULL\nORDER by id desc;\nselect * from activities where id = 54747783; # 00UO400000pCzojMAC\n\nselect p.id, p.activity_type, pc.id, pc.name\nFROM playbooks p\njoin playbook_categories pc on p.id = pc.playbook_id\nwhere p.team_id = 1 and p.activity_type = 'event';\n\nSELECT * FROM crm_fields WHERE crm_configuration_id = 1 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id = 4;\n\nselect * from crm_layouts cl join playbook_layouts pl on cl.id = pl.layout_id\nwhere crm_configuration_id = 1 and pl.playbook_id = 175;\n\nselect * from teams;\nSELECT r.* FROM automated_reports r\njoin teams t on r.team_id = t.id\nWHERE r.frequency = 'daily'\n and r.status = 1\nAND t.status = 'active'\nAND (r.expires_at >= now() OR r.expires_at IS NULL);\n\nselect * from automated_report_results where report_id IN (18, 33);\n\nselect * from users where team_id = 1 and id = 1047;\nSELECT * FROM social_accounts WHERE sociable_id = 1047;\n\nselect * from activity_searches where id = 10932;\nselect * from activity_search_filters where activity_search_id = 10932;\nselect * from automated_reports order by id desc;\nselect * from automated_report_results order by id desc;\nselect * from automated_reports where id IN (55);\nselect * from automated_report_results where id IN (81);\nselect * from users where id IN (10633, 13987, 11985);\nselect * from users where group_id IN (3710);\n\nSELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;\nSELECT * FROM automated_report_results WHERE uuid_to_bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;\n\nselect * from teams;\nselect * from accounts where team_id = 1;\n\nselect * from automated_report_results where media_type = 'pdf' and status = 2;\nSELECT * FROM automated_report_results WHERE uuid_to_bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid;\n\nselect * from teams where id = 1029;\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 = 1029 and sa.provider = 'pipedrive';\n\n[\n {\n \"user_id\": \"23460 (owner)\",\n \"email\": \"integration-account@pipedrive.jiminny.com\",\n \"id\": 69,\n \"sociable_id\": 23460,\n \"provider_user_id\": \"19555731\",\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,\n \"refresh_token_expires\": null,\n \"provider\": \"pipedrive\",\n \"state\": \"connected\",\n \"auth_scope\": \"base,deals:full,activities:full,contacts:full,search:read\",\n \"retry_after\": null,\n \"created_at\": \"2025-04-16 08:23:28\",\n \"updated_at\": \"2026-05-18 07:13:18\",\n \"provider_user_token_encrypted\": \"eyJpdiI6Ik9oYzBwcTVteWN4ajBRaDdMb0FjWGc9PSIsInZhbHVlIjoiQUNMbjU5UHR2Q1RnbWRXMEU1TUx6UVpRU3gzdVc5WktmTE4rVlhXa3lRaGhyUUlZMVZRWEJuR0JaWWhZZXNPRlBuanhuYU5MVHZ5TG9NTVVjNjJSUUpZZ2VhbGYxbHg0UzJEdTVmQjNFZnJRZkMwYjd0N2RMZ05GRS9IR3c2K0NoVjBjYTA5UG12SkxHeDlDMGVNN3ptUWUzblFiTngyYzR1eUpHSEYrdEwvZm0yZklGYjBSNEtTR2ZGazhLM1hqT3lVbjFobDNPZ0d3anFlcjhKcXpERlZGOVN1YmFyNDIvM1BFRDFMYnp4WEI4TGVLM2xYcy9CL0RDOWlQNHI3N0NwWnJPMWRtZllmM2ZKeE9TV2NBeDZxL2M1YnlSVzd3ZW96T3F1QmtBYXBHYkUraGcvdCtRajlYZXBjVVBSdFlMUjVPVDVJbDdyenVoWjMrbVJvU3ZZR1dQZ3pqQ3F3aDF2U2xPZWZIN3BCWVFLNXpxQUtDb2pIK0xHc1E3SklSM3Q0VkNSbm9oK2pFK3hLaW54T1dWbEVneUp0RGhhdVBuOFI4MXROc3dZWnFnTUpiaDVMMnZ4QmlRM3k4QWFlMVFWUFYvdGhJQzZBYnhBQmhWa2ZKN1ZhSnhpaExxbmlTemgzUWw3aXJtWjlSMlhmd0lWMDNDN1N3My9Ua0hCL2xqY3RkVFhMSjFJMDRjOE5DWlgrZ3FMVXN6RWlwUE5GWERZdG1xVjVxOFlLRGs2VVJKS3FLeWRxQjYxdDh4Z2JJNXhlWEZ3dkQ4SGtybDNUcndzblFHeVJNRkYraFh2UDFIUTdMQ1BZa3dEU1dBbzk5K0dyT2RNVFBZZUJpRytSck5pYlI1YUZyMmhUNEZCdWxHYmJLREtzbUpjVkhvV0RoejJpbm1SWHlNaXE5M0RhcS94UW9EdFoweWF3bVFVY0dTZWFPSXBmOCtDYndia215cmtyZU1oT0Exam1CV2tPblNhYjY4clVEeUs3anVHUmNHeS9YLzRha1VhbGl3N3lwaDlzZnRhQUZta2s4eFllNHgzRklSRmNyazJ4dlBDMnByNCtBRjNaVjJCTT0iLCJtYWMiOiJkYTQxZDY1OTY2ZTljMTgyZWRhNGEzMGZjZDc2MjBjN2NlNzU2YTViNGQxNWE1NTI2ZmI1MWQyYjQ2ODYxZmEwIiwidGFnIjoiIn0=\",\n \"provider_refresh_token_encrypted\": \"eyJpdiI6Imt2bGxlSmxUK05GMjF0dEtPaTMrUlE9PSIsInZhbHVlIjoiUXZHTElZRXkreHFxUU02SnZ4eVBacG9WWTRlVkd0USszV3JyVFlpU2ZaY25GSWo2WFcrRzNlbFRlUXRQczNwSXRCcEdvZEpveG9jMzBDSTgwdnZLQnc9PSIsIm1hYyI6ImQxYWI0NzU5Nzg5MDI4YWVhZmQ4Mjg1YzhkZDQzMjRkYWYwYTdhZTY5MDMxMjc0OWNiYjY0Nzc3NDQ0MTEyY2EiLCJ0YWciOiIifQ==\",\n \"encryption_key\": \"0x01020300786192D9D96DD60D3D1EBC9DFAEE5F0C45EE80165CF3F3D2B3B627026AA7CFC7CA0128DD463535D32EE491ADBADF8B07596B0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040C7FB1319048ECB2EA3F23B995020110802B52D22F5EAD341AB238FBBCB6093156E443876A664BA5555D722565C2B2D04422C868CD7350555E3CC74221\",\n \"sociable_type\": \"user\",\n \"owner_id\": 23460\n },\n {\n \"user_id\": \"23463\",\n \"email\": \"jiminny_web_sa@pipedrive.jiminny.com\",\n \"id\": 72,\n \"sociable_id\": 23463,\n \"provider_user_id\": \"23270841\",\n \"provider_user_token\": \"v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:txqCuWLeVhgwiaFqXIvQWWrtrnFIy_4lT3VCr-sRB4g6_2lK8KcQ_6ka_qFmZhr-IeIAKmAImx6H1iIKx4Ab7XZ5MnKIh03GKbHjI0n0rGT9UYkeH21jKOxJvKaSX_TyLbxFPR6irPQyvqcpBClXI52gVJH01KzZy_dMTHFXhhDLOIhEpSrQXHG7Qo8q7OuBeSPZrU1ALi9kmAm4GTpzGTbzfl-hUt9IAfPunJOCyv3mf2Tl-MT8EyQgOFPrsP3yz9UlSyVhb40zO_bCnUrqNxjwgm_E6vgpVrwULTQbHe-43Dq-TRetjceUzT88GBgVJ0UdxXP5BRBVXcL5ir8-9ZTMaNU\",\n \"provider_refresh_token\": \"5034113:23270841:34790b44838f5fd422c2d2c82e00f1ecf2178ad1\",\n \"expires\": 1753837219,\n \"refresh_token_expires\": null,\n \"provider\": \"pipedrive\",\n \"state\": \"full-refresh\",\n \"auth_scope\": \"base,deals:full,activities:full,contacts:full,search:read\",\n \"retry_after\": null,\n \"created_at\": \"2025-04-16 10:41:12\",\n \"updated_at\": \"2025-07-30 01:00:17\",\n \"provider_user_token_encrypted\": \"eyJpdiI6InVEVEl2SzIxMjd1bkNDWG9lY3YvQ0E9PSIsInZhbHVlIjoiRlJLbDZ3ZHo2dHMxUWQwdGU2YUZjV3lPWHlxQTJ0eWh4S0RTMjlSaThVcktoaWhXcTd2UXl4Mjg4bW5UUnZCZEQ5NXpuQTVKOURiMDNIa3l3K0lSWCt5azRBOEdHbitWQXhxeEpMVUZ1dnF2NVl1TTZLelZOaGNvRlBLeGpIWlpoRGloUEprd2xoNUFPcTlLcUd3WVlUU2svR1NOeXBYQ2NnMWhnK1V2aytOeVVMNzJGdVZXMU1JS3BSaGNCcmxkVjEwQ01mQXNBdWNhS1lMZWZobnZwcHBkN1R4bUVDRUNYdnNtSVJkdG5MdkN3djJBT0hMRDl1MHFGbnl4WU13ejBkUWsrdUljWkZhcTJlN0JDSGdTVzlPY0FGMUJlZi9WRGpkMUk5R20wblYwSk9VR2FuaHpLTzJNeitMbnF1V1NEMUUxRmYzaDRGZDMyaXd3Z0FjQno4SzVoYjUyTmV3UXNpRlF4TGZKNVl3dUFqdGhKVWJjRVlUUXRGalBpaXJvSGJmbS8rd25aQ2Zvc05saHRDRjlHV1VEUFFiRU5xbWRVNkxFSXV0RUZyaUlYNWMwMmhnZ0Y1VUQ4eEFkY2QyWXpnR0NidkVJSWdjVGljUjA3NDdpZW9WUHhtSlpGSGdNU2hRUTA5ZW03RGpiRFdrdytkOHJXSUxlazZNaG9iaUg2NFZYdEc3YklMeFZvblBzWmVRSDcvN2M4WUNtL3h4S2IrUW00cXhialBia3BJcW5XallBNlV5WWdhcE1ZVFBBM3RSSUVBamYvOGZEQWM5a2FJMGwyWkRSU3dlTEtPemZlQ3RXRGNDcEdYRHdMNTlTQVg2SUdUN0hVaXdZT1dUOUlrVzkrZHFBemhwWXg1cm4rSy9UOHUzcnNSM2dISlhBRTEyVUNyTkZYaFJYUlN1a2RKVHhhM2dHckR3a1JGaVZ2Wk9BVnhTclVpSEhwWTVpQTlJbXVkOUxSTGpRbDk0a1VtbE9QMVAvN3VlVEhJUHd2elowd0laNVIzZ3M3N0ZOK0NDakIwQ2FicGxoMDBhTXI0VUppUmFOZHdlWUdGV21NNFQ4RU1nY0dnWT0iLCJtYWMiOiI0ZTU4ZmJkNTdkYmY0NGE4NTJjZjlhNDExNzE2YjhlOWM2NTA5OGY2MDA4OTcyZDVlOTljY2JjZDhmMjBhMDUyIiwidGFnIjoiIn0=\",\n \"provider_refresh_token_encrypted\": \"eyJpdiI6IkJGMkdRVHRKM2VTcitKNGcvQWJtUGc9PSIsInZhbHVlIjoicmFyRkxPZ1Rybm1ORXlEVjJ2TXFGTzJtM3hWaFhnUVVHN2ZlR1lRM0I5d3ozbnZTcU5EdzJqRkI2elhyNWhlenRTUXV3bjk0N1JXeklDMVAyUzBKcHc9PSIsIm1hYyI6ImJhODVjMGQyZDE3Y2ExNjc2OWVjYWJiNmFjYWVkODIyMTMyNWVhYTExMTgwYTEyMTU0MzUzZGE1YjQ5YzQ5ZjEiLCJ0YWciOiIifQ==\",\n \"encryption_key\": \"0x01020300788C37CDF66ABE9301A68D5D4866AC0C197E04EEE4D904F20A59991322EBAE252301BEF4B24FF01359E934E5654617E4EEAC0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040CEB00EF45BDEA999A5558889E020110802B925F372F7BEFAF0B45E48686113D1DA430ECFCC07B1F61BA6828CC44235278EDB05C486E8068D0BE737D91\",\n \"sociable_type\": \"user\",\n \"owner_id\": 23460\n }\n]","role_description":"text entry area","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,"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.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":"Expand Selected","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":"Collapse All","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":"Options","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":"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}]...
|
1292623199131388967
|
6686649177355990093
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
namespace Jiminny\Component\SCIM;
use Jiminny\Component\SCIM\Builders\Filters;
class Constants
{
/**
* HTTP codes
*/
public const HTTP_OK = 200;
public const HTTP_CREATED = 201;
public const HTTP_NO_CONTENT = 204;
public const HTTP_NOT_FOUND = 404;
public const HTTP_BAD_REQUEST = 400;
public const HTTP_ACCESS_DENIED = 403;
public const HTTP_ERROR = 501;
/**
* Users resource constants
*/
public const USER_FIRST_NAME = 'givenName';
public const USER_FAMILY_NAME = 'familyName';
public const USER_STATUS = 'Active';
public const USER_USERNAME = 'UserName';
public const USER_EXTERNAL_ID = 'externalId';
public const USER_FIELDS = [
self::USER_FIRST_NAME,
self::USER_FAMILY_NAME,
self::USER_STATUS,
self::USER_USERNAME,
];
public const META_OPERATIONS_REPLACE = 'replace';
public const META_OPERATIONS_REPLACE_UPPER = 'Replace';
public const META_OPERATIONS_ADD = 'add';
public const META_OPERATIONS_ADD_UPPER = 'Add';
public const META_OPERATIONS_REMOVE_UPPER = 'Remove';
public const META_OPERATIONS_REMOVE = 'remove';
public const META_ID = 'id';
public const META_PHONE_NUMBERS = 'phoneNumbers';
public const META_TITLE = 'title';
public const META_ROLES = 'roles';
public const META_PATH = 'path';
public const META_ENTERPRISE_SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';
public const META_DEPARTMENT = 'department';
public const META_META = 'meta';
public const META_TYPE = 'type';
public const META_VALUE = 'value';
public const META_OPERATIONS = 'Operations';
public const META_OP = 'op';
public const META_RESOURCE_TYPE = 'resourceType';
public const META_CREATED = 'created';
public const META_LAST_MODIFIED = 'lastModified';
public const META_FORMATTED = 'formatted';
public const META_EMAILS = 'emails';
public const META_USERNAME = 'userName';
public const META_NAME = 'name';
public const META_STATUS = 'active';
public const META_PRIMARY = 'primary';
public const META_ERROR_STATUS = 'status';
public const META_ERROR_DETAIL = 'detail';
public const META_LIST_TOTAL_RESULTS = 'totalResults';
public const META_LIST_RESOURCES = 'Resources';
public const META_LIST_START_INDEX = 'startIndex';
public const META_LIST_COUNT = 'count';
public const META_LIST_ITEMS_PER_PAGE = 'itemsPerPage';
public const META_SCHEMAS = 'schemas';
public const META_FILTER = 'filter';
public const META_TYPE_WORK = 'work';
public const META_PHONE_NUMBER_TYPE_MOBILE = 'mobile';
public const META_EMAIL_TYPE_HOME = 'home';
public const META_CONTAINER_NAME = 'name';
public const META_CONTAINER_EMAILS = 'emails';
public const RESOURCE_TYPE_USER = 'User';
public const USER_PATCH_ATTR_TITLE = 'title';
public const USER_PATCH_ATTR_ACTIVE = 'active';
public const USER_PATCH_ATTR_USERNAME = 'userName';
public const USER_PATCH_ATTR_FIRST_NAME = 'name.givenName';
public const USER_PATCH_ATTR_LAST_NAME = 'name.familyName';
public const USER_PATCH_ATTR_PRIMARY_EMAIL = 'emails[type eq "work"].value';
public const USER_PATCH_ATTR_SECONDARY_EMAIL = 'emails[type eq "home"].value';
public const USER_PATCH_ATTR_PHONE_NUMBER = 'phoneNumbers[type eq "work"].value';
public const USER_PATCH_ATTR_PHONE_NUMBER_MOBILE = 'phoneNumbers[type eq "mobile"].value';
public const USER_PATCH_ATTR_ROLES = 'roles';
public const USER_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [
self::USER_PATCH_ATTR_TITLE => Mutators\Attributes\User\TitleAttr::class,
self::USER_PATCH_ATTR_ACTIVE => Mutators\Attributes\User\ActiveAttr::class,
self::USER_PATCH_ATTR_USERNAME => Mutators\Attributes\User\UsernameAttr::class,
self::USER_PATCH_ATTR_FIRST_NAME => Mutators\Attributes\User\FirstNameAttr::class,
self::USER_PATCH_ATTR_LAST_NAME => Mutators\Attributes\User\LastNameAttr::class,
self::USER_PATCH_ATTR_PRIMARY_EMAIL => Mutators\Attributes\User\PrimaryEmailAttr::class,
self::USER_PATCH_ATTR_SECONDARY_EMAIL => Mutators\Attributes\User\SecondaryEmailAttr::class,
self::USER_PATCH_ATTR_PHONE_NUMBER => Mutators\Attributes\User\PhoneNumberPrimaryAttr::class,
self::USER_PATCH_ATTR_PHONE_NUMBER_MOBILE => Mutators\Attributes\User\PhoneNumberSecondaryAttr::class,
self::USER_PATCH_ATTR_ROLES => Mutators\Attributes\User\RoleAttr::class,
];
public const FILTER_OPERATOR_EQ = 'eq';
public const SUPPORTED_FILTERS_OPERATORS = [
self::FILTER_OPERATOR_EQ,
];
public const USER_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [
self::USER_FILTER_LOCAL_ID => Filters\User\LocalIdFilter::class,
self::USER_FILTER_USERNAME => Filters\User\UserNameFilter::class,
self::USER_FILTER_FIRST_NAME => Filters\User\FirstNameFilter::class,
self::USER_FILTER_LAST_NAME => Filters\User\LastNameFilter::class,
self::USER_FILTER_EXTERNAL_ID => Filters\User\ExternalIdFilter::class,
self::USER_FILTER_DISPLAY_NAME => Filters\User\DisplayNameFilter::class,
];
public const USER_FILTER_LOCAL_ID = 'id';
public const USER_FILTER_USERNAME = 'userName';
public const USER_FILTER_FIRST_NAME = 'givenName';
public const USER_FILTER_LAST_NAME = 'familyName';
public const USER_FILTER_EXTERNAL_ID = 'externalId';
public const USER_FILTER_DISPLAY_NAME = 'DisplayName';
public const SCIM_SUPPORTED_RESOURCES = [
self::USER_RESOURCE_PREFIX,
self::GROUP_RESOURCE_PREFIX,
];
public const USER_RESOURCE_PREFIX = 'Users';
public const GROUP_RESOURCE_PREFIX = 'Groups';
public const OUTGOING_SCHEMAS_SUPPORTED = [
self::OUTGOING_CORE_USER,
];
/**
* Outgoing supported schemas
*/
public const OUTGOING_CORE_USER = 'urn:ietf:params:scim:schemas:core:2.0:User';
public const OUTGOING_ERROR = 'urn:ietf:params:scim:api:messages:2.0:Error';
public const OUTGOING_LIST_RESPONSE = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';
public const OUTGOING_CORE_GROUP = 'urn:ietf:params:scim:schemas:core:2.0:Group';
/**
* Groups resource constants
*/
public const GROUP_ATTRIBUTE_DISPLAY_NAME = 'displayName';
public const GROUP_ATTRIBUTE_EXTERNAL_ID = 'externalId';
public const GROUP_ATTRIBUTE_ID = 'id';
public const RESOURCE_TYPE_GROUP = 'Group';
public const GROUP_FILTER_QUERY_NAME = 'filter';
public const GROUP_EXCLUDED_ATTRIBUTES = 'excludedAttributes';
public const GROUP_SUPPORTED_FILTER_ATTRIBUTES = [
self::GROUP_ATTRIBUTE_DISPLAY_NAME,
];
public const GROUP_MEMBERS = 'members';
public const SUPPORTED_PATCH_OPERATIONS = [
self::META_OPERATIONS_ADD,
self::META_OPERATIONS_REPLACE,
self::META_OPERATIONS_REMOVE,
];
public const GROUP_PATCH_ATTRIBUTE_MEMBERS = 'members';
public const GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME = 'displayName';
public const GROUP_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [
self::GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME => Mutators\Attributes\Group\DisplayNameAttr::class,
self::GROUP_PATCH_ATTRIBUTE_MEMBERS => Mutators\Attributes\Group\MembersAttr::class,
];
public const GROUP_FILTER_DISPLAY_NAME = 'displayname';
public const GROUP_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [
self::GROUP_FILTER_DISPLAY_NAME => Filters\Group\DisplayNameFilter::class,
];
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny_jupiter
Sync Changes
Hide This Notification
Code changed:
Hide
19
19
17
Previous Highlighted Error
Next Highlighted Error
SELECT * FROM teams WHERE id = 1;
select * from crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 283;
SELECT * FROM crm_fields WHERE id = 2234;
SELECT * FROM crm_field_values WHERE crm_field_id = 2234;
select * from crm_profiles where user_id = 143;
select * from record_types where crm_configuration_id = 39; # 0121K000001MHElQAO,0121K000001MHEqQAO
select * from business_processes where crm_configuration_id = 39;
# 01941000000H669AAC, 01941000000H66JAAS
select * from record_type_field_values
where record_type_id IN (24);
select * from crm_field_values where id IN (2730);
select * from crm_configurations where id = 39;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce'; #1035
select * from users where team_id = 1; # 222 group 3
SELECT * FROM activities WHERE user_id = 222 order by id desc;
select * from sidekick_settings where team_id = 1;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from activities where crm_configuration_id = 2
and provider = 'ms-teams' and id = 608765;
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id = '59523413338';
select * from sidekick_settings where team_id = 2;
SELECT * FROM activities WHERE id = 608660;
select * from activity_summary_logs where activity_id = 608660;
select * from ai_prompts where transcription_id = 11214;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('ed78a437-2804-450e-ab2f-56ab1c641346') = uuid;
# id: 608818, crm: 59628809737
SELECT * FROM activities WHERE uuid_to_bin('36b06e55-afdd-4782-8dee-c624cd0af191') = uuid;
# id: 608821, crm: 59632069252
SELECT ce.start_time, ce.end_time, a.id, a.uuid, crm_provider_id, calendar_event_id, title,
playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id,
scheduled_start_time, scheduled_end_time, actual_start_time, actual_end_time, a.created_at
FROM activities a
join calendar_events ce on a.calendar_event_id = ce.id
WHERE a.id IN (608818, 608821);
select * from users where team_id = 1;
select * from team_settings where team_id = 1;
select * from crm_profiles where crm_configuration_id = 39 order by user_id;
select * from team_features where team_id = 1;
select * from users where team_id = 2;
SELECT * FROM activities WHERE uuid_to_bin('ec7647e9-5225-458b-b475-f31aa2769204') = uuid; # 612639
# Preslava N. Ivanova, grou id 3
SELECT * FROM opportunities WHERE uuid_to_bin('a2928fe5-aec5-46cb-85d9-7654c89e46a6') = uuid;
select * from activities where opportunity_id = 344 and actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00';
select
a.id,
a.type,
a.scheduled_start_time,
a.actual_start_time,
a.created_at,
a.opportunity_id,
a.status
FROM activities a
WHERE opportunity_id = 344
and status IN ('completed', 'received', 'delivered')
and (
(a.actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')
OR (a.created_at between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')
OR (a.scheduled_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00'))
;
SELECT * FROM users WHERE id = 222;
SELECT * FROM crm_profiles WHERE user_id = 222;
select * from crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 281;
select * from group_deal_risk_types;
select * from opportunities where team_id = 1;
SELECT * FROM opportunities WHERE id = 315;
SELECT * FROM crm_field_data WHERE object_id = 315;
select * from crm_field_data where object_id = 260;
select * from generic_ai_prompts where subject_id = 315;
select * from teams; # 36, 21, 121, [EMAIL]
SELECT * FROM social_accounts WHERE sociable_id = 121 and provider = 'bullhorn';
# [PASSWORD_DOTS]
select * from teams where id = 1;
select * from crm_configurations where id = 39;
select * from users where team_id = 1;
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 1;
# 1 - 00541000004281rAAA
# 204 - 0052g000003freeAAA
# 429 - 0052g000003qGOiAAM
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce';
select * from activities where type = 'softphone'
and created_at > '2024-12-11 15:24:36' order by id desc;
select * from activity_providers where team_id = 1;
select * from activity_provider_users where activity_provider_id = 328;
select * from opportunities where crm_configuration_id = 39
AND account_id = 178 AND is_closed = false
order by created_at DESC;
select * from contacts where id = 3952;
select * from accounts where id = 178;
# [PASSWORD_DOTS]
select * from teams where id = 36;
select * from crm_configurations where id = 21;
select * from users where team_id = 36;
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 36;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 36
and sa.provider = 'bullhorn';
select * from social_accounts where id = 348;
UPDATE social_accounts SET
provider_user_token = '21442_6802599_91:41179a58-21e7-4d7c-ad58-56bb666b2f65',
provider_refresh_token = '21442_6802599_91:01c6b335-3f2a-42e4-85ff-8a08fa65fceb',
expires = 1733998131,
state = 'connected'
WHERE id = 348;
# [PASSWORD_DOTS]
select * from teams where id = 31;
select * from crm_configurations where id = 18;
select * from users where team_id = 31; # 257
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 31;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 31
and sa.provider = 'close';
select * from contacts where crm_configuration_id = 18;
# [PASSWORD_DOTS] NEPTUNE [PASSWORD_DOTS]
select * from teams;
select * from users where id IN (1030, 1035, 1052);
select * from crm_configurations;
select * from users where team_id = 65; # 257
select * from team_settings where team_id = 65; # 257
select * from invitations where team_id = 65; # 257
select * from users where email = '[EMAIL]'; # 257
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 65;
select * from crm_configurations where id = 53;
select * from accounts where crm_configuration_id = 53 order by id desc;
select * from leads where crm_configuration_id = 53 order by id desc;
select * from contacts where crm_configuration_id = 53 order by id desc;
select * from opportunities where crm_configuration_id = 53 order by id desc;
select * from crm_profiles where crm_configuration_id = 53 order by id desc;
select * from crm_fields where crm_configuration_id = 53 order by id desc;
select * from crm_field_values where crm_field_id = 3341 order by id desc;
select * from crm_layouts where crm_configuration_id = 53 order by id desc;
select * from stages where crm_configuration_id = 53 order by id desc;
select * from crm_profiles where crm_configuration_id = 13;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 65
and sa.provider = 'integration-app';
select * from contacts where crm_configuration_id = 13;
select * from social_accounts where sociable_id = 283;
SELECT * FROM opportunities WHERE crm_provider_id = '006O400000E9bzeIAB';
select * from activity_providers where team_id = 65;
SELECT * FROM activities WHERE crm_configuration_id IN (51, 52, 53);
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 65
;
# [PASSWORD_DOTS] STAGING [PASSWORD_DOTS]
SELECT * FROM teams;
SELECT * FROM teams WHERE id = 88;
SELECT * FROM teams WHERE id = 89;
select * from team_settings where team_id = 89;
SELECT * FROM users WHERE team_id = 89;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 89;
select * from users;
SELECT * FROM social_accounts WHERE sociable_id = 1761;
SELECT * FROM crm_configurations WHERE id = 70;
select * from accounts where crm_configuration_id = 70 order by id desc;
select * from leads where crm_configuration_id = 70 order by id desc;
select * from contacts where crm_configuration_id = 70 order by id desc;
select * from opportunities where crm_configuration_id = 70 order by id desc;
select * from crm_profiles where crm_configuration_id = 70 order by id desc;
select * from crm_fields where crm_configuration_id = 70 order by id desc;
select * from crm_field_values where crm_field_id = 3536 order by id desc;
select * from crm_layouts where crm_configuration_id = 70 order by id desc;
select * from stages where crm_configuration_id = 70 order by id desc;
select * from business_processes where crm_configuration_id = 70 order by id desc;
select * from business_process_stages where business_process_id = 34;
select * from contacts where id = 10468;
select * from crm_layouts where crm_configuration_id = 70;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 388;
SELECT * FROM crm_fields WHERE id IN (3533,3534,3535);
select * from activities where crm_configuration_id = 70
and (account_id IS NOT NULL or lead_id IS NOT NULL or contact_id IS NOT NULL or opportunity_id IS NOT NULL) order by id desc;
SELECT * FROM activities WHERE uuid_to_bin('2e10b60f-8a61-41c5-a3d4-28835353dc65') = uuid;
SELECT * FROM activities where crm_configuration_id = 69 ;
SELECT * FROM users WHERE email LIKE '%[EMAIL]%';
SELECT * FROM activities WHERE uuid_to_bin('5a150c93-40fc-42ec-b3bd-c1d328e09f6e') = uuid;
SELECT * FROM opportunities WHERE id = 385;
select * from participants p
join activities a on p.activity_id = a.id
where a.crm_configuration_id = 70
and (p.lead_id IS NOT NULL or p.contact_id IS NOT NULL);
SELECT * FROM participants WHERE id = 1013638;
select * from teams where id = 90;
select * from users where team_id = 90;
select * from social_accounts where social_accounts.sociable_id IN (1960,1760);
SELECT * FROM crm_profiles WHERE crm_configuration_id = 71;
select * from invitations where team_id = 90;
select * from crm_configurations where id = 71;
select * from accounts where crm_configuration_id = 71 order by id desc;
select * from leads where crm_configuration_id = 71 order by id desc;
select * from contacts where crm_configuration_id = 71 order by id desc;
select * from opportunities where crm_configuration_id = 71 order by id desc;
select * from crm_profiles where crm_configuration_id = 71 order by id desc;
select * from crm_fields where crm_configuration_id = 71 order by id desc;
select * from crm_field_values where crm_field_id = 3341 order by id desc;
select * from crm_layouts where crm_configuration_id = 71 order by id desc;
select * from stages where crm_configuration_id = 71 order by id desc;
select * from users order by secondary_email desc;
select u.id, u.email, u.status, sa.id, sa.provider_user_id from social_accounts sa
join users u on sa.sociable_id = u.id
where sa.provider = 'google' and u.email LIKE 'aneliya%';
select * from failed_jobs order by id desc;
select * from users where email = '[EMAIL]' or secondary_email = '[EMAIL]';
select * from teams;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 39;
SELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type = 'task';
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce';
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('c38b3895-fd0f-4b1f-9fb2-c170dba137c6') = uuid;
SELECT * FROM crm_configurations WHERE id = 70;
select * from teams where id = 1;
select * from groups where team_id = 1;
select * from users where team_id = 1;
select o.id, o.name,o.close_date, u.id, u.name, u.group_id, r.id, r.display_name, g.name, g.scope from opportunities o
join users u on o.user_id = u.id
join groups g on u.group_id = g.id
join role_user ru on u.id = ru.user_id
join roles r on ru.role_id = r.id
where o.crm_configuration_id = 39 and close_date > '2024-01-01 00:00:00';
select * from role_user where user_id = 143;
select * from roles;
select * from role_user;
select * from groups where id = 9;
select * from scope_groups where group_id = 9;
# [PASSWORD_DOTS]
select * from teams where id = 36;
select * from crm_configurations;
SELECT * FROM social_accounts WHERE sociable_id = 121;
https://crmsandbox.zoho.com/crm/jiminnyw4/tab/Leads/4776201000005049105
https://crmsandbox.zoho.com/crm/
https://crm.zoho.com/crm/org3469620/tab/Leads/230045000229559080
https://crm.zoho.com/crm/
org3469620
SELECT * FROM activities WHERE uuid_to_bin('03382d20-c8bc-48e7-a3d4-90b52fa5ceab') = uuid;
select * from users where email LIKE "%mobile_automation_%";
select * from social_accounts where sociable_id IN (2228);
select * from crm_profiles where user_id IN (2222,2223,2226,2227);
select * from teams order by id desc;
SELECT * FROM users WHERE id = 2229;
SELECT * FROM crm_profiles WHERE user_id = 2229;
select * from opportunities where crm_configuration_id = 88;
select * from crm_fields where crm_configuration_id = 88;
select * from crm_profiles where crm_configuration_id = 88;
SELECT * FROM teams WHERE id = 1;
SELECT * FROM users WHERE id = 143;
SELECT * FROM users WHERE uuid_to_bin('fde193d3-06a2-4e1a-8895-62b94039215d') = uuid;
SELECT * FROM teams WHERE uuid_to_bin('73385071-a756-42ae-9c73-8b53f2309467') = uuid;
https://app.staging.jiminny.com/ondemand?
min_duration=1
&
only_recorded=1
&
user_id%5B%5D=641f1acb-16b8-42d1-8726-df52979dad0e
&
sequence_number=2
select * from users where team_id = 1 and email like '%stoyan%'
select * from coaching_feedbacks;
select * from teams;
SELECT * FROM users WHERE team_id = 36;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 19
and sa.provider = 'pipedrive';
select * from users where id = 143;
SELECT * FROM users WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
SELECT * FROM teams WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
SELECT * FROM activity_shares WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
select * from users where team_id = 2;
select * from activities where crm_configuration_id = 39
and activities.scheduled_start_time BETWEEN '2025-04-09 00:00:00' AND '2025-04-09 23:59:59'
AND user_id = 143
order by id desc;
# [PASSWORD_DOTS]
select * from teams where id = 142; # 2312, 126
select * from team_settings;
select * from users where team_id = 142; # 21642
SELECT * FROM social_accounts WHERE sociable_id = 21642;
SELECT * FROM crm_profiles cp join users u ON u.id = cp.user_id WHERE team_id = 142;
select * from crm_profiles where id IN (93);
select * from invitations;
select * from team_features where team_id = 1;
SELECT * FROM crm_configurations WHERE id = 126;
select * from accounts where crm_configuration_id = 126 order by id desc;
select * from leads where crm_configuration_id = 126 order by id desc;
select * from contacts where crm_configuration_id = 126 order by id desc;
select * from opportunities where crm_configuration_id = 126 order by id desc;
select * from crm_profiles where crm_configuration_id = 126 order by id desc;
select * from crm_fields where crm_configuration_id = 126 # 11060
# and type IN ('picklist', 'status')
# and object_type = 'task'
order by id desc;
# 5731,5732,5733
select DISTINCT crm_field_id from crm_field_values where crm_field_id IN (11151,12239,12215,12185,12175,12165,12144,12137,12127,12109,12107,12105,12103,12092,12037,12005,12003,11987,11969,11958,11951,11942,11931,11924,11921,11917,11915,11901,11893,11883,11872,11870,11868,11866,11839,11833,11821,11793,11780,11777,11769,11757,11737,11735,11656,11645,11638,11629,11618,11611,11602,11591,11584,11581,11558,11544,11543,11534,11532,11529,11527,11503,11497,11493,11488,11470,11468,11457,11455,11397,11387,11372,11363,11348,11323,11318,11309,11301,11300,11292,11290,11286,11284,11256,11252,11242,11237,11233,11219,11176,11160) order by id desc;
select * from crm_layouts where crm_configuration_id = 126 order by id desc;
SELECT * FROM crm_layout_entities WHERE crm_layout_id in (300,299,298);
select * from stages where crm_configuration_id = 126 order by id desc;
select * from business_processes where crm_configuration_id = 126 order by id desc;
select * from business_process_stages where business_process_id IN (76,75,74,73);
select * from playbooks where team_id = 142;
select * from playbook_layouts where playbook_id IN (108);
SELECT * FROM playbook_categories WHERE playbook_id IN (108);
select * from teams where id = 130;
SELECT * FROM social_accounts WHERE sociable_id = 2291;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 2
and sa.provider = 'hubspot';
SELECT * FROM activities
WHERE crm_configuration_id = 110;
select * from teams;
select * from crm_configurations;
SELECT * FROM activities WHERE id = 628773;
SELECT * FROM crm_profiles WHERE user_id = 1460;
SELECT * FROM social_accounts WHERE sociable_id = 2291;
select * from teams;
select ru.*, pr.*, p.* from users u join role_user ru on ru.user_id = u.id
join permission_role pr on pr.role_id = ru.role_id
join permissions p on p.id = pr.permission_id
where team_id = 495 and p.name IN ('dial');
select * from teams where id = 145;
select * from crm_configurations where id = 129;
select * from social_accounts where sociable_id = 2317;
SELECT * FROM activities WHERE uuid_to_bin('8dbab184-a333-4268-ad57-fb41f8d53a9a') = uuid;
select * from teams where id = 1;
SELECT * FROM crm_layouts WHERE crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 280;
SELECT * FROM crm_layout_entities WHERE id = 5507;
SELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type IN ('event');
select * from teams;
select * from activities where crm_configuration_id = 14;
SELECT * FROM social_accounts where provider = 'copper';
select * from activities where id = 628467;
select * from participants where activity_id = 628467;
SELECT * FROM contacts WHERE id = 3969;
SELECT * FROM accounts WHERE id = 177;
SELECT * FROM activities WHERE uuid_to_bin('4eb54c77-cfa3-2bd4-84a7-9ed46a21c988') = uuid;
# [PASSWORD_DOTS] BH
select * from teams where id = 36;
SELECT * FROM crm_configurations WHERE id = 21;
select * from activities where crm_configuration_id = 21 and id = 607901;
select * from activities where crm_configuration_id = 21;
select * roles;
select * from permissions;
select * from permission_role where permission_id = 226;
select * from migrations order by id desc;
# mercury
# neptune
# earth
select * from teams;
select * from teams where id = 19;
select * from teams where id = 27;
select * from users where team_id = 27;
SELECT * FROM crm_configurations WHERE id = 42;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 19
and sa.provider = 'pipedrive';
select * from activities where id = 631461;
SELECT * FROM crm_field_values WHERE crm_field_id = 180;
select * from teams where id = 2;
SELECT * FROM social_accounts WHERE sociable_id = 89;
SELECT * FROM activities WHERE uuid_to_bin('ba0c029a-bc14-4e17-8603-64174acebcbb') = uuid; # 634273
select * from activity_summary_logs where activity_id = 634273;
select * from sidekick_settings where team_id = 2;
select * from teams; # 2, 2
SELECT * FROM crm_configurations WHERE team_id = 2; # 2
select * from team_features where team_id = 2;
select * from features;
SELECT * FROM opportunities WHERE crm_configuration_id = 2 and crm_provider_id = '51317301383';
SELECT * FROM opportunities WHERE crm_configuration_id = 2 order by id desc;
select * from automated_reports order by id desc;
select * from automated_report_results order by id desc;
select * from users where team_id = 1 and id IN (7160, 3248);
select * from migrations order by id desc;
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 = 1052 and sa.provider = 'hubspot';
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 = 565;
select * from playbooks where team_id = 1;
select * from playbooks where id = 175;
select * from playbook_categories where playbook_id = 175;
select * from users where team_id = 1052;
select * from users where id = 7160;
select * from crm_profiles where user_id = 7160;
select * from features;
select
*
# id, uuid, type, provider, playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id, stage_id,
# crm_configuration_id, crm_provider_id, transcription_id, status
from activities where crm_configuration_id = 1 and type = 'conference'
# and crm_provider_id IS NOT NULL
and provider != 'uploader' and actual_start_time IS NOT NULL
ORDER by id desc;
select * from activities where id = 54747783; # 00UO400000pCzojMAC
select p.id, p.activity_type, pc.id, pc.name
FROM playbooks p
join playbook_categories pc on p.id = pc.playbook_id
where p.team_id = 1 and p.activity_type = 'event';
SELECT * FROM crm_fields WHERE crm_configuration_id = 1 and object_type = 'event';
SELECT * FROM crm_field_values WHERE crm_field_id = 4;
select * from crm_layouts cl join playbook_layouts pl on cl.id = pl.layout_id
where crm_configuration_id = 1 and pl.playbook_id = 175;
select * from teams;
SELECT r.* FROM automated_reports r
join teams t on r.team_id = t.id
WHERE r.frequency = 'daily'
and r.status = 1
AND t.status = 'active'
AND (r.expires_at >= now() OR r.expires_at IS NULL);
select * from automated_report_results where report_id IN (18, 33);
select * from users where team_id = 1 and id = 1047;
SELECT * FROM social_accounts WHERE sociable_id = 1047;
select * from activity_searches where id = 10932;
select * from activity_search_filters where activity_search_id = 10932;
select * from automated_reports order by id desc;
select * from automated_report_results order by id desc;
select * from automated_reports where id IN (55);
select * from automated_report_results where id IN (81);
select * from users where id IN (10633, 13987, 11985);
select * from users where group_id IN (3710);
SELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;
SELECT * FROM automated_report_results WHERE uuid_to_bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;
select * from teams;
select * from accounts where team_id = 1;
select * from automated_report_results where media_type = 'pdf' and status = 2;
SELECT * FROM automated_report_results WHERE uuid_to_bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid;
select * from teams where id = 1029;
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 = 1029 and sa.provider = 'pipedrive';
[
{
"user_id": "23460 (owner)",
"email": "[EMAIL]",
"id": 69,
"sociable_id": 23460,
"provider_user_id": "19555731",
"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,
"refresh_token_expires": null,
"provider": "pipedrive",
"state": "connected",
"auth_scope": "base,deals:full,activities:full,contacts:full,search:read",
"retry_after": null,
"created_at": "2025-04-16 08:23:28",
"updated_at": "2026-05-18 07:13:18",
"provider_user_token_encrypted": "eyJpdiI6Ik9oYzBwcTVteWN4ajBRaDdMb0FjWGc9PSIsInZhbHVlIjoiQUNMbjU5UHR2Q1RnbWRXMEU1TUx6UVpRU3gzdVc5WktmTE4rVlhXa3lRaGhyUUlZMVZRWEJuR0JaWWhZZXNPRlBuanhuYU5MVHZ5TG9NTVVjNjJSUUpZZ2VhbGYxbHg0UzJEdTVmQjNFZnJRZkMwYjd0N2RMZ05GRS9IR3c2K0NoVjBjYTA5UG12SkxHeDlDMGVNN3ptUWUzblFiTngyYzR1eUpHSEYrdEwvZm0yZklGYjBSNEtTR2ZGazhLM1hqT3lVbjFobDNPZ0d3anFlcjhKcXpERlZGOVN1YmFyNDIvM1BFRDFMYnp4WEI4TGVLM2xYcy9CL0RDOWlQNHI3N0NwWnJPMWRtZllmM2ZKeE9TV2NBeDZxL2M1YnlSVzd3ZW96T3F1QmtBYXBHYkUraGcvdCtRajlYZXBjVVBSdFlMUjVPVDVJbDdyenVoWjMrbVJvU3ZZR1dQZ3pqQ3F3aDF2U2xPZWZIN3BCWVFLNXpxQUtDb2pIK0xHc1E3SklSM3Q0VkNSbm9oK2pFK3hLaW54T1dWbEVneUp0RGhhdVBuOFI4MXROc3dZWnFnTUpiaDVMMnZ4QmlRM3k4QWFlMVFWUFYvdGhJQzZBYnhBQmhWa2ZKN1ZhSnhpaExxbmlTemgzUWw3aXJtWjlSMlhmd0lWMDNDN1N3My9Ua0hCL2xqY3RkVFhMSjFJMDRjOE5DWlgrZ3FMVXN6RWlwUE5GWERZdG1xVjVxOFlLRGs2VVJKS3FLeWRxQjYxdDh4Z2JJNXhlWEZ3dkQ4SGtybDNUcndzblFHeVJNRkYraFh2UDFIUTdMQ1BZa3dEU1dBbzk5K0dyT2RNVFBZZUJpRytSck5pYlI1YUZyMmhUNEZCdWxHYmJLREtzbUpjVkhvV0RoejJpbm1SWHlNaXE5M0RhcS94UW9EdFoweWF3bVFVY0dTZWFPSXBmOCtDYndia215cmtyZU1oT0Exam1CV2tPblNhYjY4clVEeUs3anVHUmNHeS9YLzRha1VhbGl3N3lwaDlzZnRhQUZta2s4eFllNHgzRklSRmNyazJ4dlBDMnByNCtBRjNaVjJCTT0iLCJtYWMiOiJkYTQxZDY1OTY2ZTljMTgyZWRhNGEzMGZjZDc2MjBjN2NlNzU2YTViNGQxNWE1NTI2ZmI1MWQyYjQ2ODYxZmEwIiwidGFnIjoiIn0=",
"provider_refresh_token_encrypted": "eyJpdiI6Imt2bGxlSmxUK05GMjF0dEtPaTMrUlE9PSIsInZhbHVlIjoiUXZHTElZRXkreHFxUU02SnZ4eVBacG9WWTRlVkd0USszV3JyVFlpU2ZaY25GSWo2WFcrRzNlbFRlUXRQczNwSXRCcEdvZEpveG9jMzBDSTgwdnZLQnc9PSIsIm1hYyI6ImQxYWI0NzU5Nzg5MDI4YWVhZmQ4Mjg1YzhkZDQzMjRkYWYwYTdhZTY5MDMxMjc0OWNiYjY0Nzc3NDQ0MTEyY2EiLCJ0YWciOiIifQ==",
"encryption_key": "0x01020300786192D9D96DD60D3D1EBC9DFAEE5F0C45EE80165CF3F3D2B3B627026AA7CFC7CA0128DD463535D32EE491ADBADF8B07596B0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040C7FB1319048ECB2EA3F23B995020110802B52D22F5EAD341AB238FBBCB6093156E443876A664BA5555D722565C2B2D04422C868CD7350555E3CC74221",
"sociable_type": "user",
"owner_id": 23460
},
{
"user_id": "23463",
"email": "[EMAIL]",
"id": 72,
"sociable_id": 23463,
"provider_user_id": "23270841",
"provider_user_token": "v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:txqCuWLeVhgwiaFqXIvQWWrtrnFIy_4lT3VCr-sRB4g6_2lK8KcQ_6ka_qFmZhr-IeIAKmAImx6H1iIKx4Ab7XZ5MnKIh03GKbHjI0n0rGT9UYkeH21jKOxJvKaSX_TyLbxFPR6irPQyvqcpBClXI52gVJH01KzZy_dMTHFXhhDLOIhEpSrQXHG7Qo8q7OuBeSPZrU1ALi9kmAm4GTpzGTbzfl-hUt9IAfPunJOCyv3mf2Tl-MT8EyQgOFPrsP3yz9UlSyVhb40zO_bCnUrqNxjwgm_E6vgpVrwULTQbHe-43Dq-TRetjceUzT88GBgVJ0UdxXP5BRBVXcL5ir8-9ZTMaNU",
"provider_refresh_token": "5034113:[TELEGRAM_TOKEN]78ad1",
"expires": 1753837219,
"refresh_token_expires": null,
"provider": "pipedrive",
"state": "full-refresh",
"auth_scope": "base,deals:full,activities:full,contacts:full,search:read",
"retry_after": null,
"created_at": "2025-04-16 10:41:12",
"updated_at": "2025-07-30 01:00:17",
"provider_user_token_encrypted": "eyJpdiI6InVEVEl2SzIxMjd1bkNDWG9lY3YvQ0E9PSIsInZhbHVlIjoiRlJLbDZ3ZHo2dHMxUWQwdGU2YUZjV3lPWHlxQTJ0eWh4S0RTMjlSaThVcktoaWhXcTd2UXl4Mjg4bW5UUnZCZEQ5NXpuQTVKOURiMDNIa3l3K0lSWCt5azRBOEdHbitWQXhxeEpMVUZ1dnF2NVl1TTZLelZOaGNvRlBLeGpIWlpoRGloUEprd2xoNUFPcTlLcUd3WVlUU2svR1NOeXBYQ2NnMWhnK1V2aytOeVVMNzJGdVZXMU1JS3BSaGNCcmxkVjEwQ01mQXNBdWNhS1lMZWZobnZwcHBkN1R4bUVDRUNYdnNtSVJkdG5MdkN3djJBT0hMRDl1MHFGbnl4WU13ejBkUWsrdUljWkZhcTJlN0JDSGdTVzlPY0FGMUJlZi9WRGpkMUk5R20wblYwSk9VR2FuaHpLTzJNeitMbnF1V1NEMUUxRmYzaDRGZDMyaXd3Z0FjQno4SzVoYjUyTmV3UXNpRlF4TGZKNVl3dUFqdGhKVWJjRVlUUXRGalBpaXJvSGJmbS8rd25aQ2Zvc05saHRDRjlHV1VEUFFiRU5xbWRVNkxFSXV0RUZyaUlYNWMwMmhnZ0Y1VUQ4eEFkY2QyWXpnR0NidkVJSWdjVGljUjA3NDdpZW9WUHhtSlpGSGdNU2hRUTA5ZW03RGpiRFdrdytkOHJXSUxlazZNaG9iaUg2NFZYdEc3YklMeFZvblBzWmVRSDcvN2M4WUNtL3h4S2IrUW00cXhialBia3BJcW5XallBNlV5WWdhcE1ZVFBBM3RSSUVBamYvOGZEQWM5a2FJMGwyWkRSU3dlTEtPemZlQ3RXRGNDcEdYRHdMNTlTQVg2SUdUN0hVaXdZT1dUOUlrVzkrZHFBemhwWXg1cm4rSy9UOHUzcnNSM2dISlhBRTEyVUNyTkZYaFJYUlN1a2RKVHhhM2dHckR3a1JGaVZ2Wk9BVnhTclVpSEhwWTVpQTlJbXVkOUxSTGpRbDk0a1VtbE9QMVAvN3VlVEhJUHd2elowd0laNVIzZ3M3N0ZOK0NDakIwQ2FicGxoMDBhTXI0VUppUmFOZHdlWUdGV21NNFQ4RU1nY0dnWT0iLCJtYWMiOiI0ZTU4ZmJkNTdkYmY0NGE4NTJjZjlhNDExNzE2YjhlOWM2NTA5OGY2MDA4OTcyZDVlOTljY2JjZDhmMjBhMDUyIiwidGFnIjoiIn0=",
"provider_refresh_token_encrypted": "eyJpdiI6IkJGMkdRVHRKM2VTcitKNGcvQWJtUGc9PSIsInZhbHVlIjoicmFyRkxPZ1Rybm1ORXlEVjJ2TXFGTzJtM3hWaFhnUVVHN2ZlR1lRM0I5d3ozbnZTcU5EdzJqRkI2elhyNWhlenRTUXV3bjk0N1JXeklDMVAyUzBKcHc9PSIsIm1hYyI6ImJhODVjMGQyZDE3Y2ExNjc2OWVjYWJiNmFjYWVkODIyMTMyNWVhYTExMTgwYTEyMTU0MzUzZGE1YjQ5YzQ5ZjEiLCJ0YWciOiIifQ==",
"encryption_key": "0x01020300788C37CDF66ABE9301A68D5D4866AC0C197E04EEE4D904F20A59991322EBAE252301BEF4B24FF01359E934E5654617E4EEAC0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040CEB00EF45BDEA999A5558889E020110802B925F372F7BEFAF0B45E48686113D1DA430ECFCC07B1F61BA6828CC44235278EDB05C486E8068D0BE737D91",
"sociable_type": "user",
"owner_id": 23460
}
]
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
53220
|
1867
|
8
|
2026-05-18T11:51:33.364300+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779105093364_m2.jpg...
|
PhpStorm
|
faVsco.js – Constants.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
namespace Jiminny\Component\SCIM;
use Jiminny\Component\SCIM\Builders\Filters;
class Constants
{
/**
* HTTP codes
*/
public const HTTP_OK = 200;
public const HTTP_CREATED = 201;
public const HTTP_NO_CONTENT = 204;
public const HTTP_NOT_FOUND = 404;
public const HTTP_BAD_REQUEST = 400;
public const HTTP_ACCESS_DENIED = 403;
public const HTTP_ERROR = 501;
/**
* Users resource constants
*/
public const USER_FIRST_NAME = 'givenName';
public const USER_FAMILY_NAME = 'familyName';
public const USER_STATUS = 'Active';
public const USER_USERNAME = 'UserName';
public const USER_EXTERNAL_ID = 'externalId';
public const USER_FIELDS = [
self::USER_FIRST_NAME,
self::USER_FAMILY_NAME,
self::USER_STATUS,
self::USER_USERNAME,
];
public const META_OPERATIONS_REPLACE = 'replace';
public const META_OPERATIONS_REPLACE_UPPER = 'Replace';
public const META_OPERATIONS_ADD = 'add';
public const META_OPERATIONS_ADD_UPPER = 'Add';
public const META_OPERATIONS_REMOVE_UPPER = 'Remove';
public const META_OPERATIONS_REMOVE = 'remove';
public const META_ID = 'id';
public const META_PHONE_NUMBERS = 'phoneNumbers';
public const META_TITLE = 'title';
public const META_ROLES = 'roles';
public const META_PATH = 'path';
public const META_ENTERPRISE_SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';
public const META_DEPARTMENT = 'department';
public const META_META = 'meta';
public const META_TYPE = 'type';
public const META_VALUE = 'value';
public const META_OPERATIONS = 'Operations';
public const META_OP = 'op';
public const META_RESOURCE_TYPE = 'resourceType';
public const META_CREATED = 'created';
public const META_LAST_MODIFIED = 'lastModified';
public const META_FORMATTED = 'formatted';
public const META_EMAILS = 'emails';
public const META_USERNAME = 'userName';
public const META_NAME = 'name';
public const META_STATUS = 'active';
public const META_PRIMARY = 'primary';
public const META_ERROR_STATUS = 'status';
public const META_ERROR_DETAIL = 'detail';
public const META_LIST_TOTAL_RESULTS = 'totalResults';
public const META_LIST_RESOURCES = 'Resources';
public const META_LIST_START_INDEX = 'startIndex';
public const META_LIST_COUNT = 'count';
public const META_LIST_ITEMS_PER_PAGE = 'itemsPerPage';
public const META_SCHEMAS = 'schemas';
public const META_FILTER = 'filter';
public const META_TYPE_WORK = 'work';
public const META_PHONE_NUMBER_TYPE_MOBILE = 'mobile';
public const META_EMAIL_TYPE_HOME = 'home';
public const META_CONTAINER_NAME = 'name';
public const META_CONTAINER_EMAILS = 'emails';
public const RESOURCE_TYPE_USER = 'User';
public const USER_PATCH_ATTR_TITLE = 'title';
public const USER_PATCH_ATTR_ACTIVE = 'active';
public const USER_PATCH_ATTR_USERNAME = 'userName';
public const USER_PATCH_ATTR_FIRST_NAME = 'name.givenName';
public const USER_PATCH_ATTR_LAST_NAME = 'name.familyName';
public const USER_PATCH_ATTR_PRIMARY_EMAIL = 'emails[type eq "work"].value';
public const USER_PATCH_ATTR_SECONDARY_EMAIL = 'emails[type eq "home"].value';
public const USER_PATCH_ATTR_PHONE_NUMBER = 'phoneNumbers[type eq "work"].value';
public const USER_PATCH_ATTR_PHONE_NUMBER_MOBILE = 'phoneNumbers[type eq "mobile"].value';
public const USER_PATCH_ATTR_ROLES = 'roles';
public const USER_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [
self::USER_PATCH_ATTR_TITLE => Mutators\Attributes\User\TitleAttr::class,
self::USER_PATCH_ATTR_ACTIVE => Mutators\Attributes\User\ActiveAttr::class,
self::USER_PATCH_ATTR_USERNAME => Mutators\Attributes\User\UsernameAttr::class,
self::USER_PATCH_ATTR_FIRST_NAME => Mutators\Attributes\User\FirstNameAttr::class,
self::USER_PATCH_ATTR_LAST_NAME => Mutators\Attributes\User\LastNameAttr::class,
self::USER_PATCH_ATTR_PRIMARY_EMAIL => Mutators\Attributes\User\PrimaryEmailAttr::class,
self::USER_PATCH_ATTR_SECONDARY_EMAIL => Mutators\Attributes\User\SecondaryEmailAttr::class,
self::USER_PATCH_ATTR_PHONE_NUMBER => Mutators\Attributes\User\PhoneNumberPrimaryAttr::class,
self::USER_PATCH_ATTR_PHONE_NUMBER_MOBILE => Mutators\Attributes\User\PhoneNumberSecondaryAttr::class,
self::USER_PATCH_ATTR_ROLES => Mutators\Attributes\User\RoleAttr::class,
];
public const FILTER_OPERATOR_EQ = 'eq';
public const SUPPORTED_FILTERS_OPERATORS = [
self::FILTER_OPERATOR_EQ,
];
public const USER_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [
self::USER_FILTER_LOCAL_ID => Filters\User\LocalIdFilter::class,
self::USER_FILTER_USERNAME => Filters\User\UserNameFilter::class,
self::USER_FILTER_FIRST_NAME => Filters\User\FirstNameFilter::class,
self::USER_FILTER_LAST_NAME => Filters\User\LastNameFilter::class,
self::USER_FILTER_EXTERNAL_ID => Filters\User\ExternalIdFilter::class,
self::USER_FILTER_DISPLAY_NAME => Filters\User\DisplayNameFilter::class,
];
public const USER_FILTER_LOCAL_ID = 'id';
public const USER_FILTER_USERNAME = 'userName';
public const USER_FILTER_FIRST_NAME = 'givenName';
public const USER_FILTER_LAST_NAME = 'familyName';
public const USER_FILTER_EXTERNAL_ID = 'externalId';
public const USER_FILTER_DISPLAY_NAME = 'DisplayName';
public const SCIM_SUPPORTED_RESOURCES = [
self::USER_RESOURCE_PREFIX,
self::GROUP_RESOURCE_PREFIX,
];
public const USER_RESOURCE_PREFIX = 'Users';
public const GROUP_RESOURCE_PREFIX = 'Groups';
public const OUTGOING_SCHEMAS_SUPPORTED = [
self::OUTGOING_CORE_USER,
];
/**
* Outgoing supported schemas
*/
public const OUTGOING_CORE_USER = 'urn:ietf:params:scim:schemas:core:2.0:User';
public const OUTGOING_ERROR = 'urn:ietf:params:scim:api:messages:2.0:Error';
public const OUTGOING_LIST_RESPONSE = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';
public const OUTGOING_CORE_GROUP = 'urn:ietf:params:scim:schemas:core:2.0:Group';
/**
* Groups resource constants
*/
public const GROUP_ATTRIBUTE_DISPLAY_NAME = 'displayName';
public const GROUP_ATTRIBUTE_EXTERNAL_ID = 'externalId';
public const GROUP_ATTRIBUTE_ID = 'id';
public const RESOURCE_TYPE_GROUP = 'Group';
public const GROUP_FILTER_QUERY_NAME = 'filter';
public const GROUP_EXCLUDED_ATTRIBUTES = 'excludedAttributes';
public const GROUP_SUPPORTED_FILTER_ATTRIBUTES = [
self::GROUP_ATTRIBUTE_DISPLAY_NAME,
];
public const GROUP_MEMBERS = 'members';
public const SUPPORTED_PATCH_OPERATIONS = [
self::META_OPERATIONS_ADD,
self::META_OPERATIONS_REPLACE,
self::META_OPERATIONS_REMOVE,
];
public const GROUP_PATCH_ATTRIBUTE_MEMBERS = 'members';
public const GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME = 'displayName';
public const GROUP_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [
self::GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME => Mutators\Attributes\Group\DisplayNameAttr::class,
self::GROUP_PATCH_ATTRIBUTE_MEMBERS => Mutators\Attributes\Group\MembersAttr::class,
];
public const GROUP_FILTER_DISPLAY_NAME = 'displayname';
public const GROUP_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [
self::GROUP_FILTER_DISPLAY_NAME => Filters\Group\DisplayNameFilter::class,
];
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny_jupiter
Sync Changes
Hide This Notification
Code changed:
Hide
19
19
17
Previous Highlighted Error
Next Highlighted Error
SELECT * FROM teams WHERE id = 1;
select * from crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 283;
SELECT * FROM crm_fields WHERE id = 2234;
SELECT * FROM crm_field_values WHERE crm_field_id = 2234;
select * from crm_profiles where user_id = 143;
select * from record_types where crm_configuration_id = 39; # 0121K000001MHElQAO,0121K000001MHEqQAO
select * from business_processes where crm_configuration_id = 39;
# 01941000000H669AAC, 01941000000H66JAAS
select * from record_type_field_values
where record_type_id IN (24);
select * from crm_field_values where id IN (2730);
select * from crm_configurations where id = 39;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce'; #1035
select * from users where team_id = 1; # 222 group 3
SELECT * FROM activities WHERE user_id = 222 order by id desc;
select * from sidekick_settings where team_id = 1;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from activities where crm_configuration_id = 2
and provider = 'ms-teams' and id = 608765;
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id = '59523413338';
select * from sidekick_settings where team_id = 2;
SELECT * FROM activities WHERE id = 608660;
select * from activity_summary_logs where activity_id = 608660;
select * from ai_prompts where transcription_id = 11214;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('ed78a437-2804-450e-ab2f-56ab1c641346') = uuid;
# id: 608818, crm: 59628809737
SELECT * FROM activities WHERE uuid_to_bin('36b06e55-afdd-4782-8dee-c624cd0af191') = uuid;
# id: 608821, crm: 59632069252
SELECT ce.start_time, ce.end_time, a.id, a.uuid, crm_provider_id, calendar_event_id, title,
playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id,
scheduled_start_time, scheduled_end_time, actual_start_time, actual_end_time, a.created_at
FROM activities a
join calendar_events ce on a.calendar_event_id = ce.id
WHERE a.id IN (608818, 608821);
select * from users where team_id = 1;
select * from team_settings where team_id = 1;
select * from crm_profiles where crm_configuration_id = 39 order by user_id;
select * from team_features where team_id = 1;
select * from users where team_id = 2;
SELECT * FROM activities WHERE uuid_to_bin('ec7647e9-5225-458b-b475-f31aa2769204') = uuid; # 612639
# Preslava N. Ivanova, grou id 3
SELECT * FROM opportunities WHERE uuid_to_bin('a2928fe5-aec5-46cb-85d9-7654c89e46a6') = uuid;
select * from activities where opportunity_id = 344 and actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00';
select
a.id,
a.type,
a.scheduled_start_time,
a.actual_start_time,
a.created_at,
a.opportunity_id,
a.status
FROM activities a
WHERE opportunity_id = 344
and status IN ('completed', 'received', 'delivered')
and (
(a.actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')
OR (a.created_at between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')
OR (a.scheduled_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00'))
;
SELECT * FROM users WHERE id = 222;
SELECT * FROM crm_profiles WHERE user_id = 222;
select * from crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 281;
select * from group_deal_risk_types;
select * from opportunities where team_id = 1;
SELECT * FROM opportunities WHERE id = 315;
SELECT * FROM crm_field_data WHERE object_id = 315;
select * from crm_field_data where object_id = 260;
select * from generic_ai_prompts where subject_id = 315;
select * from teams; # 36, 21, 121, [EMAIL]
SELECT * FROM social_accounts WHERE sociable_id = 121 and provider = 'bullhorn';
# [PASSWORD_DOTS]
select * from teams where id = 1;
select * from crm_configurations where id = 39;
select * from users where team_id = 1;
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 1;
# 1 - 00541000004281rAAA
# 204 - 0052g000003freeAAA
# 429 - 0052g000003qGOiAAM
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce';
select * from activities where type = 'softphone'
and created_at > '2024-12-11 15:24:36' order by id desc;
select * from activity_providers where team_id = 1;
select * from activity_provider_users where activity_provider_id = 328;
select * from opportunities where crm_configuration_id = 39
AND account_id = 178 AND is_closed = false
order by created_at DESC;
select * from contacts where id = 3952;
select * from accounts where id = 178;
# [PASSWORD_DOTS]
select * from teams where id = 36;
select * from crm_configurations where id = 21;
select * from users where team_id = 36;
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 36;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 36
and sa.provider = 'bullhorn';
select * from social_accounts where id = 348;
UPDATE social_accounts SET
provider_user_token = '21442_6802599_91:41179a58-21e7-4d7c-ad58-56bb666b2f65',
provider_refresh_token = '21442_6802599_91:01c6b335-3f2a-42e4-85ff-8a08fa65fceb',
expires = 1733998131,
state = 'connected'
WHERE id = 348;
# [PASSWORD_DOTS]
select * from teams where id = 31;
select * from crm_configurations where id = 18;
select * from users where team_id = 31; # 257
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 31;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 31
and sa.provider = 'close';
select * from contacts where crm_configuration_id = 18;
# [PASSWORD_DOTS] NEPTUNE [PASSWORD_DOTS]
select * from teams;
select * from users where id IN (1030, 1035, 1052);
select * from crm_configurations;
select * from users where team_id = 65; # 257
select * from team_settings where team_id = 65; # 257
select * from invitations where team_id = 65; # 257
select * from users where email = '[EMAIL]'; # 257
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 65;
select * from crm_configurations where id = 53;
select * from accounts where crm_configuration_id = 53 order by id desc;
select * from leads where crm_configuration_id = 53 order by id desc;
select * from contacts where crm_configuration_id = 53 order by id desc;
select * from opportunities where crm_configuration_id = 53 order by id desc;
select * from crm_profiles where crm_configuration_id = 53 order by id desc;
select * from crm_fields where crm_configuration_id = 53 order by id desc;
select * from crm_field_values where crm_field_id = 3341 order by id desc;
select * from crm_layouts where crm_configuration_id = 53 order by id desc;
select * from stages where crm_configuration_id = 53 order by id desc;
select * from crm_profiles where crm_configuration_id = 13;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 65
and sa.provider = 'integration-app';
select * from contacts where crm_configuration_id = 13;
select * from social_accounts where sociable_id = 283;
SELECT * FROM opportunities WHERE crm_provider_id = '006O400000E9bzeIAB';
select * from activity_providers where team_id = 65;
SELECT * FROM activities WHERE crm_configuration_id IN (51, 52, 53);
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 65
;
# [PASSWORD_DOTS] STAGING [PASSWORD_DOTS]
SELECT * FROM teams;
SELECT * FROM teams WHERE id = 88;
SELECT * FROM teams WHERE id = 89;
select * from team_settings where team_id = 89;
SELECT * FROM users WHERE team_id = 89;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 89;
select * from users;
SELECT * FROM social_accounts WHERE sociable_id = 1761;
SELECT * FROM crm_configurations WHERE id = 70;
select * from accounts where crm_configuration_id = 70 order by id desc;
select * from leads where crm_configuration_id = 70 order by id desc;
select * from contacts where crm_configuration_id = 70 order by id desc;
select * from opportunities where crm_configuration_id = 70 order by id desc;
select * from crm_profiles where crm_configuration_id = 70 order by id desc;
select * from crm_fields where crm_configuration_id = 70 order by id desc;
select * from crm_field_values where crm_field_id = 3536 order by id desc;
select * from crm_layouts where crm_configuration_id = 70 order by id desc;
select * from stages where crm_configuration_id = 70 order by id desc;
select * from business_processes where crm_configuration_id = 70 order by id desc;
select * from business_process_stages where business_process_id = 34;
select * from contacts where id = 10468;
select * from crm_layouts where crm_configuration_id = 70;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 388;
SELECT * FROM crm_fields WHERE id IN (3533,3534,3535);
select * from activities where crm_configuration_id = 70
and (account_id IS NOT NULL or lead_id IS NOT NULL or contact_id IS NOT NULL or opportunity_id IS NOT NULL) order by id desc;
SELECT * FROM activities WHERE uuid_to_bin('2e10b60f-8a61-41c5-a3d4-28835353dc65') = uuid;
SELECT * FROM activities where crm_configuration_id = 69 ;
SELECT * FROM users WHERE email LIKE '%[EMAIL]%';
SELECT * FROM activities WHERE uuid_to_bin('5a150c93-40fc-42ec-b3bd-c1d328e09f6e') = uuid;
SELECT * FROM opportunities WHERE id = 385;
select * from participants p
join activities a on p.activity_id = a.id
where a.crm_configuration_id = 70
and (p.lead_id IS NOT NULL or p.contact_id IS NOT NULL);
SELECT * FROM participants WHERE id = 1013638;
select * from teams where id = 90;
select * from users where team_id = 90;
select * from social_accounts where social_accounts.sociable_id IN (1960,1760);
SELECT * FROM crm_profiles WHERE crm_configuration_id = 71;
select * from invitations where team_id = 90;
select * from crm_configurations where id = 71;
select * from accounts where crm_configuration_id = 71 order by id desc;
select * from leads where crm_configuration_id = 71 order by id desc;
select * from contacts where crm_configuration_id = 71 order by id desc;
select * from opportunities where crm_configuration_id = 71 order by id desc;
select * from crm_profiles where crm_configuration_id = 71 order by id desc;
select * from crm_fields where crm_configuration_id = 71 order by id desc;
select * from crm_field_values where crm_field_id = 3341 order by id desc;
select * from crm_layouts where crm_configuration_id = 71 order by id desc;
select * from stages where crm_configuration_id = 71 order by id desc;
select * from users order by secondary_email desc;
select u.id, u.email, u.status, sa.id, sa.provider_user_id from social_accounts sa
join users u on sa.sociable_id = u.id
where sa.provider = 'google' and u.email LIKE 'aneliya%';
select * from failed_jobs order by id desc;
select * from users where email = '[EMAIL]' or secondary_email = '[EMAIL]';
select * from teams;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 39;
SELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type = 'task';
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce';
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('c38b3895-fd0f-4b1f-9fb2-c170dba137c6') = uuid;
SELECT * FROM crm_configurations WHERE id = 70;
select * from teams where id = 1;
select * from groups where team_id = 1;
select * from users where team_id = 1;
select o.id, o.name,o.close_date, u.id, u.name, u.group_id, r.id, r.display_name, g.name, g.scope from opportunities o
join users u on o.user_id = u.id
join groups g on u.group_id = g.id
join role_user ru on u.id = ru.user_id
join roles r on ru.role_id = r.id
where o.crm_configuration_id = 39 and close_date > '2024-01-01 00:00:00';
select * from role_user where user_id = 143;
select * from roles;
select * from role_user;
select * from groups where id = 9;
select * from scope_groups where group_id = 9;
# [PASSWORD_DOTS]
select * from teams where id = 36;
select * from crm_configurations;
SELECT * FROM social_accounts WHERE sociable_id = 121;
https://crmsandbox.zoho.com/crm/jiminnyw4/tab/Leads/4776201000005049105
https://crmsandbox.zoho.com/crm/
https://crm.zoho.com/crm/org3469620/tab/Leads/230045000229559080
https://crm.zoho.com/crm/
org3469620
SELECT * FROM activities WHERE uuid_to_bin('03382d20-c8bc-48e7-a3d4-90b52fa5ceab') = uuid;
select * from users where email LIKE "%mobile_automation_%";
select * from social_accounts where sociable_id IN (2228);
select * from crm_profiles where user_id IN (2222,2223,2226,2227);
select * from teams order by id desc;
SELECT * FROM users WHERE id = 2229;
SELECT * FROM crm_profiles WHERE user_id = 2229;
select * from opportunities where crm_configuration_id = 88;
select * from crm_fields where crm_configuration_id = 88;
select * from crm_profiles where crm_configuration_id = 88;
SELECT * FROM teams WHERE id = 1;
SELECT * FROM users WHERE id = 143;
SELECT * FROM users WHERE uuid_to_bin('fde193d3-06a2-4e1a-8895-62b94039215d') = uuid;
SELECT * FROM teams WHERE uuid_to_bin('73385071-a756-42ae-9c73-8b53f2309467') = uuid;
https://app.staging.jiminny.com/ondemand?
min_duration=1
&
only_recorded=1
&
user_id%5B%5D=641f1acb-16b8-42d1-8726-df52979dad0e
&
sequence_number=2
select * from users where team_id = 1 and email like '%stoyan%'
select * from coaching_feedbacks;
select * from teams;
SELECT * FROM users WHERE team_id = 36;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 19
and sa.provider = 'pipedrive';
select * from users where id = 143;
SELECT * FROM users WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
SELECT * FROM teams WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
SELECT * FROM activity_shares WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
select * from users where team_id = 2;
select * from activities where crm_configuration_id = 39
and activities.scheduled_start_time BETWEEN '2025-04-09 00:00:00' AND '2025-04-09 23:59:59'
AND user_id = 143
order by id desc;
# [PASSWORD_DOTS]
select * from teams where id = 142; # 2312, 126
select * from team_settings;
select * from users where team_id = 142; # 21642
SELECT * FROM social_accounts WHERE sociable_id = 21642;
SELECT * FROM crm_profiles cp join users u ON u.id = cp.user_id WHERE team_id = 142;
select * from crm_profiles where id IN (93);
select * from invitations;
select * from team_features where team_id = 1;
SELECT * FROM crm_configurations WHERE id = 126;
select * from accounts where crm_configuration_id = 126 order by id desc;
select * from leads where crm_configuration_id = 126 order by id desc;
select * from contacts where crm_configuration_id = 126 order by id desc;
select * from opportunities where crm_configuration_id = 126 order by id desc;
select * from crm_profiles where crm_configuration_id = 126 order by id desc;
select * from crm_fields where crm_configuration_id = 126 # 11060
# and type IN ('picklist', 'status')
# and object_type = 'task'
order by id desc;
# 5731,5732,5733
select DISTINCT crm_field_id from crm_field_values where crm_field_id IN (11151,12239,12215,12185,12175,12165,12144,12137,12127,12109,12107,12105,12103,12092,12037,12005,12003,11987,11969,11958,11951,11942,11931,11924,11921,11917,11915,11901,11893,11883,11872,11870,11868,11866,11839,11833,11821,11793,11780,11777,11769,11757,11737,11735,11656,11645,11638,11629,11618,11611,11602,11591,11584,11581,11558,11544,11543,11534,11532,11529,11527,11503,11497,11493,11488,11470,11468,11457,11455,11397,11387,11372,11363,11348,11323,11318,11309,11301,11300,11292,11290,11286,11284,11256,11252,11242,11237,11233,11219,11176,11160) order by id desc;
select * from crm_layouts where crm_configuration_id = 126 order by id desc;
SELECT * FROM crm_layout_entities WHERE crm_layout_id in (300,299,298);
select * from stages where crm_configuration_id = 126 order by id desc;
select * from business_processes where crm_configuration_id = 126 order by id desc;
select * from business_process_stages where business_process_id IN (76,75,74,73);
select * from playbooks where team_id = 142;
select * from playbook_layouts where playbook_id IN (108);
SELECT * FROM playbook_categories WHERE playbook_id IN (108);
select * from teams where id = 130;
SELECT * FROM social_accounts WHERE sociable_id = 2291;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 2
and sa.provider = 'hubspot';
SELECT * FROM activities
WHERE crm_configuration_id = 110;
select * from teams;
select * from crm_configurations;
SELECT * FROM activities WHERE id = 628773;
SELECT * FROM crm_profiles WHERE user_id = 1460;
SELECT * FROM social_accounts WHERE sociable_id = 2291;
select * from teams;
select ru.*, pr.*, p.* from users u join role_user ru on ru.user_id = u.id
join permission_role pr on pr.role_id = ru.role_id
join permissions p on p.id = pr.permission_id
where team_id = 495 and p.name IN ('dial');
select * from teams where id = 145;
select * from crm_configurations where id = 129;
select * from social_accounts where sociable_id = 2317;
SELECT * FROM activities WHERE uuid_to_bin('8dbab184-a333-4268-ad57-fb41f8d53a9a') = uuid;
select * from teams where id = 1;
SELECT * FROM crm_layouts WHERE crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 280;
SELECT * FROM crm_layout_entities WHERE id = 5507;
SELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type IN ('event');
select * from teams;
select * from activities where crm_configuration_id = 14;
SELECT * FROM social_accounts where provider = 'copper';
select * from activities where id = 628467;
select * from participants where activity_id = 628467;
SELECT * FROM contacts WHERE id = 3969;
SELECT * FROM accounts WHERE id = 177;
SELECT * FROM activities WHERE uuid_to_bin('4eb54c77-cfa3-2bd4-84a7-9ed46a21c988') = uuid;
# [PASSWORD_DOTS] BH
select * from teams where id = 36;
SELECT * FROM crm_configurations WHERE id = 21;
select * from activities where crm_configuration_id = 21 and id = 607901;
select * from activities where crm_configuration_id = 21;
select * roles;
select * from permissions;
select * from permission_role where permission_id = 226;
select * from migrations order by id desc;
# mercury
# neptune
# earth
select * from teams;
select * from teams where id = 19;
select * from teams where id = 27;
select * from users where team_id = 27;
SELECT * FROM crm_configurations WHERE id = 42;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 19
and sa.provider = 'pipedrive';
select * from activities where id = 631461;
SELECT * FROM crm_field_values WHERE crm_field_id = 180;
select * from teams where id = 2;
SELECT * FROM social_accounts WHERE sociable_id = 89;
SELECT * FROM activities WHERE uuid_to_bin('ba0c029a-bc14-4e17-8603-64174acebcbb') = uuid; # 634273
select * from activity_summary_logs where activity_id = 634273;
select * from sidekick_settings where team_id = 2;
select * from teams; # 2, 2
SELECT * FROM crm_configurations WHERE team_id = 2; # 2
select * from team_features where team_id = 2;
select * from features;
SELECT * FROM opportunities WHERE crm_configuration_id = 2 and crm_provider_id = '51317301383';
SELECT * FROM opportunities WHERE crm_configuration_id = 2 order by id desc;
select * from automated_reports order by id desc;
select * from automated_report_results order by id desc;
select * from users where team_id = 1 and id IN (7160, 3248);
select * from migrations order by id desc;
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 = 1052 and sa.provider = 'hubspot';
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 = 565;
select * from playbooks where team_id = 1;
select * from playbooks where id = 175;
select * from playbook_categories where playbook_id = 175;
select * from users where team_id = 1052;
select * from users where id = 7160;
select * from crm_profiles where user_id = 7160;
select * from features;
select
*
# id, uuid, type, provider, playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id, stage_id,
# crm_configuration_id, crm_provider_id, transcription_id, status
from activities where crm_configuration_id = 1 and type = 'conference'
# and crm_provider_id IS NOT NULL
and provider != 'uploader' and actual_start_time IS NOT NULL
ORDER by id desc;
select * from activities where id = 54747783; # 00UO400000pCzojMAC
select p.id, p.activity_type, pc.id, pc.name
FROM playbooks p
join playbook_categories pc on p.id = pc.playbook_id
where p.team_id = 1 and p.activity_type = 'event';
SELECT * FROM crm_fields WHERE crm_configuration_id = 1 and object_type = 'event';
SELECT * FROM crm_field_values WHERE crm_field_id = 4;
select * from crm_layouts cl join playbook_layouts pl on cl.id = pl.layout_id
where crm_configuration_id = 1 and pl.playbook_id = 175;
select * from teams;
SELECT r.* FROM automated_reports r
join teams t on r.team_id = t.id
WHERE r.frequency = 'daily'
and r.status = 1
AND t.status = 'active'
AND (r.expires_at >= now() OR r.expires_at IS NULL);
select * from automated_report_results where report_id IN (18, 33);
select * from users where team_id = 1 and id = 1047;
SELECT * FROM social_accounts WHERE sociable_id = 1047;
select * from activity_searches where id = 10932;
select * from activity_search_filters where activity_search_id = 10932;
select * from automated_reports order by id desc;
select * from automated_report_results order by id desc;
select * from automated_reports where id IN (55);
select * from automated_report_results where id IN (81);
select * from users where id IN (10633, 13987, 11985);
select * from users where group_id IN (3710);
SELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;
SELECT * FROM automated_report_results WHERE uuid_to_bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;
select * from teams;
select * from accounts where team_id = 1;
select * from automated_report_results where media_type = 'pdf' and status = 2;
SELECT * FROM automated_report_results WHERE uuid_to_bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid;
select * from teams where id = 1029;
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 = 1029 and sa.provider = 'pipedrive';
[
{
"user_id": "23460 (owner)",
"email": "[EMAIL]",
"id": 69,
"sociable_id": 23460,
"provider_user_id": "19555731",
"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,
"refresh_token_expires": null,
"provider": "pipedrive",
"state": "connected",
"auth_scope": "base,deals:full,activities:full,contacts:full,search:read",
"retry_after": null,
"created_at": "2025-04-16 08:23:28",
"updated_at": "2026-05-18 07:13:18",
"provider_user_token_encrypted": "eyJpdiI6Ik9oYzBwcTVteWN4ajBRaDdMb0FjWGc9PSIsInZhbHVlIjoiQUNMbjU5UHR2Q1RnbWRXMEU1TUx6UVpRU3gzdVc5WktmTE4rVlhXa3lRaGhyUUlZMVZRWEJuR0JaWWhZZXNPRlBuanhuYU5MVHZ5TG9NTVVjNjJSUUpZZ2VhbGYxbHg0UzJEdTVmQjNFZnJRZkMwYjd0N2RMZ05GRS9IR3c2K0NoVjBjYTA5UG12SkxHeDlDMGVNN3ptUWUzblFiTngyYzR1eUpHSEYrdEwvZm0yZklGYjBSNEtTR2ZGazhLM1hqT3lVbjFobDNPZ0d3anFlcjhKcXpERlZGOVN1YmFyNDIvM1BFRDFMYnp4WEI4TGVLM2xYcy9CL0RDOWlQNHI3N0NwWnJPMWRtZllmM2ZKeE9TV2NBeDZxL2M1YnlSVzd3ZW96T3F1QmtBYXBHYkUraGcvdCtRajlYZXBjVVBSdFlMUjVPVDVJbDdyenVoWjMrbVJvU3ZZR1dQZ3pqQ3F3aDF2U2xPZWZIN3BCWVFLNXpxQUtDb2pIK0xHc1E3SklSM3Q0VkNSbm9oK2pFK3hLaW54T1dWbEVneUp0RGhhdVBuOFI4MXROc3dZWnFnTUpiaDVMMnZ4QmlRM3k4QWFlMVFWUFYvdGhJQzZBYnhBQmhWa2ZKN1ZhSnhpaExxbmlTemgzUWw3aXJtWjlSMlhmd0lWMDNDN1N3My9Ua0hCL2xqY3RkVFhMSjFJMDRjOE5DWlgrZ3FMVXN6RWlwUE5GWERZdG1xVjVxOFlLRGs2VVJKS3FLeWRxQjYxdDh4Z2JJNXhlWEZ3dkQ4SGtybDNUcndzblFHeVJNRkYraFh2UDFIUTdMQ1BZa3dEU1dBbzk5K0dyT2RNVFBZZUJpRytSck5pYlI1YUZyMmhUNEZCdWxHYmJLREtzbUpjVkhvV0RoejJpbm1SWHlNaXE5M0RhcS94UW9EdFoweWF3bVFVY0dTZWFPSXBmOCtDYndia215cmtyZU1oT0Exam1CV2tPblNhYjY4clVEeUs3anVHUmNHeS9YLzRha1VhbGl3N3lwaDlzZnRhQUZta2s4eFllNHgzRklSRmNyazJ4dlBDMnByNCtBRjNaVjJCTT0iLCJtYWMiOiJkYTQxZDY1OTY2ZTljMTgyZWRhNGEzMGZjZDc2MjBjN2NlNzU2YTViNGQxNWE1NTI2ZmI1MWQyYjQ2ODYxZmEwIiwidGFnIjoiIn0=",
"provider_refresh_token_encrypted": "eyJpdiI6Imt2bGxlSmxUK05GMjF0dEtPaTMrUlE9PSIsInZhbHVlIjoiUXZHTElZRXkreHFxUU02SnZ4eVBacG9WWTRlVkd0USszV3JyVFlpU2ZaY25GSWo2WFcrRzNlbFRlUXRQczNwSXRCcEdvZEpveG9jMzBDSTgwdnZLQnc9PSIsIm1hYyI6ImQxYWI0NzU5Nzg5MDI4YWVhZmQ4Mjg1YzhkZDQzMjRkYWYwYTdhZTY5MDMxMjc0OWNiYjY0Nzc3NDQ0MTEyY2EiLCJ0YWciOiIifQ==",
"encryption_key": "0x01020300786192D9D96DD60D3D1EBC9DFAEE5F0C45EE80165CF3F3D2B3B627026AA7CFC7CA0128DD463535D32EE491ADBADF8B07596B0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040C7FB1319048ECB2EA3F23B995020110802B52D22F5EAD341AB238FBBCB6093156E443876A664BA5555D722565C2B2D04422C868CD7350555E3CC74221",
"sociable_type": "user",
"owner_id": 23460
},
{
"user_id": "23463",
"email": "[EMAIL]",
"id": 72,
"sociable_id": 23463,
"provider_user_id": "23270841",
"provider_user_token": "v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:txqCuWLeVhgwiaFqXIvQWWrtrnFIy_4lT3VCr-sRB4g6_2lK8KcQ_6ka_qFmZhr-IeIAKmAImx6H1iIKx4Ab7XZ5MnKIh03GKbHjI0n0rGT9UYkeH21jKOxJvKaSX_TyLbxFPR6irPQyvqcpBClXI52gVJH01KzZy_dMTHFXhhDLOIhEpSrQXHG7Qo8q7OuBeSPZrU1ALi9kmAm4GTpzGTbzfl-hUt9IAfPunJOCyv3mf2Tl-MT8EyQgOFPrsP3yz9UlSyVhb40zO_bCnUrqNxjwgm_E6vgpVrwULTQbHe-43Dq-TRetjceUzT88GBgVJ0UdxXP5BRBVXcL5ir8-9ZTMaNU",
"provider_refresh_token": "5034113:[TELEGRAM_TOKEN]78ad1",
"expires": 1753837219,
"refresh_token_expires": null,
"provider": "pipedrive",
"state": "full-refresh",
"auth_scope": "base,deals:full,activities:full,contacts:full,search:read",
"retry_after": null,
"created_at": "2025-04-16 10:41:12",
"updated_at": "2025-07-30 01:00:17",
"provider_user_token_encrypted": "eyJpdiI6InVEVEl2SzIxMjd1bkNDWG9lY3YvQ0E9PSIsInZhbHVlIjoiRlJLbDZ3ZHo2dHMxUWQwdGU2YUZjV3lPWHlxQTJ0eWh4S0RTMjlSaThVcktoaWhXcTd2UXl4Mjg4bW5UUnZCZEQ5NXpuQTVKOURiMDNIa3l3K0lSWCt5azRBOEdHbitWQXhxeEpMVUZ1dnF2NVl1TTZLelZOaGNvRlBLeGpIWlpoRGloUEprd2xoNUFPcTlLcUd3WVlUU2svR1NOeXBYQ2NnMWhnK1V2aytOeVVMNzJGdVZXMU1JS3BSaGNCcmxkVjEwQ01mQXNBdWNhS1lMZWZobnZwcHBkN1R4bUVDRUNYdnNtSVJkdG5MdkN3djJBT0hMRDl1MHFGbnl4WU13ejBkUWsrdUljWkZhcTJlN0JDSGdTVzlPY0FGMUJlZi9WRGpkMUk5R20wblYwSk9VR2FuaHpLTzJNeitMbnF1V1NEMUUxRmYzaDRGZDMyaXd3Z0FjQno4SzVoYjUyTmV3UXNpRlF4TGZKNVl3dUFqdGhKVWJjRVlUUXRGalBpaXJvSGJmbS8rd25aQ2Zvc05saHRDRjlHV1VEUFFiRU5xbWRVNkxFSXV0RUZyaUlYNWMwMmhnZ0Y1VUQ4eEFkY2QyWXpnR0NidkVJSWdjVGljUjA3NDdpZW9WUHhtSlpGSGdNU2hRUTA5ZW03RGpiRFdrdytkOHJXSUxlazZNaG9iaUg2NFZYdEc3YklMeFZvblBzWmVRSDcvN2M4WUNtL3h4S2IrUW00cXhialBia3BJcW5XallBNlV5WWdhcE1ZVFBBM3RSSUVBamYvOGZEQWM5a2FJMGwyWkRSU3dlTEtPemZlQ3RXRGNDcEdYRHdMNTlTQVg2SUdUN0hVaXdZT1dUOUlrVzkrZHFBemhwWXg1cm4rSy9UOHUzcnNSM2dISlhBRTEyVUNyTkZYaFJYUlN1a2RKVHhhM2dHckR3a1JGaVZ2Wk9BVnhTclVpSEhwWTVpQTlJbXVkOUxSTGpRbDk0a1VtbE9QMVAvN3VlVEhJUHd2elowd0laNVIzZ3M3N0ZOK0NDakIwQ2FicGxoMDBhTXI0VUppUmFOZHdlWUdGV21NNFQ4RU1nY0dnWT0iLCJtYWMiOiI0ZTU4ZmJkNTdkYmY0NGE4NTJjZjlhNDExNzE2YjhlOWM2NTA5OGY2MDA4OTcyZDVlOTljY2JjZDhmMjBhMDUyIiwidGFnIjoiIn0=",
"provider_refresh_token_encrypted": "eyJpdiI6IkJGMkdRVHRKM2VTcitKNGcvQWJtUGc9PSIsInZhbHVlIjoicmFyRkxPZ1Rybm1ORXlEVjJ2TXFGTzJtM3hWaFhnUVVHN2ZlR1lRM0I5d3ozbnZTcU5EdzJqRkI2elhyNWhlenRTUXV3bjk0N1JXeklDMVAyUzBKcHc9PSIsIm1hYyI6ImJhODVjMGQyZDE3Y2ExNjc2OWVjYWJiNmFjYWVkODIyMTMyNWVhYTExMTgwYTEyMTU0MzUzZGE1YjQ5YzQ5ZjEiLCJ0YWciOiIifQ==",
"encryption_key": "0x01020300788C37CDF66ABE9301A68D5D4866AC0C197E04EEE4D904F20A59991322EBAE252301BEF4B24FF01359E934E5654617E4EEAC0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040CEB00EF45BDEA999A5558889E020110802B925F372F7BEFAF0B45E48686113D1DA430ECFCC07B1F61BA6828CC44235278EDB05C486E8068D0BE737D91",
"sociable_type": "user",
"owner_id": 23460
}
]
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":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>114 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"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":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Component\\SCIM;\n\nuse Jiminny\\Component\\SCIM\\Builders\\Filters;\n\nclass Constants\n{\n /**\n * HTTP codes\n */\n public const HTTP_OK = 200;\n public const HTTP_CREATED = 201;\n public const HTTP_NO_CONTENT = 204;\n\n public const HTTP_NOT_FOUND = 404;\n public const HTTP_BAD_REQUEST = 400;\n public const HTTP_ACCESS_DENIED = 403;\n\n public const HTTP_ERROR = 501;\n\n /**\n * Users resource constants\n */\n public const USER_FIRST_NAME = 'givenName';\n public const USER_FAMILY_NAME = 'familyName';\n public const USER_STATUS = 'Active';\n public const USER_USERNAME = 'UserName';\n public const USER_EXTERNAL_ID = 'externalId';\n\n public const USER_FIELDS = [\n self::USER_FIRST_NAME,\n self::USER_FAMILY_NAME,\n self::USER_STATUS,\n self::USER_USERNAME,\n ];\n\n public const META_OPERATIONS_REPLACE = 'replace';\n public const META_OPERATIONS_REPLACE_UPPER = 'Replace';\n public const META_OPERATIONS_ADD = 'add';\n public const META_OPERATIONS_ADD_UPPER = 'Add';\n public const META_OPERATIONS_REMOVE_UPPER = 'Remove';\n public const META_OPERATIONS_REMOVE = 'remove';\n\n public const META_ID = 'id';\n public const META_PHONE_NUMBERS = 'phoneNumbers';\n public const META_TITLE = 'title';\n public const META_ROLES = 'roles';\n public const META_PATH = 'path';\n public const META_ENTERPRISE_SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';\n public const META_DEPARTMENT = 'department';\n public const META_META = 'meta';\n public const META_TYPE = 'type';\n public const META_VALUE = 'value';\n public const META_OPERATIONS = 'Operations';\n public const META_OP = 'op';\n public const META_RESOURCE_TYPE = 'resourceType';\n public const META_CREATED = 'created';\n public const META_LAST_MODIFIED = 'lastModified';\n public const META_FORMATTED = 'formatted';\n public const META_EMAILS = 'emails';\n public const META_USERNAME = 'userName';\n public const META_NAME = 'name';\n public const META_STATUS = 'active';\n public const META_PRIMARY = 'primary';\n public const META_ERROR_STATUS = 'status';\n public const META_ERROR_DETAIL = 'detail';\n public const META_LIST_TOTAL_RESULTS = 'totalResults';\n public const META_LIST_RESOURCES = 'Resources';\n public const META_LIST_START_INDEX = 'startIndex';\n public const META_LIST_COUNT = 'count';\n public const META_LIST_ITEMS_PER_PAGE = 'itemsPerPage';\n public const META_SCHEMAS = 'schemas';\n public const META_FILTER = 'filter';\n public const META_TYPE_WORK = 'work';\n public const META_PHONE_NUMBER_TYPE_MOBILE = 'mobile';\n public const META_EMAIL_TYPE_HOME = 'home';\n public const META_CONTAINER_NAME = 'name';\n public const META_CONTAINER_EMAILS = 'emails';\n\n public const RESOURCE_TYPE_USER = 'User';\n\n public const USER_PATCH_ATTR_TITLE = 'title';\n public const USER_PATCH_ATTR_ACTIVE = 'active';\n public const USER_PATCH_ATTR_USERNAME = 'userName';\n public const USER_PATCH_ATTR_FIRST_NAME = 'name.givenName';\n public const USER_PATCH_ATTR_LAST_NAME = 'name.familyName';\n public const USER_PATCH_ATTR_PRIMARY_EMAIL = 'emails[type eq \"work\"].value';\n public const USER_PATCH_ATTR_SECONDARY_EMAIL = 'emails[type eq \"home\"].value';\n public const USER_PATCH_ATTR_PHONE_NUMBER = 'phoneNumbers[type eq \"work\"].value';\n public const USER_PATCH_ATTR_PHONE_NUMBER_MOBILE = 'phoneNumbers[type eq \"mobile\"].value';\n public const USER_PATCH_ATTR_ROLES = 'roles';\n\n public const USER_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [\n self::USER_PATCH_ATTR_TITLE => Mutators\\Attributes\\User\\TitleAttr::class,\n self::USER_PATCH_ATTR_ACTIVE => Mutators\\Attributes\\User\\ActiveAttr::class,\n self::USER_PATCH_ATTR_USERNAME => Mutators\\Attributes\\User\\UsernameAttr::class,\n self::USER_PATCH_ATTR_FIRST_NAME => Mutators\\Attributes\\User\\FirstNameAttr::class,\n self::USER_PATCH_ATTR_LAST_NAME => Mutators\\Attributes\\User\\LastNameAttr::class,\n self::USER_PATCH_ATTR_PRIMARY_EMAIL => Mutators\\Attributes\\User\\PrimaryEmailAttr::class,\n self::USER_PATCH_ATTR_SECONDARY_EMAIL => Mutators\\Attributes\\User\\SecondaryEmailAttr::class,\n self::USER_PATCH_ATTR_PHONE_NUMBER => Mutators\\Attributes\\User\\PhoneNumberPrimaryAttr::class,\n self::USER_PATCH_ATTR_PHONE_NUMBER_MOBILE => Mutators\\Attributes\\User\\PhoneNumberSecondaryAttr::class,\n self::USER_PATCH_ATTR_ROLES => Mutators\\Attributes\\User\\RoleAttr::class,\n ];\n\n public const FILTER_OPERATOR_EQ = 'eq';\n\n public const SUPPORTED_FILTERS_OPERATORS = [\n self::FILTER_OPERATOR_EQ,\n ];\n\n public const USER_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [\n self::USER_FILTER_LOCAL_ID => Filters\\User\\LocalIdFilter::class,\n self::USER_FILTER_USERNAME => Filters\\User\\UserNameFilter::class,\n self::USER_FILTER_FIRST_NAME => Filters\\User\\FirstNameFilter::class,\n self::USER_FILTER_LAST_NAME => Filters\\User\\LastNameFilter::class,\n self::USER_FILTER_EXTERNAL_ID => Filters\\User\\ExternalIdFilter::class,\n self::USER_FILTER_DISPLAY_NAME => Filters\\User\\DisplayNameFilter::class,\n ];\n\n public const USER_FILTER_LOCAL_ID = 'id';\n public const USER_FILTER_USERNAME = 'userName';\n public const USER_FILTER_FIRST_NAME = 'givenName';\n public const USER_FILTER_LAST_NAME = 'familyName';\n public const USER_FILTER_EXTERNAL_ID = 'externalId';\n public const USER_FILTER_DISPLAY_NAME = 'DisplayName';\n\n public const SCIM_SUPPORTED_RESOURCES = [\n self::USER_RESOURCE_PREFIX,\n self::GROUP_RESOURCE_PREFIX,\n ];\n\n public const USER_RESOURCE_PREFIX = 'Users';\n public const GROUP_RESOURCE_PREFIX = 'Groups';\n\n public const OUTGOING_SCHEMAS_SUPPORTED = [\n self::OUTGOING_CORE_USER,\n\n ];\n\n /**\n * Outgoing supported schemas\n */\n public const OUTGOING_CORE_USER = 'urn:ietf:params:scim:schemas:core:2.0:User';\n public const OUTGOING_ERROR = 'urn:ietf:params:scim:api:messages:2.0:Error';\n public const OUTGOING_LIST_RESPONSE = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';\n\n public const OUTGOING_CORE_GROUP = 'urn:ietf:params:scim:schemas:core:2.0:Group';\n\n /**\n * Groups resource constants\n */\n public const GROUP_ATTRIBUTE_DISPLAY_NAME = 'displayName';\n public const GROUP_ATTRIBUTE_EXTERNAL_ID = 'externalId';\n public const GROUP_ATTRIBUTE_ID = 'id';\n public const RESOURCE_TYPE_GROUP = 'Group';\n public const GROUP_FILTER_QUERY_NAME = 'filter';\n public const GROUP_EXCLUDED_ATTRIBUTES = 'excludedAttributes';\n\n public const GROUP_SUPPORTED_FILTER_ATTRIBUTES = [\n self::GROUP_ATTRIBUTE_DISPLAY_NAME,\n ];\n\n public const GROUP_MEMBERS = 'members';\n\n public const SUPPORTED_PATCH_OPERATIONS = [\n self::META_OPERATIONS_ADD,\n self::META_OPERATIONS_REPLACE,\n self::META_OPERATIONS_REMOVE,\n ];\n\n public const GROUP_PATCH_ATTRIBUTE_MEMBERS = 'members';\n public const GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME = 'displayName';\n\n public const GROUP_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [\n self::GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME => Mutators\\Attributes\\Group\\DisplayNameAttr::class,\n self::GROUP_PATCH_ATTRIBUTE_MEMBERS => Mutators\\Attributes\\Group\\MembersAttr::class,\n ];\n\n public const GROUP_FILTER_DISPLAY_NAME = 'displayname';\n\n public const GROUP_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [\n self::GROUP_FILTER_DISPLAY_NAME => Filters\\Group\\DisplayNameFilter::class,\n ];\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Component\\SCIM;\n\nuse Jiminny\\Component\\SCIM\\Builders\\Filters;\n\nclass Constants\n{\n /**\n * HTTP codes\n */\n public const HTTP_OK = 200;\n public const HTTP_CREATED = 201;\n public const HTTP_NO_CONTENT = 204;\n\n public const HTTP_NOT_FOUND = 404;\n public const HTTP_BAD_REQUEST = 400;\n public const HTTP_ACCESS_DENIED = 403;\n\n public const HTTP_ERROR = 501;\n\n /**\n * Users resource constants\n */\n public const USER_FIRST_NAME = 'givenName';\n public const USER_FAMILY_NAME = 'familyName';\n public const USER_STATUS = 'Active';\n public const USER_USERNAME = 'UserName';\n public const USER_EXTERNAL_ID = 'externalId';\n\n public const USER_FIELDS = [\n self::USER_FIRST_NAME,\n self::USER_FAMILY_NAME,\n self::USER_STATUS,\n self::USER_USERNAME,\n ];\n\n public const META_OPERATIONS_REPLACE = 'replace';\n public const META_OPERATIONS_REPLACE_UPPER = 'Replace';\n public const META_OPERATIONS_ADD = 'add';\n public const META_OPERATIONS_ADD_UPPER = 'Add';\n public const META_OPERATIONS_REMOVE_UPPER = 'Remove';\n public const META_OPERATIONS_REMOVE = 'remove';\n\n public const META_ID = 'id';\n public const META_PHONE_NUMBERS = 'phoneNumbers';\n public const META_TITLE = 'title';\n public const META_ROLES = 'roles';\n public const META_PATH = 'path';\n public const META_ENTERPRISE_SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';\n public const META_DEPARTMENT = 'department';\n public const META_META = 'meta';\n public const META_TYPE = 'type';\n public const META_VALUE = 'value';\n public const META_OPERATIONS = 'Operations';\n public const META_OP = 'op';\n public const META_RESOURCE_TYPE = 'resourceType';\n public const META_CREATED = 'created';\n public const META_LAST_MODIFIED = 'lastModified';\n public const META_FORMATTED = 'formatted';\n public const META_EMAILS = 'emails';\n public const META_USERNAME = 'userName';\n public const META_NAME = 'name';\n public const META_STATUS = 'active';\n public const META_PRIMARY = 'primary';\n public const META_ERROR_STATUS = 'status';\n public const META_ERROR_DETAIL = 'detail';\n public const META_LIST_TOTAL_RESULTS = 'totalResults';\n public const META_LIST_RESOURCES = 'Resources';\n public const META_LIST_START_INDEX = 'startIndex';\n public const META_LIST_COUNT = 'count';\n public const META_LIST_ITEMS_PER_PAGE = 'itemsPerPage';\n public const META_SCHEMAS = 'schemas';\n public const META_FILTER = 'filter';\n public const META_TYPE_WORK = 'work';\n public const META_PHONE_NUMBER_TYPE_MOBILE = 'mobile';\n public const META_EMAIL_TYPE_HOME = 'home';\n public const META_CONTAINER_NAME = 'name';\n public const META_CONTAINER_EMAILS = 'emails';\n\n public const RESOURCE_TYPE_USER = 'User';\n\n public const USER_PATCH_ATTR_TITLE = 'title';\n public const USER_PATCH_ATTR_ACTIVE = 'active';\n public const USER_PATCH_ATTR_USERNAME = 'userName';\n public const USER_PATCH_ATTR_FIRST_NAME = 'name.givenName';\n public const USER_PATCH_ATTR_LAST_NAME = 'name.familyName';\n public const USER_PATCH_ATTR_PRIMARY_EMAIL = 'emails[type eq \"work\"].value';\n public const USER_PATCH_ATTR_SECONDARY_EMAIL = 'emails[type eq \"home\"].value';\n public const USER_PATCH_ATTR_PHONE_NUMBER = 'phoneNumbers[type eq \"work\"].value';\n public const USER_PATCH_ATTR_PHONE_NUMBER_MOBILE = 'phoneNumbers[type eq \"mobile\"].value';\n public const USER_PATCH_ATTR_ROLES = 'roles';\n\n public const USER_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [\n self::USER_PATCH_ATTR_TITLE => Mutators\\Attributes\\User\\TitleAttr::class,\n self::USER_PATCH_ATTR_ACTIVE => Mutators\\Attributes\\User\\ActiveAttr::class,\n self::USER_PATCH_ATTR_USERNAME => Mutators\\Attributes\\User\\UsernameAttr::class,\n self::USER_PATCH_ATTR_FIRST_NAME => Mutators\\Attributes\\User\\FirstNameAttr::class,\n self::USER_PATCH_ATTR_LAST_NAME => Mutators\\Attributes\\User\\LastNameAttr::class,\n self::USER_PATCH_ATTR_PRIMARY_EMAIL => Mutators\\Attributes\\User\\PrimaryEmailAttr::class,\n self::USER_PATCH_ATTR_SECONDARY_EMAIL => Mutators\\Attributes\\User\\SecondaryEmailAttr::class,\n self::USER_PATCH_ATTR_PHONE_NUMBER => Mutators\\Attributes\\User\\PhoneNumberPrimaryAttr::class,\n self::USER_PATCH_ATTR_PHONE_NUMBER_MOBILE => Mutators\\Attributes\\User\\PhoneNumberSecondaryAttr::class,\n self::USER_PATCH_ATTR_ROLES => Mutators\\Attributes\\User\\RoleAttr::class,\n ];\n\n public const FILTER_OPERATOR_EQ = 'eq';\n\n public const SUPPORTED_FILTERS_OPERATORS = [\n self::FILTER_OPERATOR_EQ,\n ];\n\n public const USER_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [\n self::USER_FILTER_LOCAL_ID => Filters\\User\\LocalIdFilter::class,\n self::USER_FILTER_USERNAME => Filters\\User\\UserNameFilter::class,\n self::USER_FILTER_FIRST_NAME => Filters\\User\\FirstNameFilter::class,\n self::USER_FILTER_LAST_NAME => Filters\\User\\LastNameFilter::class,\n self::USER_FILTER_EXTERNAL_ID => Filters\\User\\ExternalIdFilter::class,\n self::USER_FILTER_DISPLAY_NAME => Filters\\User\\DisplayNameFilter::class,\n ];\n\n public const USER_FILTER_LOCAL_ID = 'id';\n public const USER_FILTER_USERNAME = 'userName';\n public const USER_FILTER_FIRST_NAME = 'givenName';\n public const USER_FILTER_LAST_NAME = 'familyName';\n public const USER_FILTER_EXTERNAL_ID = 'externalId';\n public const USER_FILTER_DISPLAY_NAME = 'DisplayName';\n\n public const SCIM_SUPPORTED_RESOURCES = [\n self::USER_RESOURCE_PREFIX,\n self::GROUP_RESOURCE_PREFIX,\n ];\n\n public const USER_RESOURCE_PREFIX = 'Users';\n public const GROUP_RESOURCE_PREFIX = 'Groups';\n\n public const OUTGOING_SCHEMAS_SUPPORTED = [\n self::OUTGOING_CORE_USER,\n\n ];\n\n /**\n * Outgoing supported schemas\n */\n public const OUTGOING_CORE_USER = 'urn:ietf:params:scim:schemas:core:2.0:User';\n public const OUTGOING_ERROR = 'urn:ietf:params:scim:api:messages:2.0:Error';\n public const OUTGOING_LIST_RESPONSE = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';\n\n public const OUTGOING_CORE_GROUP = 'urn:ietf:params:scim:schemas:core:2.0:Group';\n\n /**\n * Groups resource constants\n */\n public const GROUP_ATTRIBUTE_DISPLAY_NAME = 'displayName';\n public const GROUP_ATTRIBUTE_EXTERNAL_ID = 'externalId';\n public const GROUP_ATTRIBUTE_ID = 'id';\n public const RESOURCE_TYPE_GROUP = 'Group';\n public const GROUP_FILTER_QUERY_NAME = 'filter';\n public const GROUP_EXCLUDED_ATTRIBUTES = 'excludedAttributes';\n\n public const GROUP_SUPPORTED_FILTER_ATTRIBUTES = [\n self::GROUP_ATTRIBUTE_DISPLAY_NAME,\n ];\n\n public const GROUP_MEMBERS = 'members';\n\n public const SUPPORTED_PATCH_OPERATIONS = [\n self::META_OPERATIONS_ADD,\n self::META_OPERATIONS_REPLACE,\n self::META_OPERATIONS_REMOVE,\n ];\n\n public const GROUP_PATCH_ATTRIBUTE_MEMBERS = 'members';\n public const GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME = 'displayName';\n\n public const GROUP_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [\n self::GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME => Mutators\\Attributes\\Group\\DisplayNameAttr::class,\n self::GROUP_PATCH_ATTRIBUTE_MEMBERS => Mutators\\Attributes\\Group\\MembersAttr::class,\n ];\n\n public const GROUP_FILTER_DISPLAY_NAME = 'displayname';\n\n public const GROUP_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [\n self::GROUP_FILTER_DISPLAY_NAME => Filters\\Group\\DisplayNameFilter::class,\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_jupiter","depth":4,"bounds":{"left":0.69348407,"top":0.09896249,"width":0.04089096,"height":0.01915403},"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":"19","depth":4,"bounds":{"left":0.6871675,"top":0.123703115,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"19","depth":4,"bounds":{"left":0.6988032,"top":0.123703115,"width":0.009640957,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"17","depth":4,"bounds":{"left":0.71043885,"top":0.123703115,"width":0.00930851,"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 * FROM teams WHERE id = 1;\n\nselect * from crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 283;\nSELECT * FROM crm_fields WHERE id = 2234;\nSELECT * FROM crm_field_values WHERE crm_field_id = 2234;\n\nselect * from crm_profiles where user_id = 143;\n\nselect * from record_types where crm_configuration_id = 39; # 0121K000001MHElQAO,0121K000001MHEqQAO\nselect * from business_processes where crm_configuration_id = 39;\n# 01941000000H669AAC, 01941000000H66JAAS\n\nselect * from record_type_field_values\n where record_type_id IN (24);\n\nselect * from crm_field_values where id IN (2730);\n\nselect * from crm_configurations where id = 39;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce'; #1035\n\n\nselect * from users where team_id = 1; # 222 group 3\nSELECT * FROM activities WHERE user_id = 222 order by id desc;\nselect * from sidekick_settings where team_id = 1;\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\n\nselect * from activities where crm_configuration_id = 2\nand provider = 'ms-teams' and id = 608765;\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id = '59523413338';\n\nselect * from sidekick_settings where team_id = 2;\n\nSELECT * FROM activities WHERE id = 608660;\nselect * from activity_summary_logs where activity_id = 608660;\nselect * from ai_prompts where transcription_id = 11214;\n\n# ********************************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('ed78a437-2804-450e-ab2f-56ab1c641346') = uuid;\n# id: 608818, crm: 59628809737\nSELECT * FROM activities WHERE uuid_to_bin('36b06e55-afdd-4782-8dee-c624cd0af191') = uuid;\n# id: 608821, crm: 59632069252\nSELECT ce.start_time, ce.end_time, a.id, a.uuid, crm_provider_id, calendar_event_id, title,\nplaybook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id,\nscheduled_start_time, scheduled_end_time, actual_start_time, actual_end_time, a.created_at\nFROM activities a\njoin calendar_events ce on a.calendar_event_id = ce.id\nWHERE a.id IN (608818, 608821);\n\nselect * from users where team_id = 1;\nselect * from team_settings where team_id = 1;\nselect * from crm_profiles where crm_configuration_id = 39 order by user_id;\n\nselect * from team_features where team_id = 1;\n\nselect * from users where team_id = 2;\n\nSELECT * FROM activities WHERE uuid_to_bin('ec7647e9-5225-458b-b475-f31aa2769204') = uuid; # 612639\n# Preslava N. Ivanova, grou id 3\n\nSELECT * FROM opportunities WHERE uuid_to_bin('a2928fe5-aec5-46cb-85d9-7654c89e46a6') = uuid;\n\nselect * from activities where opportunity_id = 344 and actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00';\n\nselect\n a.id,\n a.type,\n a.scheduled_start_time,\n a.actual_start_time,\n a.created_at,\n a.opportunity_id,\n a.status\nFROM activities a\nWHERE opportunity_id = 344\nand status IN ('completed', 'received', 'delivered')\nand (\n (a.actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')\nOR (a.created_at between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')\nOR (a.scheduled_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00'))\n;\n\nSELECT * FROM users WHERE id = 222;\n\nSELECT * FROM crm_profiles WHERE user_id = 222;\nselect * from crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 281;\n\nselect * from group_deal_risk_types;\n\nselect * from opportunities where team_id = 1;\n\nSELECT * FROM opportunities WHERE id = 315;\nSELECT * FROM crm_field_data WHERE object_id = 315;\nselect * from crm_field_data where object_id = 260;\n\nselect * from generic_ai_prompts where subject_id = 315;\n\nselect * from teams; # 36, 21, 121, james.graham@bullhorn.jiminny.com\nSELECT * FROM social_accounts WHERE sociable_id = 121 and provider = 'bullhorn';\n\n# ************************************************************************************\nselect * from teams where id = 1;\nselect * from crm_configurations where id = 39;\nselect * from users where team_id = 1;\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 1;\n# 1 - 00541000004281rAAA\n# 204 - 0052g000003freeAAA\n# 429 - 0052g000003qGOiAAM\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce';\n\nselect * from activities where type = 'softphone'\nand created_at > '2024-12-11 15:24:36' order by id desc;\n\nselect * from activity_providers where team_id = 1;\nselect * from activity_provider_users where activity_provider_id = 328;\n\nselect * from opportunities where crm_configuration_id = 39\nAND account_id = 178 AND is_closed = false\norder by created_at DESC;\n\nselect * from contacts where id = 3952;\nselect * from accounts where id = 178;\n\n# ************************************************************************************\nselect * from teams where id = 36;\nselect * from crm_configurations where id = 21;\nselect * from users where team_id = 36;\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 36;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 36\nand sa.provider = 'bullhorn';\n\nselect * from social_accounts where id = 348;\nUPDATE social_accounts SET\nprovider_user_token = '21442_6802599_91:41179a58-21e7-4d7c-ad58-56bb666b2f65',\nprovider_refresh_token = '21442_6802599_91:01c6b335-3f2a-42e4-85ff-8a08fa65fceb',\nexpires = 1733998131,\nstate = 'connected'\nWHERE id = 348;\n\n# ************************************************************************************\nselect * from teams where id = 31;\nselect * from crm_configurations where id = 18;\n\nselect * from users where team_id = 31; # 257\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 31;\n\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 31\nand sa.provider = 'close';\n\nselect * from contacts where crm_configuration_id = 18;\n\n# ********************** NEPTUNE **************************************************************\nselect * from teams;\nselect * from users where id IN (1030, 1035, 1052);\nselect * from crm_configurations;\n\nselect * from users where team_id = 65; # 257\nselect * from team_settings where team_id = 65; # 257\nselect * from invitations where team_id = 65; # 257\nselect * from users where email = 'integration-account@jiminny.com'; # 257\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 65;\n\nselect * from crm_configurations where id = 53;\nselect * from accounts where crm_configuration_id = 53 order by id desc;\nselect * from leads where crm_configuration_id = 53 order by id desc;\nselect * from contacts where crm_configuration_id = 53 order by id desc;\nselect * from opportunities where crm_configuration_id = 53 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 53 order by id desc;\nselect * from crm_fields where crm_configuration_id = 53 order by id desc;\nselect * from crm_field_values where crm_field_id = 3341 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 53 order by id desc;\nselect * from stages where crm_configuration_id = 53 order by id desc;\n\n\nselect * from crm_profiles where crm_configuration_id = 13;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 65\nand sa.provider = 'integration-app';\n\nselect * from contacts where crm_configuration_id = 13;\n\nselect * from social_accounts where sociable_id = 283;\n\nSELECT * FROM opportunities WHERE crm_provider_id = '006O400000E9bzeIAB';\n\nselect * from activity_providers where team_id = 65;\nSELECT * FROM activities WHERE crm_configuration_id IN (51, 52, 53);\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 65\n;\n\n# ***************************** STAGING ********************************************\nSELECT * FROM teams;\nSELECT * FROM teams WHERE id = 88;\nSELECT * FROM teams WHERE id = 89;\nselect * from team_settings where team_id = 89;\nSELECT * FROM users WHERE team_id = 89;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 89;\n\nselect * from users;\nSELECT * FROM social_accounts WHERE sociable_id = 1761;\nSELECT * FROM crm_configurations WHERE id = 70;\nselect * from accounts where crm_configuration_id = 70 order by id desc;\nselect * from leads where crm_configuration_id = 70 order by id desc;\nselect * from contacts where crm_configuration_id = 70 order by id desc;\nselect * from opportunities where crm_configuration_id = 70 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 70 order by id desc;\nselect * from crm_fields where crm_configuration_id = 70 order by id desc;\nselect * from crm_field_values where crm_field_id = 3536 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 70 order by id desc;\nselect * from stages where crm_configuration_id = 70 order by id desc;\nselect * from business_processes where crm_configuration_id = 70 order by id desc;\nselect * from business_process_stages where business_process_id = 34;\n\nselect * from contacts where id = 10468;\n\nselect * from crm_layouts where crm_configuration_id = 70;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 388;\nSELECT * FROM crm_fields WHERE id IN (3533,3534,3535);\n\nselect * from activities where crm_configuration_id = 70\nand (account_id IS NOT NULL or lead_id IS NOT NULL or contact_id IS NOT NULL or opportunity_id IS NOT NULL) order by id desc;\n\nSELECT * FROM activities WHERE uuid_to_bin('2e10b60f-8a61-41c5-a3d4-28835353dc65') = uuid;\nSELECT * FROM activities where crm_configuration_id = 69 ;\n\nSELECT * FROM users WHERE email LIKE '%jiminny_web_sa2@jiminny.com%';\nSELECT * FROM activities WHERE uuid_to_bin('5a150c93-40fc-42ec-b3bd-c1d328e09f6e') = uuid;\nSELECT * FROM opportunities WHERE id = 385;\n\nselect * from participants p\njoin activities a on p.activity_id = a.id\nwhere a.crm_configuration_id = 70\nand (p.lead_id IS NOT NULL or p.contact_id IS NOT NULL);\nSELECT * FROM participants WHERE id = 1013638;\n\nselect * from teams where id = 90;\nselect * from users where team_id = 90;\nselect * from social_accounts where social_accounts.sociable_id IN (1960,1760);\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 71;\nselect * from invitations where team_id = 90;\n\nselect * from crm_configurations where id = 71;\nselect * from accounts where crm_configuration_id = 71 order by id desc;\nselect * from leads where crm_configuration_id = 71 order by id desc;\nselect * from contacts where crm_configuration_id = 71 order by id desc;\nselect * from opportunities where crm_configuration_id = 71 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 71 order by id desc;\nselect * from crm_fields where crm_configuration_id = 71 order by id desc;\nselect * from crm_field_values where crm_field_id = 3341 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 71 order by id desc;\nselect * from stages where crm_configuration_id = 71 order by id desc;\n\nselect * from users order by secondary_email desc;\nselect u.id, u.email, u.status, sa.id, sa.provider_user_id from social_accounts sa\n join users u on sa.sociable_id = u.id\nwhere sa.provider = 'google' and u.email LIKE 'aneliya%';\n\nselect * from failed_jobs order by id desc;\n\nselect * from users where email = 'ben.allwright@learningpeople.co.uk' or secondary_email = 'ben.allwright@learningpeople.co.uk';\n\nselect * from teams;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 39;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type = 'task';\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce';\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('c38b3895-fd0f-4b1f-9fb2-c170dba137c6') = uuid;\nSELECT * FROM crm_configurations WHERE id = 70;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1;\nselect * from users where team_id = 1;\n\nselect o.id, o.name,o.close_date, u.id, u.name, u.group_id, r.id, r.display_name, g.name, g.scope from opportunities o\njoin users u on o.user_id = u.id\njoin groups g on u.group_id = g.id\njoin role_user ru on u.id = ru.user_id\njoin roles r on ru.role_id = r.id\nwhere o.crm_configuration_id = 39 and close_date > '2024-01-01 00:00:00';\n\nselect * from role_user where user_id = 143;\nselect * from roles;\n\nselect * from role_user;\nselect * from groups where id = 9;\nselect * from scope_groups where group_id = 9;\n\n# ************************************************************************************\nselect * from teams where id = 36;\nselect * from crm_configurations;\nSELECT * FROM social_accounts WHERE sociable_id = 121;\n\nhttps://crmsandbox.zoho.com/crm/jiminnyw4/tab/Leads/4776201000005049105\nhttps://crmsandbox.zoho.com/crm/\n\nhttps://crm.zoho.com/crm/org3469620/tab/Leads/230045000229559080\n https://crm.zoho.com/crm/\n org3469620\n\nSELECT * FROM activities WHERE uuid_to_bin('03382d20-c8bc-48e7-a3d4-90b52fa5ceab') = uuid;\n\nselect * from users where email LIKE \"%mobile_automation_%\";\nselect * from social_accounts where sociable_id IN (2228);\nselect * from crm_profiles where user_id IN (2222,2223,2226,2227);\n\nselect * from teams order by id desc;\nSELECT * FROM users WHERE id = 2229;\nSELECT * FROM crm_profiles WHERE user_id = 2229;\nselect * from opportunities where crm_configuration_id = 88;\nselect * from crm_fields where crm_configuration_id = 88;\nselect * from crm_profiles where crm_configuration_id = 88;\n\nSELECT * FROM teams WHERE id = 1;\n\nSELECT * FROM users WHERE id = 143;\nSELECT * FROM users WHERE uuid_to_bin('fde193d3-06a2-4e1a-8895-62b94039215d') = uuid;\nSELECT * FROM teams WHERE uuid_to_bin('73385071-a756-42ae-9c73-8b53f2309467') = uuid;\n\nhttps://app.staging.jiminny.com/ondemand?\n min_duration=1\n &\n only_recorded=1\n &\n user_id%5B%5D=641f1acb-16b8-42d1-8726-df52979dad0e\n &\n sequence_number=2\n\n select * from users where team_id = 1 and email like '%stoyan%'\n\nselect * from coaching_feedbacks;\n\nselect * from teams;\nSELECT * FROM users WHERE team_id = 36;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 19\nand sa.provider = 'pipedrive';\n\nselect * from users where id = 143;\n\nSELECT * FROM users WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\nSELECT * FROM teams WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\nSELECT * FROM activity_shares WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\n\nselect * from users where team_id = 2;\nselect * from activities where crm_configuration_id = 39\nand activities.scheduled_start_time BETWEEN '2025-04-09 00:00:00' AND '2025-04-09 23:59:59'\nAND user_id = 143\norder by id desc;\n\n# ************************************************************************************\nselect * from teams where id = 142; # 2312, 126\nselect * from team_settings;\nselect * from users where team_id = 142; # 21642\nSELECT * FROM social_accounts WHERE sociable_id = 21642;\nSELECT * FROM crm_profiles cp join users u ON u.id = cp.user_id WHERE team_id = 142;\nselect * from crm_profiles where id IN (93);\nselect * from invitations;\nselect * from team_features where team_id = 1;\n\nSELECT * FROM crm_configurations WHERE id = 126;\nselect * from accounts where crm_configuration_id = 126 order by id desc;\nselect * from leads where crm_configuration_id = 126 order by id desc;\nselect * from contacts where crm_configuration_id = 126 order by id desc;\nselect * from opportunities where crm_configuration_id = 126 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 126 order by id desc;\nselect * from crm_fields where crm_configuration_id = 126 # 11060\n# and type IN ('picklist', 'status')\n# and object_type = 'task'\norder by id desc;\n# 5731,5732,5733\nselect DISTINCT crm_field_id from crm_field_values where crm_field_id IN (11151,12239,12215,12185,12175,12165,12144,12137,12127,12109,12107,12105,12103,12092,12037,12005,12003,11987,11969,11958,11951,11942,11931,11924,11921,11917,11915,11901,11893,11883,11872,11870,11868,11866,11839,11833,11821,11793,11780,11777,11769,11757,11737,11735,11656,11645,11638,11629,11618,11611,11602,11591,11584,11581,11558,11544,11543,11534,11532,11529,11527,11503,11497,11493,11488,11470,11468,11457,11455,11397,11387,11372,11363,11348,11323,11318,11309,11301,11300,11292,11290,11286,11284,11256,11252,11242,11237,11233,11219,11176,11160) order by id desc;\nselect * from crm_layouts where crm_configuration_id = 126 order by id desc;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id in (300,299,298);\nselect * from stages where crm_configuration_id = 126 order by id desc;\nselect * from business_processes where crm_configuration_id = 126 order by id desc;\nselect * from business_process_stages where business_process_id IN (76,75,74,73);\nselect * from playbooks where team_id = 142;\nselect * from playbook_layouts where playbook_id IN (108);\nSELECT * FROM playbook_categories WHERE playbook_id IN (108);\n\nselect * from teams where id = 130;\nSELECT * FROM social_accounts WHERE sociable_id = 2291;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 2\nand sa.provider = 'hubspot';\n\nSELECT * FROM activities\n WHERE crm_configuration_id = 110;\n\nselect * from teams;\nselect * from crm_configurations;\n\nSELECT * FROM activities WHERE id = 628773;\nSELECT * FROM crm_profiles WHERE user_id = 1460;\nSELECT * FROM social_accounts WHERE sociable_id = 2291;\n\nselect * from teams;\nselect ru.*, pr.*, p.* from users u join role_user ru on ru.user_id = u.id\njoin permission_role pr on pr.role_id = ru.role_id\n join permissions p on p.id = pr.permission_id\nwhere team_id = 495 and p.name IN ('dial');\n\nselect * from teams where id = 145;\nselect * from crm_configurations where id = 129;\nselect * from social_accounts where sociable_id = 2317;\nSELECT * FROM activities WHERE uuid_to_bin('8dbab184-a333-4268-ad57-fb41f8d53a9a') = uuid;\n\nselect * from teams where id = 1;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 280;\nSELECT * FROM crm_layout_entities WHERE id = 5507;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type IN ('event');\n\nselect * from teams;\nselect * from activities where crm_configuration_id = 14;\n\nSELECT * FROM social_accounts where provider = 'copper';\n\nselect * from activities where id = 628467;\nselect * from participants where activity_id = 628467;\n\nSELECT * FROM contacts WHERE id = 3969;\nSELECT * FROM accounts WHERE id = 177;\n\nSELECT * FROM activities WHERE uuid_to_bin('4eb54c77-cfa3-2bd4-84a7-9ed46a21c988') = uuid;\n\n# ********************* BH\nselect * from teams where id = 36;\nSELECT * FROM crm_configurations WHERE id = 21;\nselect * from activities where crm_configuration_id = 21 and id = 607901;\nselect * from activities where crm_configuration_id = 21;\n\nselect * roles;\nselect * from permissions;\nselect * from permission_role where permission_id = 226;\n\nselect * from migrations order by id desc;\n\n# mercury\n# neptune\n# earth\n\nselect * from teams;\nselect * from teams where id = 19;\nselect * from teams where id = 27;\nselect * from users where team_id = 27;\nSELECT * FROM crm_configurations WHERE id = 42;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 19\nand sa.provider = 'pipedrive';\n\nselect * from activities where id = 631461;\nSELECT * FROM crm_field_values WHERE crm_field_id = 180;\n\nselect * from teams where id = 2;\nSELECT * FROM social_accounts WHERE sociable_id = 89;\n\nSELECT * FROM activities WHERE uuid_to_bin('ba0c029a-bc14-4e17-8603-64174acebcbb') = uuid; # 634273\nselect * from activity_summary_logs where activity_id = 634273;\n\nselect * from sidekick_settings where team_id = 2;\n\nselect * from teams; # 2, 2\nSELECT * FROM crm_configurations WHERE team_id = 2; # 2\nselect * from team_features where team_id = 2;\nselect * from features;\nSELECT * FROM opportunities WHERE crm_configuration_id = 2 and crm_provider_id = '51317301383';\nSELECT * FROM opportunities WHERE crm_configuration_id = 2 order by id desc;\n\nselect * from automated_reports order by id desc;\nselect * from automated_report_results order by id desc;\nselect * from users where team_id = 1 and id IN (7160, 3248);\nselect * from migrations order by id desc;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1052 and sa.provider = 'hubspot';\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 = 565;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 175;\nselect * from playbook_categories where playbook_id = 175;\nselect * from users where team_id = 1052;\nselect * from users where id = 7160;\nselect * from crm_profiles where user_id = 7160;\nselect * from features;\nselect\n *\n# id, uuid, type, provider, playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id, stage_id,\n# crm_configuration_id, crm_provider_id, transcription_id, status\nfrom activities where crm_configuration_id = 1 and type = 'conference'\n# and crm_provider_id IS NOT NULL\nand provider != 'uploader' and actual_start_time IS NOT NULL\nORDER by id desc;\nselect * from activities where id = 54747783; # 00UO400000pCzojMAC\n\nselect p.id, p.activity_type, pc.id, pc.name\nFROM playbooks p\njoin playbook_categories pc on p.id = pc.playbook_id\nwhere p.team_id = 1 and p.activity_type = 'event';\n\nSELECT * FROM crm_fields WHERE crm_configuration_id = 1 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id = 4;\n\nselect * from crm_layouts cl join playbook_layouts pl on cl.id = pl.layout_id\nwhere crm_configuration_id = 1 and pl.playbook_id = 175;\n\nselect * from teams;\nSELECT r.* FROM automated_reports r\njoin teams t on r.team_id = t.id\nWHERE r.frequency = 'daily'\n and r.status = 1\nAND t.status = 'active'\nAND (r.expires_at >= now() OR r.expires_at IS NULL);\n\nselect * from automated_report_results where report_id IN (18, 33);\n\nselect * from users where team_id = 1 and id = 1047;\nSELECT * FROM social_accounts WHERE sociable_id = 1047;\n\nselect * from activity_searches where id = 10932;\nselect * from activity_search_filters where activity_search_id = 10932;\nselect * from automated_reports order by id desc;\nselect * from automated_report_results order by id desc;\nselect * from automated_reports where id IN (55);\nselect * from automated_report_results where id IN (81);\nselect * from users where id IN (10633, 13987, 11985);\nselect * from users where group_id IN (3710);\n\nSELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;\nSELECT * FROM automated_report_results WHERE uuid_to_bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;\n\nselect * from teams;\nselect * from accounts where team_id = 1;\n\nselect * from automated_report_results where media_type = 'pdf' and status = 2;\nSELECT * FROM automated_report_results WHERE uuid_to_bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid;\n\nselect * from teams where id = 1029;\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 = 1029 and sa.provider = 'pipedrive';\n\n[\n {\n \"user_id\": \"23460 (owner)\",\n \"email\": \"integration-account@pipedrive.jiminny.com\",\n \"id\": 69,\n \"sociable_id\": 23460,\n \"provider_user_id\": \"19555731\",\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,\n \"refresh_token_expires\": null,\n \"provider\": \"pipedrive\",\n \"state\": \"connected\",\n \"auth_scope\": \"base,deals:full,activities:full,contacts:full,search:read\",\n \"retry_after\": null,\n \"created_at\": \"2025-04-16 08:23:28\",\n \"updated_at\": \"2026-05-18 07:13:18\",\n \"provider_user_token_encrypted\": \"eyJpdiI6Ik9oYzBwcTVteWN4ajBRaDdMb0FjWGc9PSIsInZhbHVlIjoiQUNMbjU5UHR2Q1RnbWRXMEU1TUx6UVpRU3gzdVc5WktmTE4rVlhXa3lRaGhyUUlZMVZRWEJuR0JaWWhZZXNPRlBuanhuYU5MVHZ5TG9NTVVjNjJSUUpZZ2VhbGYxbHg0UzJEdTVmQjNFZnJRZkMwYjd0N2RMZ05GRS9IR3c2K0NoVjBjYTA5UG12SkxHeDlDMGVNN3ptUWUzblFiTngyYzR1eUpHSEYrdEwvZm0yZklGYjBSNEtTR2ZGazhLM1hqT3lVbjFobDNPZ0d3anFlcjhKcXpERlZGOVN1YmFyNDIvM1BFRDFMYnp4WEI4TGVLM2xYcy9CL0RDOWlQNHI3N0NwWnJPMWRtZllmM2ZKeE9TV2NBeDZxL2M1YnlSVzd3ZW96T3F1QmtBYXBHYkUraGcvdCtRajlYZXBjVVBSdFlMUjVPVDVJbDdyenVoWjMrbVJvU3ZZR1dQZ3pqQ3F3aDF2U2xPZWZIN3BCWVFLNXpxQUtDb2pIK0xHc1E3SklSM3Q0VkNSbm9oK2pFK3hLaW54T1dWbEVneUp0RGhhdVBuOFI4MXROc3dZWnFnTUpiaDVMMnZ4QmlRM3k4QWFlMVFWUFYvdGhJQzZBYnhBQmhWa2ZKN1ZhSnhpaExxbmlTemgzUWw3aXJtWjlSMlhmd0lWMDNDN1N3My9Ua0hCL2xqY3RkVFhMSjFJMDRjOE5DWlgrZ3FMVXN6RWlwUE5GWERZdG1xVjVxOFlLRGs2VVJKS3FLeWRxQjYxdDh4Z2JJNXhlWEZ3dkQ4SGtybDNUcndzblFHeVJNRkYraFh2UDFIUTdMQ1BZa3dEU1dBbzk5K0dyT2RNVFBZZUJpRytSck5pYlI1YUZyMmhUNEZCdWxHYmJLREtzbUpjVkhvV0RoejJpbm1SWHlNaXE5M0RhcS94UW9EdFoweWF3bVFVY0dTZWFPSXBmOCtDYndia215cmtyZU1oT0Exam1CV2tPblNhYjY4clVEeUs3anVHUmNHeS9YLzRha1VhbGl3N3lwaDlzZnRhQUZta2s4eFllNHgzRklSRmNyazJ4dlBDMnByNCtBRjNaVjJCTT0iLCJtYWMiOiJkYTQxZDY1OTY2ZTljMTgyZWRhNGEzMGZjZDc2MjBjN2NlNzU2YTViNGQxNWE1NTI2ZmI1MWQyYjQ2ODYxZmEwIiwidGFnIjoiIn0=\",\n \"provider_refresh_token_encrypted\": \"eyJpdiI6Imt2bGxlSmxUK05GMjF0dEtPaTMrUlE9PSIsInZhbHVlIjoiUXZHTElZRXkreHFxUU02SnZ4eVBacG9WWTRlVkd0USszV3JyVFlpU2ZaY25GSWo2WFcrRzNlbFRlUXRQczNwSXRCcEdvZEpveG9jMzBDSTgwdnZLQnc9PSIsIm1hYyI6ImQxYWI0NzU5Nzg5MDI4YWVhZmQ4Mjg1YzhkZDQzMjRkYWYwYTdhZTY5MDMxMjc0OWNiYjY0Nzc3NDQ0MTEyY2EiLCJ0YWciOiIifQ==\",\n \"encryption_key\": \"0x01020300786192D9D96DD60D3D1EBC9DFAEE5F0C45EE80165CF3F3D2B3B627026AA7CFC7CA0128DD463535D32EE491ADBADF8B07596B0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040C7FB1319048ECB2EA3F23B995020110802B52D22F5EAD341AB238FBBCB6093156E443876A664BA5555D722565C2B2D04422C868CD7350555E3CC74221\",\n \"sociable_type\": \"user\",\n \"owner_id\": 23460\n },\n {\n \"user_id\": \"23463\",\n \"email\": \"jiminny_web_sa@pipedrive.jiminny.com\",\n \"id\": 72,\n \"sociable_id\": 23463,\n \"provider_user_id\": \"23270841\",\n \"provider_user_token\": \"v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:txqCuWLeVhgwiaFqXIvQWWrtrnFIy_4lT3VCr-sRB4g6_2lK8KcQ_6ka_qFmZhr-IeIAKmAImx6H1iIKx4Ab7XZ5MnKIh03GKbHjI0n0rGT9UYkeH21jKOxJvKaSX_TyLbxFPR6irPQyvqcpBClXI52gVJH01KzZy_dMTHFXhhDLOIhEpSrQXHG7Qo8q7OuBeSPZrU1ALi9kmAm4GTpzGTbzfl-hUt9IAfPunJOCyv3mf2Tl-MT8EyQgOFPrsP3yz9UlSyVhb40zO_bCnUrqNxjwgm_E6vgpVrwULTQbHe-43Dq-TRetjceUzT88GBgVJ0UdxXP5BRBVXcL5ir8-9ZTMaNU\",\n \"provider_refresh_token\": \"5034113:23270841:34790b44838f5fd422c2d2c82e00f1ecf2178ad1\",\n \"expires\": 1753837219,\n \"refresh_token_expires\": null,\n \"provider\": \"pipedrive\",\n \"state\": \"full-refresh\",\n \"auth_scope\": \"base,deals:full,activities:full,contacts:full,search:read\",\n \"retry_after\": null,\n \"created_at\": \"2025-04-16 10:41:12\",\n \"updated_at\": \"2025-07-30 01:00:17\",\n \"provider_user_token_encrypted\": \"eyJpdiI6InVEVEl2SzIxMjd1bkNDWG9lY3YvQ0E9PSIsInZhbHVlIjoiRlJLbDZ3ZHo2dHMxUWQwdGU2YUZjV3lPWHlxQTJ0eWh4S0RTMjlSaThVcktoaWhXcTd2UXl4Mjg4bW5UUnZCZEQ5NXpuQTVKOURiMDNIa3l3K0lSWCt5azRBOEdHbitWQXhxeEpMVUZ1dnF2NVl1TTZLelZOaGNvRlBLeGpIWlpoRGloUEprd2xoNUFPcTlLcUd3WVlUU2svR1NOeXBYQ2NnMWhnK1V2aytOeVVMNzJGdVZXMU1JS3BSaGNCcmxkVjEwQ01mQXNBdWNhS1lMZWZobnZwcHBkN1R4bUVDRUNYdnNtSVJkdG5MdkN3djJBT0hMRDl1MHFGbnl4WU13ejBkUWsrdUljWkZhcTJlN0JDSGdTVzlPY0FGMUJlZi9WRGpkMUk5R20wblYwSk9VR2FuaHpLTzJNeitMbnF1V1NEMUUxRmYzaDRGZDMyaXd3Z0FjQno4SzVoYjUyTmV3UXNpRlF4TGZKNVl3dUFqdGhKVWJjRVlUUXRGalBpaXJvSGJmbS8rd25aQ2Zvc05saHRDRjlHV1VEUFFiRU5xbWRVNkxFSXV0RUZyaUlYNWMwMmhnZ0Y1VUQ4eEFkY2QyWXpnR0NidkVJSWdjVGljUjA3NDdpZW9WUHhtSlpGSGdNU2hRUTA5ZW03RGpiRFdrdytkOHJXSUxlazZNaG9iaUg2NFZYdEc3YklMeFZvblBzWmVRSDcvN2M4WUNtL3h4S2IrUW00cXhialBia3BJcW5XallBNlV5WWdhcE1ZVFBBM3RSSUVBamYvOGZEQWM5a2FJMGwyWkRSU3dlTEtPemZlQ3RXRGNDcEdYRHdMNTlTQVg2SUdUN0hVaXdZT1dUOUlrVzkrZHFBemhwWXg1cm4rSy9UOHUzcnNSM2dISlhBRTEyVUNyTkZYaFJYUlN1a2RKVHhhM2dHckR3a1JGaVZ2Wk9BVnhTclVpSEhwWTVpQTlJbXVkOUxSTGpRbDk0a1VtbE9QMVAvN3VlVEhJUHd2elowd0laNVIzZ3M3N0ZOK0NDakIwQ2FicGxoMDBhTXI0VUppUmFOZHdlWUdGV21NNFQ4RU1nY0dnWT0iLCJtYWMiOiI0ZTU4ZmJkNTdkYmY0NGE4NTJjZjlhNDExNzE2YjhlOWM2NTA5OGY2MDA4OTcyZDVlOTljY2JjZDhmMjBhMDUyIiwidGFnIjoiIn0=\",\n \"provider_refresh_token_encrypted\": \"eyJpdiI6IkJGMkdRVHRKM2VTcitKNGcvQWJtUGc9PSIsInZhbHVlIjoicmFyRkxPZ1Rybm1ORXlEVjJ2TXFGTzJtM3hWaFhnUVVHN2ZlR1lRM0I5d3ozbnZTcU5EdzJqRkI2elhyNWhlenRTUXV3bjk0N1JXeklDMVAyUzBKcHc9PSIsIm1hYyI6ImJhODVjMGQyZDE3Y2ExNjc2OWVjYWJiNmFjYWVkODIyMTMyNWVhYTExMTgwYTEyMTU0MzUzZGE1YjQ5YzQ5ZjEiLCJ0YWciOiIifQ==\",\n \"encryption_key\": \"0x01020300788C37CDF66ABE9301A68D5D4866AC0C197E04EEE4D904F20A59991322EBAE252301BEF4B24FF01359E934E5654617E4EEAC0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040CEB00EF45BDEA999A5558889E020110802B925F372F7BEFAF0B45E48686113D1DA430ECFCC07B1F61BA6828CC44235278EDB05C486E8068D0BE737D91\",\n \"sociable_type\": \"user\",\n \"owner_id\": 23460\n }\n]","depth":4,"on_screen":true,"value":"SELECT * FROM teams WHERE id = 1;\n\nselect * from crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 283;\nSELECT * FROM crm_fields WHERE id = 2234;\nSELECT * FROM crm_field_values WHERE crm_field_id = 2234;\n\nselect * from crm_profiles where user_id = 143;\n\nselect * from record_types where crm_configuration_id = 39; # 0121K000001MHElQAO,0121K000001MHEqQAO\nselect * from business_processes where crm_configuration_id = 39;\n# 01941000000H669AAC, 01941000000H66JAAS\n\nselect * from record_type_field_values\n where record_type_id IN (24);\n\nselect * from crm_field_values where id IN (2730);\n\nselect * from crm_configurations where id = 39;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce'; #1035\n\n\nselect * from users where team_id = 1; # 222 group 3\nSELECT * FROM activities WHERE user_id = 222 order by id desc;\nselect * from sidekick_settings where team_id = 1;\nselect * from teams where id = 1;\nselect * from team_features where team_id = 1;\n\nselect * from activities where crm_configuration_id = 2\nand provider = 'ms-teams' and id = 608765;\n\nSELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id = '59523413338';\n\nselect * from sidekick_settings where team_id = 2;\n\nSELECT * FROM activities WHERE id = 608660;\nselect * from activity_summary_logs where activity_id = 608660;\nselect * from ai_prompts where transcription_id = 11214;\n\n# ********************************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('ed78a437-2804-450e-ab2f-56ab1c641346') = uuid;\n# id: 608818, crm: 59628809737\nSELECT * FROM activities WHERE uuid_to_bin('36b06e55-afdd-4782-8dee-c624cd0af191') = uuid;\n# id: 608821, crm: 59632069252\nSELECT ce.start_time, ce.end_time, a.id, a.uuid, crm_provider_id, calendar_event_id, title,\nplaybook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id,\nscheduled_start_time, scheduled_end_time, actual_start_time, actual_end_time, a.created_at\nFROM activities a\njoin calendar_events ce on a.calendar_event_id = ce.id\nWHERE a.id IN (608818, 608821);\n\nselect * from users where team_id = 1;\nselect * from team_settings where team_id = 1;\nselect * from crm_profiles where crm_configuration_id = 39 order by user_id;\n\nselect * from team_features where team_id = 1;\n\nselect * from users where team_id = 2;\n\nSELECT * FROM activities WHERE uuid_to_bin('ec7647e9-5225-458b-b475-f31aa2769204') = uuid; # 612639\n# Preslava N. Ivanova, grou id 3\n\nSELECT * FROM opportunities WHERE uuid_to_bin('a2928fe5-aec5-46cb-85d9-7654c89e46a6') = uuid;\n\nselect * from activities where opportunity_id = 344 and actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00';\n\nselect\n a.id,\n a.type,\n a.scheduled_start_time,\n a.actual_start_time,\n a.created_at,\n a.opportunity_id,\n a.status\nFROM activities a\nWHERE opportunity_id = 344\nand status IN ('completed', 'received', 'delivered')\nand (\n (a.actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')\nOR (a.created_at between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')\nOR (a.scheduled_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00'))\n;\n\nSELECT * FROM users WHERE id = 222;\n\nSELECT * FROM crm_profiles WHERE user_id = 222;\nselect * from crm_layouts where crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 281;\n\nselect * from group_deal_risk_types;\n\nselect * from opportunities where team_id = 1;\n\nSELECT * FROM opportunities WHERE id = 315;\nSELECT * FROM crm_field_data WHERE object_id = 315;\nselect * from crm_field_data where object_id = 260;\n\nselect * from generic_ai_prompts where subject_id = 315;\n\nselect * from teams; # 36, 21, 121, james.graham@bullhorn.jiminny.com\nSELECT * FROM social_accounts WHERE sociable_id = 121 and provider = 'bullhorn';\n\n# ************************************************************************************\nselect * from teams where id = 1;\nselect * from crm_configurations where id = 39;\nselect * from users where team_id = 1;\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 1;\n# 1 - 00541000004281rAAA\n# 204 - 0052g000003freeAAA\n# 429 - 0052g000003qGOiAAM\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce';\n\nselect * from activities where type = 'softphone'\nand created_at > '2024-12-11 15:24:36' order by id desc;\n\nselect * from activity_providers where team_id = 1;\nselect * from activity_provider_users where activity_provider_id = 328;\n\nselect * from opportunities where crm_configuration_id = 39\nAND account_id = 178 AND is_closed = false\norder by created_at DESC;\n\nselect * from contacts where id = 3952;\nselect * from accounts where id = 178;\n\n# ************************************************************************************\nselect * from teams where id = 36;\nselect * from crm_configurations where id = 21;\nselect * from users where team_id = 36;\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 36;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 36\nand sa.provider = 'bullhorn';\n\nselect * from social_accounts where id = 348;\nUPDATE social_accounts SET\nprovider_user_token = '21442_6802599_91:41179a58-21e7-4d7c-ad58-56bb666b2f65',\nprovider_refresh_token = '21442_6802599_91:01c6b335-3f2a-42e4-85ff-8a08fa65fceb',\nexpires = 1733998131,\nstate = 'connected'\nWHERE id = 348;\n\n# ************************************************************************************\nselect * from teams where id = 31;\nselect * from crm_configurations where id = 18;\n\nselect * from users where team_id = 31; # 257\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 31;\n\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 31\nand sa.provider = 'close';\n\nselect * from contacts where crm_configuration_id = 18;\n\n# ********************** NEPTUNE **************************************************************\nselect * from teams;\nselect * from users where id IN (1030, 1035, 1052);\nselect * from crm_configurations;\n\nselect * from users where team_id = 65; # 257\nselect * from team_settings where team_id = 65; # 257\nselect * from invitations where team_id = 65; # 257\nselect * from users where email = 'integration-account@jiminny.com'; # 257\nselect u.email, cp.* from users u\njoin crm_profiles cp on u.id = cp.user_id\nwhere u.team_id = 65;\n\nselect * from crm_configurations where id = 53;\nselect * from accounts where crm_configuration_id = 53 order by id desc;\nselect * from leads where crm_configuration_id = 53 order by id desc;\nselect * from contacts where crm_configuration_id = 53 order by id desc;\nselect * from opportunities where crm_configuration_id = 53 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 53 order by id desc;\nselect * from crm_fields where crm_configuration_id = 53 order by id desc;\nselect * from crm_field_values where crm_field_id = 3341 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 53 order by id desc;\nselect * from stages where crm_configuration_id = 53 order by id desc;\n\n\nselect * from crm_profiles where crm_configuration_id = 13;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 65\nand sa.provider = 'integration-app';\n\nselect * from contacts where crm_configuration_id = 13;\n\nselect * from social_accounts where sociable_id = 283;\n\nSELECT * FROM opportunities WHERE crm_provider_id = '006O400000E9bzeIAB';\n\nselect * from activity_providers where team_id = 65;\nSELECT * FROM activities WHERE crm_configuration_id IN (51, 52, 53);\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 65\n;\n\n# ***************************** STAGING ********************************************\nSELECT * FROM teams;\nSELECT * FROM teams WHERE id = 88;\nSELECT * FROM teams WHERE id = 89;\nselect * from team_settings where team_id = 89;\nSELECT * FROM users WHERE team_id = 89;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 89;\n\nselect * from users;\nSELECT * FROM social_accounts WHERE sociable_id = 1761;\nSELECT * FROM crm_configurations WHERE id = 70;\nselect * from accounts where crm_configuration_id = 70 order by id desc;\nselect * from leads where crm_configuration_id = 70 order by id desc;\nselect * from contacts where crm_configuration_id = 70 order by id desc;\nselect * from opportunities where crm_configuration_id = 70 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 70 order by id desc;\nselect * from crm_fields where crm_configuration_id = 70 order by id desc;\nselect * from crm_field_values where crm_field_id = 3536 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 70 order by id desc;\nselect * from stages where crm_configuration_id = 70 order by id desc;\nselect * from business_processes where crm_configuration_id = 70 order by id desc;\nselect * from business_process_stages where business_process_id = 34;\n\nselect * from contacts where id = 10468;\n\nselect * from crm_layouts where crm_configuration_id = 70;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 388;\nSELECT * FROM crm_fields WHERE id IN (3533,3534,3535);\n\nselect * from activities where crm_configuration_id = 70\nand (account_id IS NOT NULL or lead_id IS NOT NULL or contact_id IS NOT NULL or opportunity_id IS NOT NULL) order by id desc;\n\nSELECT * FROM activities WHERE uuid_to_bin('2e10b60f-8a61-41c5-a3d4-28835353dc65') = uuid;\nSELECT * FROM activities where crm_configuration_id = 69 ;\n\nSELECT * FROM users WHERE email LIKE '%jiminny_web_sa2@jiminny.com%';\nSELECT * FROM activities WHERE uuid_to_bin('5a150c93-40fc-42ec-b3bd-c1d328e09f6e') = uuid;\nSELECT * FROM opportunities WHERE id = 385;\n\nselect * from participants p\njoin activities a on p.activity_id = a.id\nwhere a.crm_configuration_id = 70\nand (p.lead_id IS NOT NULL or p.contact_id IS NOT NULL);\nSELECT * FROM participants WHERE id = 1013638;\n\nselect * from teams where id = 90;\nselect * from users where team_id = 90;\nselect * from social_accounts where social_accounts.sociable_id IN (1960,1760);\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 71;\nselect * from invitations where team_id = 90;\n\nselect * from crm_configurations where id = 71;\nselect * from accounts where crm_configuration_id = 71 order by id desc;\nselect * from leads where crm_configuration_id = 71 order by id desc;\nselect * from contacts where crm_configuration_id = 71 order by id desc;\nselect * from opportunities where crm_configuration_id = 71 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 71 order by id desc;\nselect * from crm_fields where crm_configuration_id = 71 order by id desc;\nselect * from crm_field_values where crm_field_id = 3341 order by id desc;\nselect * from crm_layouts where crm_configuration_id = 71 order by id desc;\nselect * from stages where crm_configuration_id = 71 order by id desc;\n\nselect * from users order by secondary_email desc;\nselect u.id, u.email, u.status, sa.id, sa.provider_user_id from social_accounts sa\n join users u on sa.sociable_id = u.id\nwhere sa.provider = 'google' and u.email LIKE 'aneliya%';\n\nselect * from failed_jobs order by id desc;\n\nselect * from users where email = 'ben.allwright@learningpeople.co.uk' or secondary_email = 'ben.allwright@learningpeople.co.uk';\n\nselect * from teams;\nSELECT * FROM crm_profiles WHERE crm_configuration_id = 39;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type = 'task';\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 1\nand sa.provider = 'salesforce';\n\n# ************************************************************************************\nSELECT * FROM activities WHERE uuid_to_bin('c38b3895-fd0f-4b1f-9fb2-c170dba137c6') = uuid;\nSELECT * FROM crm_configurations WHERE id = 70;\n\nselect * from teams where id = 1;\nselect * from groups where team_id = 1;\nselect * from users where team_id = 1;\n\nselect o.id, o.name,o.close_date, u.id, u.name, u.group_id, r.id, r.display_name, g.name, g.scope from opportunities o\njoin users u on o.user_id = u.id\njoin groups g on u.group_id = g.id\njoin role_user ru on u.id = ru.user_id\njoin roles r on ru.role_id = r.id\nwhere o.crm_configuration_id = 39 and close_date > '2024-01-01 00:00:00';\n\nselect * from role_user where user_id = 143;\nselect * from roles;\n\nselect * from role_user;\nselect * from groups where id = 9;\nselect * from scope_groups where group_id = 9;\n\n# ************************************************************************************\nselect * from teams where id = 36;\nselect * from crm_configurations;\nSELECT * FROM social_accounts WHERE sociable_id = 121;\n\nhttps://crmsandbox.zoho.com/crm/jiminnyw4/tab/Leads/4776201000005049105\nhttps://crmsandbox.zoho.com/crm/\n\nhttps://crm.zoho.com/crm/org3469620/tab/Leads/230045000229559080\n https://crm.zoho.com/crm/\n org3469620\n\nSELECT * FROM activities WHERE uuid_to_bin('03382d20-c8bc-48e7-a3d4-90b52fa5ceab') = uuid;\n\nselect * from users where email LIKE \"%mobile_automation_%\";\nselect * from social_accounts where sociable_id IN (2228);\nselect * from crm_profiles where user_id IN (2222,2223,2226,2227);\n\nselect * from teams order by id desc;\nSELECT * FROM users WHERE id = 2229;\nSELECT * FROM crm_profiles WHERE user_id = 2229;\nselect * from opportunities where crm_configuration_id = 88;\nselect * from crm_fields where crm_configuration_id = 88;\nselect * from crm_profiles where crm_configuration_id = 88;\n\nSELECT * FROM teams WHERE id = 1;\n\nSELECT * FROM users WHERE id = 143;\nSELECT * FROM users WHERE uuid_to_bin('fde193d3-06a2-4e1a-8895-62b94039215d') = uuid;\nSELECT * FROM teams WHERE uuid_to_bin('73385071-a756-42ae-9c73-8b53f2309467') = uuid;\n\nhttps://app.staging.jiminny.com/ondemand?\n min_duration=1\n &\n only_recorded=1\n &\n user_id%5B%5D=641f1acb-16b8-42d1-8726-df52979dad0e\n &\n sequence_number=2\n\n select * from users where team_id = 1 and email like '%stoyan%'\n\nselect * from coaching_feedbacks;\n\nselect * from teams;\nSELECT * FROM users WHERE team_id = 36;\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 19\nand sa.provider = 'pipedrive';\n\nselect * from users where id = 143;\n\nSELECT * FROM users WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\nSELECT * FROM teams WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\nSELECT * FROM activity_shares WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;\n\nselect * from users where team_id = 2;\nselect * from activities where crm_configuration_id = 39\nand activities.scheduled_start_time BETWEEN '2025-04-09 00:00:00' AND '2025-04-09 23:59:59'\nAND user_id = 143\norder by id desc;\n\n# ************************************************************************************\nselect * from teams where id = 142; # 2312, 126\nselect * from team_settings;\nselect * from users where team_id = 142; # 21642\nSELECT * FROM social_accounts WHERE sociable_id = 21642;\nSELECT * FROM crm_profiles cp join users u ON u.id = cp.user_id WHERE team_id = 142;\nselect * from crm_profiles where id IN (93);\nselect * from invitations;\nselect * from team_features where team_id = 1;\n\nSELECT * FROM crm_configurations WHERE id = 126;\nselect * from accounts where crm_configuration_id = 126 order by id desc;\nselect * from leads where crm_configuration_id = 126 order by id desc;\nselect * from contacts where crm_configuration_id = 126 order by id desc;\nselect * from opportunities where crm_configuration_id = 126 order by id desc;\nselect * from crm_profiles where crm_configuration_id = 126 order by id desc;\nselect * from crm_fields where crm_configuration_id = 126 # 11060\n# and type IN ('picklist', 'status')\n# and object_type = 'task'\norder by id desc;\n# 5731,5732,5733\nselect DISTINCT crm_field_id from crm_field_values where crm_field_id IN (11151,12239,12215,12185,12175,12165,12144,12137,12127,12109,12107,12105,12103,12092,12037,12005,12003,11987,11969,11958,11951,11942,11931,11924,11921,11917,11915,11901,11893,11883,11872,11870,11868,11866,11839,11833,11821,11793,11780,11777,11769,11757,11737,11735,11656,11645,11638,11629,11618,11611,11602,11591,11584,11581,11558,11544,11543,11534,11532,11529,11527,11503,11497,11493,11488,11470,11468,11457,11455,11397,11387,11372,11363,11348,11323,11318,11309,11301,11300,11292,11290,11286,11284,11256,11252,11242,11237,11233,11219,11176,11160) order by id desc;\nselect * from crm_layouts where crm_configuration_id = 126 order by id desc;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id in (300,299,298);\nselect * from stages where crm_configuration_id = 126 order by id desc;\nselect * from business_processes where crm_configuration_id = 126 order by id desc;\nselect * from business_process_stages where business_process_id IN (76,75,74,73);\nselect * from playbooks where team_id = 142;\nselect * from playbook_layouts where playbook_id IN (108);\nSELECT * FROM playbook_categories WHERE playbook_id IN (108);\n\nselect * from teams where id = 130;\nSELECT * FROM social_accounts WHERE sociable_id = 2291;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 2\nand sa.provider = 'hubspot';\n\nSELECT * FROM activities\n WHERE crm_configuration_id = 110;\n\nselect * from teams;\nselect * from crm_configurations;\n\nSELECT * FROM activities WHERE id = 628773;\nSELECT * FROM crm_profiles WHERE user_id = 1460;\nSELECT * FROM social_accounts WHERE sociable_id = 2291;\n\nselect * from teams;\nselect ru.*, pr.*, p.* from users u join role_user ru on ru.user_id = u.id\njoin permission_role pr on pr.role_id = ru.role_id\n join permissions p on p.id = pr.permission_id\nwhere team_id = 495 and p.name IN ('dial');\n\nselect * from teams where id = 145;\nselect * from crm_configurations where id = 129;\nselect * from social_accounts where sociable_id = 2317;\nSELECT * FROM activities WHERE uuid_to_bin('8dbab184-a333-4268-ad57-fb41f8d53a9a') = uuid;\n\nselect * from teams where id = 1;\nSELECT * FROM crm_layouts WHERE crm_configuration_id = 39;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 280;\nSELECT * FROM crm_layout_entities WHERE id = 5507;\nSELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type IN ('event');\n\nselect * from teams;\nselect * from activities where crm_configuration_id = 14;\n\nSELECT * FROM social_accounts where provider = 'copper';\n\nselect * from activities where id = 628467;\nselect * from participants where activity_id = 628467;\n\nSELECT * FROM contacts WHERE id = 3969;\nSELECT * FROM accounts WHERE id = 177;\n\nSELECT * FROM activities WHERE uuid_to_bin('4eb54c77-cfa3-2bd4-84a7-9ed46a21c988') = uuid;\n\n# ********************* BH\nselect * from teams where id = 36;\nSELECT * FROM crm_configurations WHERE id = 21;\nselect * from activities where crm_configuration_id = 21 and id = 607901;\nselect * from activities where crm_configuration_id = 21;\n\nselect * roles;\nselect * from permissions;\nselect * from permission_role where permission_id = 226;\n\nselect * from migrations order by id desc;\n\n# mercury\n# neptune\n# earth\n\nselect * from teams;\nselect * from teams where id = 19;\nselect * from teams where id = 27;\nselect * from users where team_id = 27;\nSELECT * FROM crm_configurations WHERE id = 42;\n\nselect * from social_accounts sa\njoin users u on sa.sociable_id = u.id\nwhere u.team_id = 19\nand sa.provider = 'pipedrive';\n\nselect * from activities where id = 631461;\nSELECT * FROM crm_field_values WHERE crm_field_id = 180;\n\nselect * from teams where id = 2;\nSELECT * FROM social_accounts WHERE sociable_id = 89;\n\nSELECT * FROM activities WHERE uuid_to_bin('ba0c029a-bc14-4e17-8603-64174acebcbb') = uuid; # 634273\nselect * from activity_summary_logs where activity_id = 634273;\n\nselect * from sidekick_settings where team_id = 2;\n\nselect * from teams; # 2, 2\nSELECT * FROM crm_configurations WHERE team_id = 2; # 2\nselect * from team_features where team_id = 2;\nselect * from features;\nSELECT * FROM opportunities WHERE crm_configuration_id = 2 and crm_provider_id = '51317301383';\nSELECT * FROM opportunities WHERE crm_configuration_id = 2 order by id desc;\n\nselect * from automated_reports order by id desc;\nselect * from automated_report_results order by id desc;\nselect * from users where team_id = 1 and id IN (7160, 3248);\nselect * from migrations order by id desc;\n\nSELECT\n CONCAT(u.id, CASE WHEN u.id = t.owner_id THEN ' (owner)' ELSE '' END) AS user_id,\n u.email,\n sa.*,\n t.owner_id FROM social_accounts sa\nJOIN users u on u.id = sa.sociable_id\nJOIN teams t on t.id = u.team_id\nWHERE u.team_id = 1052 and sa.provider = 'hubspot';\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 = 565;\nselect * from playbooks where team_id = 1;\nselect * from playbooks where id = 175;\nselect * from playbook_categories where playbook_id = 175;\nselect * from users where team_id = 1052;\nselect * from users where id = 7160;\nselect * from crm_profiles where user_id = 7160;\nselect * from features;\nselect\n *\n# id, uuid, type, provider, playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id, stage_id,\n# crm_configuration_id, crm_provider_id, transcription_id, status\nfrom activities where crm_configuration_id = 1 and type = 'conference'\n# and crm_provider_id IS NOT NULL\nand provider != 'uploader' and actual_start_time IS NOT NULL\nORDER by id desc;\nselect * from activities where id = 54747783; # 00UO400000pCzojMAC\n\nselect p.id, p.activity_type, pc.id, pc.name\nFROM playbooks p\njoin playbook_categories pc on p.id = pc.playbook_id\nwhere p.team_id = 1 and p.activity_type = 'event';\n\nSELECT * FROM crm_fields WHERE crm_configuration_id = 1 and object_type = 'event';\nSELECT * FROM crm_field_values WHERE crm_field_id = 4;\n\nselect * from crm_layouts cl join playbook_layouts pl on cl.id = pl.layout_id\nwhere crm_configuration_id = 1 and pl.playbook_id = 175;\n\nselect * from teams;\nSELECT r.* FROM automated_reports r\njoin teams t on r.team_id = t.id\nWHERE r.frequency = 'daily'\n and r.status = 1\nAND t.status = 'active'\nAND (r.expires_at >= now() OR r.expires_at IS NULL);\n\nselect * from automated_report_results where report_id IN (18, 33);\n\nselect * from users where team_id = 1 and id = 1047;\nSELECT * FROM social_accounts WHERE sociable_id = 1047;\n\nselect * from activity_searches where id = 10932;\nselect * from activity_search_filters where activity_search_id = 10932;\nselect * from automated_reports order by id desc;\nselect * from automated_report_results order by id desc;\nselect * from automated_reports where id IN (55);\nselect * from automated_report_results where id IN (81);\nselect * from users where id IN (10633, 13987, 11985);\nselect * from users where group_id IN (3710);\n\nSELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;\nSELECT * FROM automated_report_results WHERE uuid_to_bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;\n\nselect * from teams;\nselect * from accounts where team_id = 1;\n\nselect * from automated_report_results where media_type = 'pdf' and status = 2;\nSELECT * FROM automated_report_results WHERE uuid_to_bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid;\n\nselect * from teams where id = 1029;\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 = 1029 and sa.provider = 'pipedrive';\n\n[\n {\n \"user_id\": \"23460 (owner)\",\n \"email\": \"integration-account@pipedrive.jiminny.com\",\n \"id\": 69,\n \"sociable_id\": 23460,\n \"provider_user_id\": \"19555731\",\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,\n \"refresh_token_expires\": null,\n \"provider\": \"pipedrive\",\n \"state\": \"connected\",\n \"auth_scope\": \"base,deals:full,activities:full,contacts:full,search:read\",\n \"retry_after\": null,\n \"created_at\": \"2025-04-16 08:23:28\",\n \"updated_at\": \"2026-05-18 07:13:18\",\n \"provider_user_token_encrypted\": \"eyJpdiI6Ik9oYzBwcTVteWN4ajBRaDdMb0FjWGc9PSIsInZhbHVlIjoiQUNMbjU5UHR2Q1RnbWRXMEU1TUx6UVpRU3gzdVc5WktmTE4rVlhXa3lRaGhyUUlZMVZRWEJuR0JaWWhZZXNPRlBuanhuYU5MVHZ5TG9NTVVjNjJSUUpZZ2VhbGYxbHg0UzJEdTVmQjNFZnJRZkMwYjd0N2RMZ05GRS9IR3c2K0NoVjBjYTA5UG12SkxHeDlDMGVNN3ptUWUzblFiTngyYzR1eUpHSEYrdEwvZm0yZklGYjBSNEtTR2ZGazhLM1hqT3lVbjFobDNPZ0d3anFlcjhKcXpERlZGOVN1YmFyNDIvM1BFRDFMYnp4WEI4TGVLM2xYcy9CL0RDOWlQNHI3N0NwWnJPMWRtZllmM2ZKeE9TV2NBeDZxL2M1YnlSVzd3ZW96T3F1QmtBYXBHYkUraGcvdCtRajlYZXBjVVBSdFlMUjVPVDVJbDdyenVoWjMrbVJvU3ZZR1dQZ3pqQ3F3aDF2U2xPZWZIN3BCWVFLNXpxQUtDb2pIK0xHc1E3SklSM3Q0VkNSbm9oK2pFK3hLaW54T1dWbEVneUp0RGhhdVBuOFI4MXROc3dZWnFnTUpiaDVMMnZ4QmlRM3k4QWFlMVFWUFYvdGhJQzZBYnhBQmhWa2ZKN1ZhSnhpaExxbmlTemgzUWw3aXJtWjlSMlhmd0lWMDNDN1N3My9Ua0hCL2xqY3RkVFhMSjFJMDRjOE5DWlgrZ3FMVXN6RWlwUE5GWERZdG1xVjVxOFlLRGs2VVJKS3FLeWRxQjYxdDh4Z2JJNXhlWEZ3dkQ4SGtybDNUcndzblFHeVJNRkYraFh2UDFIUTdMQ1BZa3dEU1dBbzk5K0dyT2RNVFBZZUJpRytSck5pYlI1YUZyMmhUNEZCdWxHYmJLREtzbUpjVkhvV0RoejJpbm1SWHlNaXE5M0RhcS94UW9EdFoweWF3bVFVY0dTZWFPSXBmOCtDYndia215cmtyZU1oT0Exam1CV2tPblNhYjY4clVEeUs3anVHUmNHeS9YLzRha1VhbGl3N3lwaDlzZnRhQUZta2s4eFllNHgzRklSRmNyazJ4dlBDMnByNCtBRjNaVjJCTT0iLCJtYWMiOiJkYTQxZDY1OTY2ZTljMTgyZWRhNGEzMGZjZDc2MjBjN2NlNzU2YTViNGQxNWE1NTI2ZmI1MWQyYjQ2ODYxZmEwIiwidGFnIjoiIn0=\",\n \"provider_refresh_token_encrypted\": \"eyJpdiI6Imt2bGxlSmxUK05GMjF0dEtPaTMrUlE9PSIsInZhbHVlIjoiUXZHTElZRXkreHFxUU02SnZ4eVBacG9WWTRlVkd0USszV3JyVFlpU2ZaY25GSWo2WFcrRzNlbFRlUXRQczNwSXRCcEdvZEpveG9jMzBDSTgwdnZLQnc9PSIsIm1hYyI6ImQxYWI0NzU5Nzg5MDI4YWVhZmQ4Mjg1YzhkZDQzMjRkYWYwYTdhZTY5MDMxMjc0OWNiYjY0Nzc3NDQ0MTEyY2EiLCJ0YWciOiIifQ==\",\n \"encryption_key\": \"0x01020300786192D9D96DD60D3D1EBC9DFAEE5F0C45EE80165CF3F3D2B3B627026AA7CFC7CA0128DD463535D32EE491ADBADF8B07596B0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040C7FB1319048ECB2EA3F23B995020110802B52D22F5EAD341AB238FBBCB6093156E443876A664BA5555D722565C2B2D04422C868CD7350555E3CC74221\",\n \"sociable_type\": \"user\",\n \"owner_id\": 23460\n },\n {\n \"user_id\": \"23463\",\n \"email\": \"jiminny_web_sa@pipedrive.jiminny.com\",\n \"id\": 72,\n \"sociable_id\": 23463,\n \"provider_user_id\": \"23270841\",\n \"provider_user_token\": \"v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:txqCuWLeVhgwiaFqXIvQWWrtrnFIy_4lT3VCr-sRB4g6_2lK8KcQ_6ka_qFmZhr-IeIAKmAImx6H1iIKx4Ab7XZ5MnKIh03GKbHjI0n0rGT9UYkeH21jKOxJvKaSX_TyLbxFPR6irPQyvqcpBClXI52gVJH01KzZy_dMTHFXhhDLOIhEpSrQXHG7Qo8q7OuBeSPZrU1ALi9kmAm4GTpzGTbzfl-hUt9IAfPunJOCyv3mf2Tl-MT8EyQgOFPrsP3yz9UlSyVhb40zO_bCnUrqNxjwgm_E6vgpVrwULTQbHe-43Dq-TRetjceUzT88GBgVJ0UdxXP5BRBVXcL5ir8-9ZTMaNU\",\n \"provider_refresh_token\": \"5034113:23270841:34790b44838f5fd422c2d2c82e00f1ecf2178ad1\",\n \"expires\": 1753837219,\n \"refresh_token_expires\": null,\n \"provider\": \"pipedrive\",\n \"state\": \"full-refresh\",\n \"auth_scope\": \"base,deals:full,activities:full,contacts:full,search:read\",\n \"retry_after\": null,\n \"created_at\": \"2025-04-16 10:41:12\",\n \"updated_at\": \"2025-07-30 01:00:17\",\n \"provider_user_token_encrypted\": \"eyJpdiI6InVEVEl2SzIxMjd1bkNDWG9lY3YvQ0E9PSIsInZhbHVlIjoiRlJLbDZ3ZHo2dHMxUWQwdGU2YUZjV3lPWHlxQTJ0eWh4S0RTMjlSaThVcktoaWhXcTd2UXl4Mjg4bW5UUnZCZEQ5NXpuQTVKOURiMDNIa3l3K0lSWCt5azRBOEdHbitWQXhxeEpMVUZ1dnF2NVl1TTZLelZOaGNvRlBLeGpIWlpoRGloUEprd2xoNUFPcTlLcUd3WVlUU2svR1NOeXBYQ2NnMWhnK1V2aytOeVVMNzJGdVZXMU1JS3BSaGNCcmxkVjEwQ01mQXNBdWNhS1lMZWZobnZwcHBkN1R4bUVDRUNYdnNtSVJkdG5MdkN3djJBT0hMRDl1MHFGbnl4WU13ejBkUWsrdUljWkZhcTJlN0JDSGdTVzlPY0FGMUJlZi9WRGpkMUk5R20wblYwSk9VR2FuaHpLTzJNeitMbnF1V1NEMUUxRmYzaDRGZDMyaXd3Z0FjQno4SzVoYjUyTmV3UXNpRlF4TGZKNVl3dUFqdGhKVWJjRVlUUXRGalBpaXJvSGJmbS8rd25aQ2Zvc05saHRDRjlHV1VEUFFiRU5xbWRVNkxFSXV0RUZyaUlYNWMwMmhnZ0Y1VUQ4eEFkY2QyWXpnR0NidkVJSWdjVGljUjA3NDdpZW9WUHhtSlpGSGdNU2hRUTA5ZW03RGpiRFdrdytkOHJXSUxlazZNaG9iaUg2NFZYdEc3YklMeFZvblBzWmVRSDcvN2M4WUNtL3h4S2IrUW00cXhialBia3BJcW5XallBNlV5WWdhcE1ZVFBBM3RSSUVBamYvOGZEQWM5a2FJMGwyWkRSU3dlTEtPemZlQ3RXRGNDcEdYRHdMNTlTQVg2SUdUN0hVaXdZT1dUOUlrVzkrZHFBemhwWXg1cm4rSy9UOHUzcnNSM2dISlhBRTEyVUNyTkZYaFJYUlN1a2RKVHhhM2dHckR3a1JGaVZ2Wk9BVnhTclVpSEhwWTVpQTlJbXVkOUxSTGpRbDk0a1VtbE9QMVAvN3VlVEhJUHd2elowd0laNVIzZ3M3N0ZOK0NDakIwQ2FicGxoMDBhTXI0VUppUmFOZHdlWUdGV21NNFQ4RU1nY0dnWT0iLCJtYWMiOiI0ZTU4ZmJkNTdkYmY0NGE4NTJjZjlhNDExNzE2YjhlOWM2NTA5OGY2MDA4OTcyZDVlOTljY2JjZDhmMjBhMDUyIiwidGFnIjoiIn0=\",\n \"provider_refresh_token_encrypted\": \"eyJpdiI6IkJGMkdRVHRKM2VTcitKNGcvQWJtUGc9PSIsInZhbHVlIjoicmFyRkxPZ1Rybm1ORXlEVjJ2TXFGTzJtM3hWaFhnUVVHN2ZlR1lRM0I5d3ozbnZTcU5EdzJqRkI2elhyNWhlenRTUXV3bjk0N1JXeklDMVAyUzBKcHc9PSIsIm1hYyI6ImJhODVjMGQyZDE3Y2ExNjc2OWVjYWJiNmFjYWVkODIyMTMyNWVhYTExMTgwYTEyMTU0MzUzZGE1YjQ5YzQ5ZjEiLCJ0YWciOiIifQ==\",\n \"encryption_key\": \"0x01020300788C37CDF66ABE9301A68D5D4866AC0C197E04EEE4D904F20A59991322EBAE252301BEF4B24FF01359E934E5654617E4EEAC0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040CEB00EF45BDEA999A5558889E020110802B925F372F7BEFAF0B45E48686113D1DA430ECFCC07B1F61BA6828CC44235278EDB05C486E8068D0BE737D91\",\n \"sociable_type\": \"user\",\n \"owner_id\": 23460\n }\n]","role_description":"text entry area","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}]...
|
1292623199131388967
|
6686649177355990093
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
namespace Jiminny\Component\SCIM;
use Jiminny\Component\SCIM\Builders\Filters;
class Constants
{
/**
* HTTP codes
*/
public const HTTP_OK = 200;
public const HTTP_CREATED = 201;
public const HTTP_NO_CONTENT = 204;
public const HTTP_NOT_FOUND = 404;
public const HTTP_BAD_REQUEST = 400;
public const HTTP_ACCESS_DENIED = 403;
public const HTTP_ERROR = 501;
/**
* Users resource constants
*/
public const USER_FIRST_NAME = 'givenName';
public const USER_FAMILY_NAME = 'familyName';
public const USER_STATUS = 'Active';
public const USER_USERNAME = 'UserName';
public const USER_EXTERNAL_ID = 'externalId';
public const USER_FIELDS = [
self::USER_FIRST_NAME,
self::USER_FAMILY_NAME,
self::USER_STATUS,
self::USER_USERNAME,
];
public const META_OPERATIONS_REPLACE = 'replace';
public const META_OPERATIONS_REPLACE_UPPER = 'Replace';
public const META_OPERATIONS_ADD = 'add';
public const META_OPERATIONS_ADD_UPPER = 'Add';
public const META_OPERATIONS_REMOVE_UPPER = 'Remove';
public const META_OPERATIONS_REMOVE = 'remove';
public const META_ID = 'id';
public const META_PHONE_NUMBERS = 'phoneNumbers';
public const META_TITLE = 'title';
public const META_ROLES = 'roles';
public const META_PATH = 'path';
public const META_ENTERPRISE_SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';
public const META_DEPARTMENT = 'department';
public const META_META = 'meta';
public const META_TYPE = 'type';
public const META_VALUE = 'value';
public const META_OPERATIONS = 'Operations';
public const META_OP = 'op';
public const META_RESOURCE_TYPE = 'resourceType';
public const META_CREATED = 'created';
public const META_LAST_MODIFIED = 'lastModified';
public const META_FORMATTED = 'formatted';
public const META_EMAILS = 'emails';
public const META_USERNAME = 'userName';
public const META_NAME = 'name';
public const META_STATUS = 'active';
public const META_PRIMARY = 'primary';
public const META_ERROR_STATUS = 'status';
public const META_ERROR_DETAIL = 'detail';
public const META_LIST_TOTAL_RESULTS = 'totalResults';
public const META_LIST_RESOURCES = 'Resources';
public const META_LIST_START_INDEX = 'startIndex';
public const META_LIST_COUNT = 'count';
public const META_LIST_ITEMS_PER_PAGE = 'itemsPerPage';
public const META_SCHEMAS = 'schemas';
public const META_FILTER = 'filter';
public const META_TYPE_WORK = 'work';
public const META_PHONE_NUMBER_TYPE_MOBILE = 'mobile';
public const META_EMAIL_TYPE_HOME = 'home';
public const META_CONTAINER_NAME = 'name';
public const META_CONTAINER_EMAILS = 'emails';
public const RESOURCE_TYPE_USER = 'User';
public const USER_PATCH_ATTR_TITLE = 'title';
public const USER_PATCH_ATTR_ACTIVE = 'active';
public const USER_PATCH_ATTR_USERNAME = 'userName';
public const USER_PATCH_ATTR_FIRST_NAME = 'name.givenName';
public const USER_PATCH_ATTR_LAST_NAME = 'name.familyName';
public const USER_PATCH_ATTR_PRIMARY_EMAIL = 'emails[type eq "work"].value';
public const USER_PATCH_ATTR_SECONDARY_EMAIL = 'emails[type eq "home"].value';
public const USER_PATCH_ATTR_PHONE_NUMBER = 'phoneNumbers[type eq "work"].value';
public const USER_PATCH_ATTR_PHONE_NUMBER_MOBILE = 'phoneNumbers[type eq "mobile"].value';
public const USER_PATCH_ATTR_ROLES = 'roles';
public const USER_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [
self::USER_PATCH_ATTR_TITLE => Mutators\Attributes\User\TitleAttr::class,
self::USER_PATCH_ATTR_ACTIVE => Mutators\Attributes\User\ActiveAttr::class,
self::USER_PATCH_ATTR_USERNAME => Mutators\Attributes\User\UsernameAttr::class,
self::USER_PATCH_ATTR_FIRST_NAME => Mutators\Attributes\User\FirstNameAttr::class,
self::USER_PATCH_ATTR_LAST_NAME => Mutators\Attributes\User\LastNameAttr::class,
self::USER_PATCH_ATTR_PRIMARY_EMAIL => Mutators\Attributes\User\PrimaryEmailAttr::class,
self::USER_PATCH_ATTR_SECONDARY_EMAIL => Mutators\Attributes\User\SecondaryEmailAttr::class,
self::USER_PATCH_ATTR_PHONE_NUMBER => Mutators\Attributes\User\PhoneNumberPrimaryAttr::class,
self::USER_PATCH_ATTR_PHONE_NUMBER_MOBILE => Mutators\Attributes\User\PhoneNumberSecondaryAttr::class,
self::USER_PATCH_ATTR_ROLES => Mutators\Attributes\User\RoleAttr::class,
];
public const FILTER_OPERATOR_EQ = 'eq';
public const SUPPORTED_FILTERS_OPERATORS = [
self::FILTER_OPERATOR_EQ,
];
public const USER_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [
self::USER_FILTER_LOCAL_ID => Filters\User\LocalIdFilter::class,
self::USER_FILTER_USERNAME => Filters\User\UserNameFilter::class,
self::USER_FILTER_FIRST_NAME => Filters\User\FirstNameFilter::class,
self::USER_FILTER_LAST_NAME => Filters\User\LastNameFilter::class,
self::USER_FILTER_EXTERNAL_ID => Filters\User\ExternalIdFilter::class,
self::USER_FILTER_DISPLAY_NAME => Filters\User\DisplayNameFilter::class,
];
public const USER_FILTER_LOCAL_ID = 'id';
public const USER_FILTER_USERNAME = 'userName';
public const USER_FILTER_FIRST_NAME = 'givenName';
public const USER_FILTER_LAST_NAME = 'familyName';
public const USER_FILTER_EXTERNAL_ID = 'externalId';
public const USER_FILTER_DISPLAY_NAME = 'DisplayName';
public const SCIM_SUPPORTED_RESOURCES = [
self::USER_RESOURCE_PREFIX,
self::GROUP_RESOURCE_PREFIX,
];
public const USER_RESOURCE_PREFIX = 'Users';
public const GROUP_RESOURCE_PREFIX = 'Groups';
public const OUTGOING_SCHEMAS_SUPPORTED = [
self::OUTGOING_CORE_USER,
];
/**
* Outgoing supported schemas
*/
public const OUTGOING_CORE_USER = 'urn:ietf:params:scim:schemas:core:2.0:User';
public const OUTGOING_ERROR = 'urn:ietf:params:scim:api:messages:2.0:Error';
public const OUTGOING_LIST_RESPONSE = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';
public const OUTGOING_CORE_GROUP = 'urn:ietf:params:scim:schemas:core:2.0:Group';
/**
* Groups resource constants
*/
public const GROUP_ATTRIBUTE_DISPLAY_NAME = 'displayName';
public const GROUP_ATTRIBUTE_EXTERNAL_ID = 'externalId';
public const GROUP_ATTRIBUTE_ID = 'id';
public const RESOURCE_TYPE_GROUP = 'Group';
public const GROUP_FILTER_QUERY_NAME = 'filter';
public const GROUP_EXCLUDED_ATTRIBUTES = 'excludedAttributes';
public const GROUP_SUPPORTED_FILTER_ATTRIBUTES = [
self::GROUP_ATTRIBUTE_DISPLAY_NAME,
];
public const GROUP_MEMBERS = 'members';
public const SUPPORTED_PATCH_OPERATIONS = [
self::META_OPERATIONS_ADD,
self::META_OPERATIONS_REPLACE,
self::META_OPERATIONS_REMOVE,
];
public const GROUP_PATCH_ATTRIBUTE_MEMBERS = 'members';
public const GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME = 'displayName';
public const GROUP_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [
self::GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME => Mutators\Attributes\Group\DisplayNameAttr::class,
self::GROUP_PATCH_ATTRIBUTE_MEMBERS => Mutators\Attributes\Group\MembersAttr::class,
];
public const GROUP_FILTER_DISPLAY_NAME = 'displayname';
public const GROUP_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [
self::GROUP_FILTER_DISPLAY_NAME => Filters\Group\DisplayNameFilter::class,
];
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny_jupiter
Sync Changes
Hide This Notification
Code changed:
Hide
19
19
17
Previous Highlighted Error
Next Highlighted Error
SELECT * FROM teams WHERE id = 1;
select * from crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 283;
SELECT * FROM crm_fields WHERE id = 2234;
SELECT * FROM crm_field_values WHERE crm_field_id = 2234;
select * from crm_profiles where user_id = 143;
select * from record_types where crm_configuration_id = 39; # 0121K000001MHElQAO,0121K000001MHEqQAO
select * from business_processes where crm_configuration_id = 39;
# 01941000000H669AAC, 01941000000H66JAAS
select * from record_type_field_values
where record_type_id IN (24);
select * from crm_field_values where id IN (2730);
select * from crm_configurations where id = 39;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce'; #1035
select * from users where team_id = 1; # 222 group 3
SELECT * FROM activities WHERE user_id = 222 order by id desc;
select * from sidekick_settings where team_id = 1;
select * from teams where id = 1;
select * from team_features where team_id = 1;
select * from activities where crm_configuration_id = 2
and provider = 'ms-teams' and id = 608765;
SELECT * FROM activities WHERE crm_configuration_id = 2 and crm_provider_id = '59523413338';
select * from sidekick_settings where team_id = 2;
SELECT * FROM activities WHERE id = 608660;
select * from activity_summary_logs where activity_id = 608660;
select * from ai_prompts where transcription_id = 11214;
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('ed78a437-2804-450e-ab2f-56ab1c641346') = uuid;
# id: 608818, crm: 59628809737
SELECT * FROM activities WHERE uuid_to_bin('36b06e55-afdd-4782-8dee-c624cd0af191') = uuid;
# id: 608821, crm: 59632069252
SELECT ce.start_time, ce.end_time, a.id, a.uuid, crm_provider_id, calendar_event_id, title,
playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id,
scheduled_start_time, scheduled_end_time, actual_start_time, actual_end_time, a.created_at
FROM activities a
join calendar_events ce on a.calendar_event_id = ce.id
WHERE a.id IN (608818, 608821);
select * from users where team_id = 1;
select * from team_settings where team_id = 1;
select * from crm_profiles where crm_configuration_id = 39 order by user_id;
select * from team_features where team_id = 1;
select * from users where team_id = 2;
SELECT * FROM activities WHERE uuid_to_bin('ec7647e9-5225-458b-b475-f31aa2769204') = uuid; # 612639
# Preslava N. Ivanova, grou id 3
SELECT * FROM opportunities WHERE uuid_to_bin('a2928fe5-aec5-46cb-85d9-7654c89e46a6') = uuid;
select * from activities where opportunity_id = 344 and actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00';
select
a.id,
a.type,
a.scheduled_start_time,
a.actual_start_time,
a.created_at,
a.opportunity_id,
a.status
FROM activities a
WHERE opportunity_id = 344
and status IN ('completed', 'received', 'delivered')
and (
(a.actual_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')
OR (a.created_at between '2024-10-11 00:00:00' and '2024-10-12 00:00:00')
OR (a.scheduled_start_time between '2024-10-11 00:00:00' and '2024-10-12 00:00:00'))
;
SELECT * FROM users WHERE id = 222;
SELECT * FROM crm_profiles WHERE user_id = 222;
select * from crm_layouts where crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 281;
select * from group_deal_risk_types;
select * from opportunities where team_id = 1;
SELECT * FROM opportunities WHERE id = 315;
SELECT * FROM crm_field_data WHERE object_id = 315;
select * from crm_field_data where object_id = 260;
select * from generic_ai_prompts where subject_id = 315;
select * from teams; # 36, 21, 121, [EMAIL]
SELECT * FROM social_accounts WHERE sociable_id = 121 and provider = 'bullhorn';
# [PASSWORD_DOTS]
select * from teams where id = 1;
select * from crm_configurations where id = 39;
select * from users where team_id = 1;
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 1;
# 1 - 00541000004281rAAA
# 204 - 0052g000003freeAAA
# 429 - 0052g000003qGOiAAM
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce';
select * from activities where type = 'softphone'
and created_at > '2024-12-11 15:24:36' order by id desc;
select * from activity_providers where team_id = 1;
select * from activity_provider_users where activity_provider_id = 328;
select * from opportunities where crm_configuration_id = 39
AND account_id = 178 AND is_closed = false
order by created_at DESC;
select * from contacts where id = 3952;
select * from accounts where id = 178;
# [PASSWORD_DOTS]
select * from teams where id = 36;
select * from crm_configurations where id = 21;
select * from users where team_id = 36;
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 36;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 36
and sa.provider = 'bullhorn';
select * from social_accounts where id = 348;
UPDATE social_accounts SET
provider_user_token = '21442_6802599_91:41179a58-21e7-4d7c-ad58-56bb666b2f65',
provider_refresh_token = '21442_6802599_91:01c6b335-3f2a-42e4-85ff-8a08fa65fceb',
expires = 1733998131,
state = 'connected'
WHERE id = 348;
# [PASSWORD_DOTS]
select * from teams where id = 31;
select * from crm_configurations where id = 18;
select * from users where team_id = 31; # 257
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 31;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 31
and sa.provider = 'close';
select * from contacts where crm_configuration_id = 18;
# [PASSWORD_DOTS] NEPTUNE [PASSWORD_DOTS]
select * from teams;
select * from users where id IN (1030, 1035, 1052);
select * from crm_configurations;
select * from users where team_id = 65; # 257
select * from team_settings where team_id = 65; # 257
select * from invitations where team_id = 65; # 257
select * from users where email = '[EMAIL]'; # 257
select u.email, cp.* from users u
join crm_profiles cp on u.id = cp.user_id
where u.team_id = 65;
select * from crm_configurations where id = 53;
select * from accounts where crm_configuration_id = 53 order by id desc;
select * from leads where crm_configuration_id = 53 order by id desc;
select * from contacts where crm_configuration_id = 53 order by id desc;
select * from opportunities where crm_configuration_id = 53 order by id desc;
select * from crm_profiles where crm_configuration_id = 53 order by id desc;
select * from crm_fields where crm_configuration_id = 53 order by id desc;
select * from crm_field_values where crm_field_id = 3341 order by id desc;
select * from crm_layouts where crm_configuration_id = 53 order by id desc;
select * from stages where crm_configuration_id = 53 order by id desc;
select * from crm_profiles where crm_configuration_id = 13;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 65
and sa.provider = 'integration-app';
select * from contacts where crm_configuration_id = 13;
select * from social_accounts where sociable_id = 283;
SELECT * FROM opportunities WHERE crm_provider_id = '006O400000E9bzeIAB';
select * from activity_providers where team_id = 65;
SELECT * FROM activities WHERE crm_configuration_id IN (51, 52, 53);
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 65
;
# [PASSWORD_DOTS] STAGING [PASSWORD_DOTS]
SELECT * FROM teams;
SELECT * FROM teams WHERE id = 88;
SELECT * FROM teams WHERE id = 89;
select * from team_settings where team_id = 89;
SELECT * FROM users WHERE team_id = 89;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 89;
select * from users;
SELECT * FROM social_accounts WHERE sociable_id = 1761;
SELECT * FROM crm_configurations WHERE id = 70;
select * from accounts where crm_configuration_id = 70 order by id desc;
select * from leads where crm_configuration_id = 70 order by id desc;
select * from contacts where crm_configuration_id = 70 order by id desc;
select * from opportunities where crm_configuration_id = 70 order by id desc;
select * from crm_profiles where crm_configuration_id = 70 order by id desc;
select * from crm_fields where crm_configuration_id = 70 order by id desc;
select * from crm_field_values where crm_field_id = 3536 order by id desc;
select * from crm_layouts where crm_configuration_id = 70 order by id desc;
select * from stages where crm_configuration_id = 70 order by id desc;
select * from business_processes where crm_configuration_id = 70 order by id desc;
select * from business_process_stages where business_process_id = 34;
select * from contacts where id = 10468;
select * from crm_layouts where crm_configuration_id = 70;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 388;
SELECT * FROM crm_fields WHERE id IN (3533,3534,3535);
select * from activities where crm_configuration_id = 70
and (account_id IS NOT NULL or lead_id IS NOT NULL or contact_id IS NOT NULL or opportunity_id IS NOT NULL) order by id desc;
SELECT * FROM activities WHERE uuid_to_bin('2e10b60f-8a61-41c5-a3d4-28835353dc65') = uuid;
SELECT * FROM activities where crm_configuration_id = 69 ;
SELECT * FROM users WHERE email LIKE '%[EMAIL]%';
SELECT * FROM activities WHERE uuid_to_bin('5a150c93-40fc-42ec-b3bd-c1d328e09f6e') = uuid;
SELECT * FROM opportunities WHERE id = 385;
select * from participants p
join activities a on p.activity_id = a.id
where a.crm_configuration_id = 70
and (p.lead_id IS NOT NULL or p.contact_id IS NOT NULL);
SELECT * FROM participants WHERE id = 1013638;
select * from teams where id = 90;
select * from users where team_id = 90;
select * from social_accounts where social_accounts.sociable_id IN (1960,1760);
SELECT * FROM crm_profiles WHERE crm_configuration_id = 71;
select * from invitations where team_id = 90;
select * from crm_configurations where id = 71;
select * from accounts where crm_configuration_id = 71 order by id desc;
select * from leads where crm_configuration_id = 71 order by id desc;
select * from contacts where crm_configuration_id = 71 order by id desc;
select * from opportunities where crm_configuration_id = 71 order by id desc;
select * from crm_profiles where crm_configuration_id = 71 order by id desc;
select * from crm_fields where crm_configuration_id = 71 order by id desc;
select * from crm_field_values where crm_field_id = 3341 order by id desc;
select * from crm_layouts where crm_configuration_id = 71 order by id desc;
select * from stages where crm_configuration_id = 71 order by id desc;
select * from users order by secondary_email desc;
select u.id, u.email, u.status, sa.id, sa.provider_user_id from social_accounts sa
join users u on sa.sociable_id = u.id
where sa.provider = 'google' and u.email LIKE 'aneliya%';
select * from failed_jobs order by id desc;
select * from users where email = '[EMAIL]' or secondary_email = '[EMAIL]';
select * from teams;
SELECT * FROM crm_profiles WHERE crm_configuration_id = 39;
SELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type = 'task';
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 1
and sa.provider = 'salesforce';
# [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('c38b3895-fd0f-4b1f-9fb2-c170dba137c6') = uuid;
SELECT * FROM crm_configurations WHERE id = 70;
select * from teams where id = 1;
select * from groups where team_id = 1;
select * from users where team_id = 1;
select o.id, o.name,o.close_date, u.id, u.name, u.group_id, r.id, r.display_name, g.name, g.scope from opportunities o
join users u on o.user_id = u.id
join groups g on u.group_id = g.id
join role_user ru on u.id = ru.user_id
join roles r on ru.role_id = r.id
where o.crm_configuration_id = 39 and close_date > '2024-01-01 00:00:00';
select * from role_user where user_id = 143;
select * from roles;
select * from role_user;
select * from groups where id = 9;
select * from scope_groups where group_id = 9;
# [PASSWORD_DOTS]
select * from teams where id = 36;
select * from crm_configurations;
SELECT * FROM social_accounts WHERE sociable_id = 121;
https://crmsandbox.zoho.com/crm/jiminnyw4/tab/Leads/4776201000005049105
https://crmsandbox.zoho.com/crm/
https://crm.zoho.com/crm/org3469620/tab/Leads/230045000229559080
https://crm.zoho.com/crm/
org3469620
SELECT * FROM activities WHERE uuid_to_bin('03382d20-c8bc-48e7-a3d4-90b52fa5ceab') = uuid;
select * from users where email LIKE "%mobile_automation_%";
select * from social_accounts where sociable_id IN (2228);
select * from crm_profiles where user_id IN (2222,2223,2226,2227);
select * from teams order by id desc;
SELECT * FROM users WHERE id = 2229;
SELECT * FROM crm_profiles WHERE user_id = 2229;
select * from opportunities where crm_configuration_id = 88;
select * from crm_fields where crm_configuration_id = 88;
select * from crm_profiles where crm_configuration_id = 88;
SELECT * FROM teams WHERE id = 1;
SELECT * FROM users WHERE id = 143;
SELECT * FROM users WHERE uuid_to_bin('fde193d3-06a2-4e1a-8895-62b94039215d') = uuid;
SELECT * FROM teams WHERE uuid_to_bin('73385071-a756-42ae-9c73-8b53f2309467') = uuid;
https://app.staging.jiminny.com/ondemand?
min_duration=1
&
only_recorded=1
&
user_id%5B%5D=641f1acb-16b8-42d1-8726-df52979dad0e
&
sequence_number=2
select * from users where team_id = 1 and email like '%stoyan%'
select * from coaching_feedbacks;
select * from teams;
SELECT * FROM users WHERE team_id = 36;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 19
and sa.provider = 'pipedrive';
select * from users where id = 143;
SELECT * FROM users WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
SELECT * FROM teams WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
SELECT * FROM activity_shares WHERE uuid_to_bin('73180eeb-33de-4065-977d-ccbe0e6c94fc') = uuid;
select * from users where team_id = 2;
select * from activities where crm_configuration_id = 39
and activities.scheduled_start_time BETWEEN '2025-04-09 00:00:00' AND '2025-04-09 23:59:59'
AND user_id = 143
order by id desc;
# [PASSWORD_DOTS]
select * from teams where id = 142; # 2312, 126
select * from team_settings;
select * from users where team_id = 142; # 21642
SELECT * FROM social_accounts WHERE sociable_id = 21642;
SELECT * FROM crm_profiles cp join users u ON u.id = cp.user_id WHERE team_id = 142;
select * from crm_profiles where id IN (93);
select * from invitations;
select * from team_features where team_id = 1;
SELECT * FROM crm_configurations WHERE id = 126;
select * from accounts where crm_configuration_id = 126 order by id desc;
select * from leads where crm_configuration_id = 126 order by id desc;
select * from contacts where crm_configuration_id = 126 order by id desc;
select * from opportunities where crm_configuration_id = 126 order by id desc;
select * from crm_profiles where crm_configuration_id = 126 order by id desc;
select * from crm_fields where crm_configuration_id = 126 # 11060
# and type IN ('picklist', 'status')
# and object_type = 'task'
order by id desc;
# 5731,5732,5733
select DISTINCT crm_field_id from crm_field_values where crm_field_id IN (11151,12239,12215,12185,12175,12165,12144,12137,12127,12109,12107,12105,12103,12092,12037,12005,12003,11987,11969,11958,11951,11942,11931,11924,11921,11917,11915,11901,11893,11883,11872,11870,11868,11866,11839,11833,11821,11793,11780,11777,11769,11757,11737,11735,11656,11645,11638,11629,11618,11611,11602,11591,11584,11581,11558,11544,11543,11534,11532,11529,11527,11503,11497,11493,11488,11470,11468,11457,11455,11397,11387,11372,11363,11348,11323,11318,11309,11301,11300,11292,11290,11286,11284,11256,11252,11242,11237,11233,11219,11176,11160) order by id desc;
select * from crm_layouts where crm_configuration_id = 126 order by id desc;
SELECT * FROM crm_layout_entities WHERE crm_layout_id in (300,299,298);
select * from stages where crm_configuration_id = 126 order by id desc;
select * from business_processes where crm_configuration_id = 126 order by id desc;
select * from business_process_stages where business_process_id IN (76,75,74,73);
select * from playbooks where team_id = 142;
select * from playbook_layouts where playbook_id IN (108);
SELECT * FROM playbook_categories WHERE playbook_id IN (108);
select * from teams where id = 130;
SELECT * FROM social_accounts WHERE sociable_id = 2291;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 2
and sa.provider = 'hubspot';
SELECT * FROM activities
WHERE crm_configuration_id = 110;
select * from teams;
select * from crm_configurations;
SELECT * FROM activities WHERE id = 628773;
SELECT * FROM crm_profiles WHERE user_id = 1460;
SELECT * FROM social_accounts WHERE sociable_id = 2291;
select * from teams;
select ru.*, pr.*, p.* from users u join role_user ru on ru.user_id = u.id
join permission_role pr on pr.role_id = ru.role_id
join permissions p on p.id = pr.permission_id
where team_id = 495 and p.name IN ('dial');
select * from teams where id = 145;
select * from crm_configurations where id = 129;
select * from social_accounts where sociable_id = 2317;
SELECT * FROM activities WHERE uuid_to_bin('8dbab184-a333-4268-ad57-fb41f8d53a9a') = uuid;
select * from teams where id = 1;
SELECT * FROM crm_layouts WHERE crm_configuration_id = 39;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 280;
SELECT * FROM crm_layout_entities WHERE id = 5507;
SELECT * FROM crm_fields WHERE crm_configuration_id = 39 and object_type IN ('event');
select * from teams;
select * from activities where crm_configuration_id = 14;
SELECT * FROM social_accounts where provider = 'copper';
select * from activities where id = 628467;
select * from participants where activity_id = 628467;
SELECT * FROM contacts WHERE id = 3969;
SELECT * FROM accounts WHERE id = 177;
SELECT * FROM activities WHERE uuid_to_bin('4eb54c77-cfa3-2bd4-84a7-9ed46a21c988') = uuid;
# [PASSWORD_DOTS] BH
select * from teams where id = 36;
SELECT * FROM crm_configurations WHERE id = 21;
select * from activities where crm_configuration_id = 21 and id = 607901;
select * from activities where crm_configuration_id = 21;
select * roles;
select * from permissions;
select * from permission_role where permission_id = 226;
select * from migrations order by id desc;
# mercury
# neptune
# earth
select * from teams;
select * from teams where id = 19;
select * from teams where id = 27;
select * from users where team_id = 27;
SELECT * FROM crm_configurations WHERE id = 42;
select * from social_accounts sa
join users u on sa.sociable_id = u.id
where u.team_id = 19
and sa.provider = 'pipedrive';
select * from activities where id = 631461;
SELECT * FROM crm_field_values WHERE crm_field_id = 180;
select * from teams where id = 2;
SELECT * FROM social_accounts WHERE sociable_id = 89;
SELECT * FROM activities WHERE uuid_to_bin('ba0c029a-bc14-4e17-8603-64174acebcbb') = uuid; # 634273
select * from activity_summary_logs where activity_id = 634273;
select * from sidekick_settings where team_id = 2;
select * from teams; # 2, 2
SELECT * FROM crm_configurations WHERE team_id = 2; # 2
select * from team_features where team_id = 2;
select * from features;
SELECT * FROM opportunities WHERE crm_configuration_id = 2 and crm_provider_id = '51317301383';
SELECT * FROM opportunities WHERE crm_configuration_id = 2 order by id desc;
select * from automated_reports order by id desc;
select * from automated_report_results order by id desc;
select * from users where team_id = 1 and id IN (7160, 3248);
select * from migrations order by id desc;
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 = 1052 and sa.provider = 'hubspot';
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 = 565;
select * from playbooks where team_id = 1;
select * from playbooks where id = 175;
select * from playbook_categories where playbook_id = 175;
select * from users where team_id = 1052;
select * from users where id = 7160;
select * from crm_profiles where user_id = 7160;
select * from features;
select
*
# id, uuid, type, provider, playbook_category_id, user_id, lead_id, contact_id, account_id, opportunity_id, stage_id,
# crm_configuration_id, crm_provider_id, transcription_id, status
from activities where crm_configuration_id = 1 and type = 'conference'
# and crm_provider_id IS NOT NULL
and provider != 'uploader' and actual_start_time IS NOT NULL
ORDER by id desc;
select * from activities where id = 54747783; # 00UO400000pCzojMAC
select p.id, p.activity_type, pc.id, pc.name
FROM playbooks p
join playbook_categories pc on p.id = pc.playbook_id
where p.team_id = 1 and p.activity_type = 'event';
SELECT * FROM crm_fields WHERE crm_configuration_id = 1 and object_type = 'event';
SELECT * FROM crm_field_values WHERE crm_field_id = 4;
select * from crm_layouts cl join playbook_layouts pl on cl.id = pl.layout_id
where crm_configuration_id = 1 and pl.playbook_id = 175;
select * from teams;
SELECT r.* FROM automated_reports r
join teams t on r.team_id = t.id
WHERE r.frequency = 'daily'
and r.status = 1
AND t.status = 'active'
AND (r.expires_at >= now() OR r.expires_at IS NULL);
select * from automated_report_results where report_id IN (18, 33);
select * from users where team_id = 1 and id = 1047;
SELECT * FROM social_accounts WHERE sociable_id = 1047;
select * from activity_searches where id = 10932;
select * from activity_search_filters where activity_search_id = 10932;
select * from automated_reports order by id desc;
select * from automated_report_results order by id desc;
select * from automated_reports where id IN (55);
select * from automated_report_results where id IN (81);
select * from users where id IN (10633, 13987, 11985);
select * from users where group_id IN (3710);
SELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;
SELECT * FROM automated_report_results WHERE uuid_to_bin('582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;
select * from teams;
select * from accounts where team_id = 1;
select * from automated_report_results where media_type = 'pdf' and status = 2;
SELECT * FROM automated_report_results WHERE uuid_to_bin('82e74956-6144-4cd1-a3d3-af985c3070a4') = uuid;
select * from teams where id = 1029;
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 = 1029 and sa.provider = 'pipedrive';
[
{
"user_id": "23460 (owner)",
"email": "[EMAIL]",
"id": 69,
"sociable_id": 23460,
"provider_user_id": "19555731",
"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,
"refresh_token_expires": null,
"provider": "pipedrive",
"state": "connected",
"auth_scope": "base,deals:full,activities:full,contacts:full,search:read",
"retry_after": null,
"created_at": "2025-04-16 08:23:28",
"updated_at": "2026-05-18 07:13:18",
"provider_user_token_encrypted": "eyJpdiI6Ik9oYzBwcTVteWN4ajBRaDdMb0FjWGc9PSIsInZhbHVlIjoiQUNMbjU5UHR2Q1RnbWRXMEU1TUx6UVpRU3gzdVc5WktmTE4rVlhXa3lRaGhyUUlZMVZRWEJuR0JaWWhZZXNPRlBuanhuYU5MVHZ5TG9NTVVjNjJSUUpZZ2VhbGYxbHg0UzJEdTVmQjNFZnJRZkMwYjd0N2RMZ05GRS9IR3c2K0NoVjBjYTA5UG12SkxHeDlDMGVNN3ptUWUzblFiTngyYzR1eUpHSEYrdEwvZm0yZklGYjBSNEtTR2ZGazhLM1hqT3lVbjFobDNPZ0d3anFlcjhKcXpERlZGOVN1YmFyNDIvM1BFRDFMYnp4WEI4TGVLM2xYcy9CL0RDOWlQNHI3N0NwWnJPMWRtZllmM2ZKeE9TV2NBeDZxL2M1YnlSVzd3ZW96T3F1QmtBYXBHYkUraGcvdCtRajlYZXBjVVBSdFlMUjVPVDVJbDdyenVoWjMrbVJvU3ZZR1dQZ3pqQ3F3aDF2U2xPZWZIN3BCWVFLNXpxQUtDb2pIK0xHc1E3SklSM3Q0VkNSbm9oK2pFK3hLaW54T1dWbEVneUp0RGhhdVBuOFI4MXROc3dZWnFnTUpiaDVMMnZ4QmlRM3k4QWFlMVFWUFYvdGhJQzZBYnhBQmhWa2ZKN1ZhSnhpaExxbmlTemgzUWw3aXJtWjlSMlhmd0lWMDNDN1N3My9Ua0hCL2xqY3RkVFhMSjFJMDRjOE5DWlgrZ3FMVXN6RWlwUE5GWERZdG1xVjVxOFlLRGs2VVJKS3FLeWRxQjYxdDh4Z2JJNXhlWEZ3dkQ4SGtybDNUcndzblFHeVJNRkYraFh2UDFIUTdMQ1BZa3dEU1dBbzk5K0dyT2RNVFBZZUJpRytSck5pYlI1YUZyMmhUNEZCdWxHYmJLREtzbUpjVkhvV0RoejJpbm1SWHlNaXE5M0RhcS94UW9EdFoweWF3bVFVY0dTZWFPSXBmOCtDYndia215cmtyZU1oT0Exam1CV2tPblNhYjY4clVEeUs3anVHUmNHeS9YLzRha1VhbGl3N3lwaDlzZnRhQUZta2s4eFllNHgzRklSRmNyazJ4dlBDMnByNCtBRjNaVjJCTT0iLCJtYWMiOiJkYTQxZDY1OTY2ZTljMTgyZWRhNGEzMGZjZDc2MjBjN2NlNzU2YTViNGQxNWE1NTI2ZmI1MWQyYjQ2ODYxZmEwIiwidGFnIjoiIn0=",
"provider_refresh_token_encrypted": "eyJpdiI6Imt2bGxlSmxUK05GMjF0dEtPaTMrUlE9PSIsInZhbHVlIjoiUXZHTElZRXkreHFxUU02SnZ4eVBacG9WWTRlVkd0USszV3JyVFlpU2ZaY25GSWo2WFcrRzNlbFRlUXRQczNwSXRCcEdvZEpveG9jMzBDSTgwdnZLQnc9PSIsIm1hYyI6ImQxYWI0NzU5Nzg5MDI4YWVhZmQ4Mjg1YzhkZDQzMjRkYWYwYTdhZTY5MDMxMjc0OWNiYjY0Nzc3NDQ0MTEyY2EiLCJ0YWciOiIifQ==",
"encryption_key": "0x01020300786192D9D96DD60D3D1EBC9DFAEE5F0C45EE80165CF3F3D2B3B627026AA7CFC7CA0128DD463535D32EE491ADBADF8B07596B0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040C7FB1319048ECB2EA3F23B995020110802B52D22F5EAD341AB238FBBCB6093156E443876A664BA5555D722565C2B2D04422C868CD7350555E3CC74221",
"sociable_type": "user",
"owner_id": 23460
},
{
"user_id": "23463",
"email": "[EMAIL]",
"id": 72,
"sociable_id": 23463,
"provider_user_id": "23270841",
"provider_user_token": "v1u:AQIBAHj-LzTNK2yuuuaLqifzhWb9crUNKTpk4FlQ9rjnXqp_6AEQhDhDQVa1nvWCHEvnpvSEAAAAfjB8BgkqhkiG9w0BBwagbzBtAgEAMGgGCSqGSIb3DQEHATAeBglghkgBZQMEAS4wEQQMnG8KNcZLIjEnlRPxAgEQgDsGPIcKjsMU7Qel36BtM5FCQa56mYUy24_AAoqd12yjVFkq6egLqS0inp-5G4JE7frJURMV8VTw_fY14g:txqCuWLeVhgwiaFqXIvQWWrtrnFIy_4lT3VCr-sRB4g6_2lK8KcQ_6ka_qFmZhr-IeIAKmAImx6H1iIKx4Ab7XZ5MnKIh03GKbHjI0n0rGT9UYkeH21jKOxJvKaSX_TyLbxFPR6irPQyvqcpBClXI52gVJH01KzZy_dMTHFXhhDLOIhEpSrQXHG7Qo8q7OuBeSPZrU1ALi9kmAm4GTpzGTbzfl-hUt9IAfPunJOCyv3mf2Tl-MT8EyQgOFPrsP3yz9UlSyVhb40zO_bCnUrqNxjwgm_E6vgpVrwULTQbHe-43Dq-TRetjceUzT88GBgVJ0UdxXP5BRBVXcL5ir8-9ZTMaNU",
"provider_refresh_token": "5034113:[TELEGRAM_TOKEN]78ad1",
"expires": 1753837219,
"refresh_token_expires": null,
"provider": "pipedrive",
"state": "full-refresh",
"auth_scope": "base,deals:full,activities:full,contacts:full,search:read",
"retry_after": null,
"created_at": "2025-04-16 10:41:12",
"updated_at": "2025-07-30 01:00:17",
"provider_user_token_encrypted": "eyJpdiI6InVEVEl2SzIxMjd1bkNDWG9lY3YvQ0E9PSIsInZhbHVlIjoiRlJLbDZ3ZHo2dHMxUWQwdGU2YUZjV3lPWHlxQTJ0eWh4S0RTMjlSaThVcktoaWhXcTd2UXl4Mjg4bW5UUnZCZEQ5NXpuQTVKOURiMDNIa3l3K0lSWCt5azRBOEdHbitWQXhxeEpMVUZ1dnF2NVl1TTZLelZOaGNvRlBLeGpIWlpoRGloUEprd2xoNUFPcTlLcUd3WVlUU2svR1NOeXBYQ2NnMWhnK1V2aytOeVVMNzJGdVZXMU1JS3BSaGNCcmxkVjEwQ01mQXNBdWNhS1lMZWZobnZwcHBkN1R4bUVDRUNYdnNtSVJkdG5MdkN3djJBT0hMRDl1MHFGbnl4WU13ejBkUWsrdUljWkZhcTJlN0JDSGdTVzlPY0FGMUJlZi9WRGpkMUk5R20wblYwSk9VR2FuaHpLTzJNeitMbnF1V1NEMUUxRmYzaDRGZDMyaXd3Z0FjQno4SzVoYjUyTmV3UXNpRlF4TGZKNVl3dUFqdGhKVWJjRVlUUXRGalBpaXJvSGJmbS8rd25aQ2Zvc05saHRDRjlHV1VEUFFiRU5xbWRVNkxFSXV0RUZyaUlYNWMwMmhnZ0Y1VUQ4eEFkY2QyWXpnR0NidkVJSWdjVGljUjA3NDdpZW9WUHhtSlpGSGdNU2hRUTA5ZW03RGpiRFdrdytkOHJXSUxlazZNaG9iaUg2NFZYdEc3YklMeFZvblBzWmVRSDcvN2M4WUNtL3h4S2IrUW00cXhialBia3BJcW5XallBNlV5WWdhcE1ZVFBBM3RSSUVBamYvOGZEQWM5a2FJMGwyWkRSU3dlTEtPemZlQ3RXRGNDcEdYRHdMNTlTQVg2SUdUN0hVaXdZT1dUOUlrVzkrZHFBemhwWXg1cm4rSy9UOHUzcnNSM2dISlhBRTEyVUNyTkZYaFJYUlN1a2RKVHhhM2dHckR3a1JGaVZ2Wk9BVnhTclVpSEhwWTVpQTlJbXVkOUxSTGpRbDk0a1VtbE9QMVAvN3VlVEhJUHd2elowd0laNVIzZ3M3N0ZOK0NDakIwQ2FicGxoMDBhTXI0VUppUmFOZHdlWUdGV21NNFQ4RU1nY0dnWT0iLCJtYWMiOiI0ZTU4ZmJkNTdkYmY0NGE4NTJjZjlhNDExNzE2YjhlOWM2NTA5OGY2MDA4OTcyZDVlOTljY2JjZDhmMjBhMDUyIiwidGFnIjoiIn0=",
"provider_refresh_token_encrypted": "eyJpdiI6IkJGMkdRVHRKM2VTcitKNGcvQWJtUGc9PSIsInZhbHVlIjoicmFyRkxPZ1Rybm1ORXlEVjJ2TXFGTzJtM3hWaFhnUVVHN2ZlR1lRM0I5d3ozbnZTcU5EdzJqRkI2elhyNWhlenRTUXV3bjk0N1JXeklDMVAyUzBKcHc9PSIsIm1hYyI6ImJhODVjMGQyZDE3Y2ExNjc2OWVjYWJiNmFjYWVkODIyMTMyNWVhYTExMTgwYTEyMTU0MzUzZGE1YjQ5YzQ5ZjEiLCJ0YWciOiIifQ==",
"encryption_key": "0x01020300788C37CDF66ABE9301A68D5D4866AC0C197E04EEE4D904F20A59991322EBAE252301BEF4B24FF01359E934E5654617E4EEAC0000006E306C06092A864886F70D010706A05F305D020100305806092A864886F70D010701301E060960864801650304012E3011040CEB00EF45BDEA999A5558889E020110802B925F372F7BEFAF0B45E48686113D1DA430ECFCC07B1F61BA6828CC44235278EDB05C486E8068D0BE737D91",
"sociable_type": "user",
"owner_id": 23460
}
]
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
53219
|
1867
|
7
|
2026-05-18T11:51:30.330815+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779105090330_m2.jpg...
|
PhpStorm
|
faVsco.js – Constants.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
PhostormVIewINavigarecodeLaravelKeractorJOOISWindo PhostormVIewINavigarecodeLaravelKeractorJOOISWindowFV faVsco.js°9 master k >ProiectC ActivityController.ongC BaseService.php© SasVisibilityControlTest.phpC) CoreUserRequest.pnpscimProvistoning.ong© CoreUser.phpC ListenersActivities> AudioC7 AutomatedReportsclass constantsAutoscoreM Crmpublic const MELlA OPERATLONS REMOVE = 'remove' ;• DealRisks/ ElasticSearchpublic const MELA,ID ='id';a GrouosD ImportMailbo)public const MELIA, PHONE NUMBERS = 'phoneNumbers';M Onnortunitiespublic const META JITLE = 'title';PlaylistsTm Teamspublic const META ROLES = 'roles':RenectTm Transcrintion-565D UsersTM Wehhook/usagespublic const META_PATH = 'path';— J00D Mailm Modolepublic const META ENTERPRISE SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:Usep': 569— 570D Notificationspublic const META DEPARTMENT = 'department':C Policiespublic const META META = 'meta':0 Repositories0 RulesC CrmReferenceTest.php0) ListenerRoleCannotHaveAdminOrManage0) SmsMessageTest.phpM ServicesE575public const MElAlYPE = "type'"public const META VALUE = 'value':public const Merhob3 edits *,X Reject File ose4 2 of 8 files →77= 578=579Local Chanaes• Changes 9 files.E env.local app@ Constants.php app/Component/SCIM→ E Side-by-side viewerAchiehfdcann/Comnonent/SCIM/ScimProvicionina.nhr(C) CoreUser.oho aoo/DTO/SCIMIAAD/Resoonse@ CoreUserRequest.ohp app/DTO/SCIMIAAD/Requestuce liminnv' Modelcl Role•(C)JiminnvDebuaCommand.oho apo/Console/Commandsuse Jiminny hodels leamuce liminnvl Modelc|llcen•pho logdina.nhn confidJiminny services userserviceCentry@) SoftPhoneManager.nhn ann/Comnonent/Twilio/Conference/ConferenceManad(C) TeytMessaainaService.nhn ann/Services/Telenhonviaace ScimProvisioningUnversioned Files 12 files= env nikilocal annl= .env.other app© CanAccessAiReportsTest.php tests/Unit/Policies(e)CrostoMockAck liminnvDonartDocultCommand.nhnann/Concolo/Commandc/ppublic function-_constructdorivate readonly Dispatcher SeventDispatcherorivate readonly UserService suserService.orivate readonly Rolechangelogger Srolechangeloggerf0 favicon ico nublidE ids.txt appListenerRoleCannotHaveAdminOrManagerPermissionRule.php app/Rules@ ListenerRoleCannotHaveAdminOrManagerPermissionRuleTest.php tests/Unit/RP row cal auory cal annnublic function vaLidatellserIdInnut(Sid. Team Steam): boo1Workcnace accociated with hranch 'macter' hac heon rectored Il Pollback II Confiaure (21 minutec aao))supoon Dally • In sm100% S2• Mon 18 May 14:51:30AskJiminnyReportActivityServiceTest v4 HS_local [jiminny@localhost]& console [PROD]# console [euyCascadeImplement Trial OwneFixing Redis Rate LimSalestorce Token FalliSCIM Role ManagemeGo jiminny_jupiterBISBIS XIA V+O •=custom.log= laravel.log4 SF jiminny@localhost]A console [STAGING] XTx: Autov556select * from teams.SELECT r.* FROM automated_reports rioin teams t on r.team id = t.idiWHERE r.frequency = 'daily'and r.status = 1AND t.status = 'activeAND (r.expires at >= now) OR r.expires at IS NULL):select * from automated_report_results where report id IN (18, 33):select * from users where team_id = 1 and id = 1047:SELECT * FROM social_accounts WHERE sociable_id = 1047;select x rron aculvity searches Where 10 = 10752select * trom activity search tilters where activity search 10 = 10952select * from automated reportsorder by 10 desc:order by 1d descselect * trom automated reports where 10 IN (557results where id IN (81):select * trom users where 1d IN 00055,15787.4785)"select * trom users where qrouo 10IN (5/0)%SELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;SELEC * FROMIWHERE uuid_to_bin( 582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;select * from teams:Current vercionuse Jiminny Models Roleuse Jiminny Models\ Team:use Jiminny Models\User:use Jiminny\Services\UserService:use Jiminny\Contracts\Acl\RoleRepositoryInterface:use Iuluminare support racades vauldacoruse Jiminny Rules DependentRolesRule:use Jaminny Rules ListenerRolecannotHaveAdmin0rManagerPermissionrule:use Jiminny Rules\ListenerRoleRequiresListenerFeatureRule:use Jaminny Actions UodateUserRolesactioniuse Jiminny\DTO\Roles UserRolesSvncDTO:use Sentryclass ScimProvisioninolnublic function constructd• Write unit tests for SCIM role management10 Contact Mario to update customel10 70 tasks doneThought for 1s›SCIM role management for Teamtailor has been successfuliv imolemented. Here's what was comoleted;1. CoreUserRequest DTO - Added role parsing from SCIM requests2. SCIM Constants - Added META ROLES and USER PATCH ATTR ROLES constants3. RoleAttr Mutator - Created mutator for handling role assignments via SCIM PATCH operations4. ScimProvisioning - Updated to handle roles during user creation with proper validation5. ListenerRoleCannotHaveAdminOrManaderPermiscionPule - Created validation rule to nrevent listener role from6. CoreUser Response - Updated to include roles in SCIM responses7. Unit Tests - Created comprehensive tests for the validation ruleKev Features.R fles +726-16>Reject allAccept allAsk anvthina (%4L)+ •code SWE-1.64 ditterencesW Windsurf Teams48-1UITE.8Iio 4 spaces...
|
NULL
|
2842536269687807652
|
NULL
|
visual_change
|
ocr
|
NULL
|
PhostormVIewINavigarecodeLaravelKeractorJOOISWindo PhostormVIewINavigarecodeLaravelKeractorJOOISWindowFV faVsco.js°9 master k >ProiectC ActivityController.ongC BaseService.php© SasVisibilityControlTest.phpC) CoreUserRequest.pnpscimProvistoning.ong© CoreUser.phpC ListenersActivities> AudioC7 AutomatedReportsclass constantsAutoscoreM Crmpublic const MELlA OPERATLONS REMOVE = 'remove' ;• DealRisks/ ElasticSearchpublic const MELA,ID ='id';a GrouosD ImportMailbo)public const MELIA, PHONE NUMBERS = 'phoneNumbers';M Onnortunitiespublic const META JITLE = 'title';PlaylistsTm Teamspublic const META ROLES = 'roles':RenectTm Transcrintion-565D UsersTM Wehhook/usagespublic const META_PATH = 'path';— J00D Mailm Modolepublic const META ENTERPRISE SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:Usep': 569— 570D Notificationspublic const META DEPARTMENT = 'department':C Policiespublic const META META = 'meta':0 Repositories0 RulesC CrmReferenceTest.php0) ListenerRoleCannotHaveAdminOrManage0) SmsMessageTest.phpM ServicesE575public const MElAlYPE = "type'"public const META VALUE = 'value':public const Merhob3 edits *,X Reject File ose4 2 of 8 files →77= 578=579Local Chanaes• Changes 9 files.E env.local app@ Constants.php app/Component/SCIM→ E Side-by-side viewerAchiehfdcann/Comnonent/SCIM/ScimProvicionina.nhr(C) CoreUser.oho aoo/DTO/SCIMIAAD/Resoonse@ CoreUserRequest.ohp app/DTO/SCIMIAAD/Requestuce liminnv' Modelcl Role•(C)JiminnvDebuaCommand.oho apo/Console/Commandsuse Jiminny hodels leamuce liminnvl Modelc|llcen•pho logdina.nhn confidJiminny services userserviceCentry@) SoftPhoneManager.nhn ann/Comnonent/Twilio/Conference/ConferenceManad(C) TeytMessaainaService.nhn ann/Services/Telenhonviaace ScimProvisioningUnversioned Files 12 files= env nikilocal annl= .env.other app© CanAccessAiReportsTest.php tests/Unit/Policies(e)CrostoMockAck liminnvDonartDocultCommand.nhnann/Concolo/Commandc/ppublic function-_constructdorivate readonly Dispatcher SeventDispatcherorivate readonly UserService suserService.orivate readonly Rolechangelogger Srolechangeloggerf0 favicon ico nublidE ids.txt appListenerRoleCannotHaveAdminOrManagerPermissionRule.php app/Rules@ ListenerRoleCannotHaveAdminOrManagerPermissionRuleTest.php tests/Unit/RP row cal auory cal annnublic function vaLidatellserIdInnut(Sid. Team Steam): boo1Workcnace accociated with hranch 'macter' hac heon rectored Il Pollback II Confiaure (21 minutec aao))supoon Dally • In sm100% S2• Mon 18 May 14:51:30AskJiminnyReportActivityServiceTest v4 HS_local [jiminny@localhost]& console [PROD]# console [euyCascadeImplement Trial OwneFixing Redis Rate LimSalestorce Token FalliSCIM Role ManagemeGo jiminny_jupiterBISBIS XIA V+O •=custom.log= laravel.log4 SF jiminny@localhost]A console [STAGING] XTx: Autov556select * from teams.SELECT r.* FROM automated_reports rioin teams t on r.team id = t.idiWHERE r.frequency = 'daily'and r.status = 1AND t.status = 'activeAND (r.expires at >= now) OR r.expires at IS NULL):select * from automated_report_results where report id IN (18, 33):select * from users where team_id = 1 and id = 1047:SELECT * FROM social_accounts WHERE sociable_id = 1047;select x rron aculvity searches Where 10 = 10752select * trom activity search tilters where activity search 10 = 10952select * from automated reportsorder by 10 desc:order by 1d descselect * trom automated reports where 10 IN (557results where id IN (81):select * trom users where 1d IN 00055,15787.4785)"select * trom users where qrouo 10IN (5/0)%SELECT * FROM automated_reports WHERE uuid_to_bin('18a06a75-afd2-476f-aadc-14d4057bdda2') = uuid;SELEC * FROMIWHERE uuid_to_bin( 582d4b50-8cd3-42a9-9819-d676ff8f3b43') = uuid;select * from teams:Current vercionuse Jiminny Models Roleuse Jiminny Models\ Team:use Jiminny Models\User:use Jiminny\Services\UserService:use Jiminny\Contracts\Acl\RoleRepositoryInterface:use Iuluminare support racades vauldacoruse Jiminny Rules DependentRolesRule:use Jaminny Rules ListenerRolecannotHaveAdmin0rManagerPermissionrule:use Jiminny Rules\ListenerRoleRequiresListenerFeatureRule:use Jaminny Actions UodateUserRolesactioniuse Jiminny\DTO\Roles UserRolesSvncDTO:use Sentryclass ScimProvisioninolnublic function constructd• Write unit tests for SCIM role management10 Contact Mario to update customel10 70 tasks doneThought for 1s›SCIM role management for Teamtailor has been successfuliv imolemented. Here's what was comoleted;1. CoreUserRequest DTO - Added role parsing from SCIM requests2. SCIM Constants - Added META ROLES and USER PATCH ATTR ROLES constants3. RoleAttr Mutator - Created mutator for handling role assignments via SCIM PATCH operations4. ScimProvisioning - Updated to handle roles during user creation with proper validation5. ListenerRoleCannotHaveAdminOrManaderPermiscionPule - Created validation rule to nrevent listener role from6. CoreUser Response - Updated to include roles in SCIM responses7. Unit Tests - Created comprehensive tests for the validation ruleKev Features.R fles +726-16>Reject allAccept allAsk anvthina (%4L)+ •code SWE-1.64 ditterencesW Windsurf Teams48-1UITE.8Iio 4 spaces...
|
53217
|
NULL
|
NULL
|
NULL
|
|
53218
|
1866
|
9
|
2026-05-18T11:51:28.570420+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779105088570_m1.jpg...
|
PhpStorm
|
faVsco.js – Constants.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpEUDOCKER881DEV SlackFileEditViewGoHistoryWindowHelpEUDOCKER881DEV (docker)782XI"@timestamp":"2026-05-18T11:51:20Z"sticsearch": "No livingconnections"}"tags" : ["warning"{"type" : "log""@timestamp": "2026-05-18T11:51:20Z","taskManager""taskManager"], "pid" :7,"message": "Failed"tags" : ["error"for work: Error: No Liconnections"}"@timestamp": "2026-05-18T11:51:21Z""tags": ["error""pid":7, "message" : "[ConnectionError]:getaddrinfo ENOTFOUND elasticsearelasticsearch:9200"}docker_lamp_12026-05-18 11:51:17 Running ['artisan'mailbox:skip-lists:refresh]. 4S DONEdocker_lamp_11 '/usr/local/bin/php' 'artisan' mailbox:skip-lists:refresh › */proc/1/fd/1'2>&1kibana1 {"type": "log", "@timestamp" : "2026-05-18T11:51:23Z", "tags" : ["warning","elasticsearch", "data"], "pid" :7,"message" : "Unable torevive connection: [URL_WITH_CREDENTIALS] "2026-05-18T11:51:23Z","tags" : ["warning","elasticsearch", "data"], "pid" :7,"message": "No livingconnections"}kibana1 {"type": "log""@timestamp": "2026-05-18T11:51:23Z", "tags" : ["error"ns","taskManager""taskManager"], "pid" :7, "message" : "Failed,"plugito poll for work: Error: No Livingconnections"}kibana1 {"type" : "log""@timestamp" : "2026-05-18T11:51:23Z""tags" : ["error","elasticsearch".,"data"], "pid" :7, "message" : "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type" : "log","@timestamp": "2026-05-18T11:51:23Z","tags" : ["error","elasticsearch", "data"], "pid" :7,"message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}docker_lamp_12026-05-18 11:51:21 Running ['artisan' mailbox:batch:process --max-batches=15]4s DONEdocker_lamp_11 '/usr/local/bin/php' 'artisan'mailbox:batch:process --max-batches=15 > */proc/1/fd/1' 2>&1kibanaI {"type" : "log", "@timestamp" : "2026-05-18T11:51:26Z""tags" : ["warning", "elasticsearch", "data"], "pid":7, "message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T11:51:26Z" , "tags" : ["warning", "elasticsearch", "data"],"pid":7, "message": "No livingconnections"}kibana1 {"type" : "log"!"@timestamp":"2026-05-18T11:51:26Z", "tags" : ["error"ns", "taskManager"vingconnections"}"taskManager"], "pid" :7, "message" : "Failed to poll for work: Error: No Likibana1 {"type": "log", "@timestamp": "2026-05-18T11:51:27Z", "tags" : ["error","elasticsearch", "data"], "pid" :7,"message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearchelasticsearch:9200"}View in Docker Desktop• View ConfigEnable WatchHomeDMsActivityFilesLaterMore-Jiminny ...Metrotrtencee# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...0 Direct messagesNikolay YankovR. Aneliya Angelovaão Stefka Stoyanova. Stoyan Tomov€. Vasil VasilevGalya DimitrovaLe Todor Stamatov "N. Mario GeorgievNikolay IvanovLo James Graham *2 Stoyan Tanev&. Steliyan Georgiev&e Petko KashinskiE. Lukas Kovalik y...AppsJira CloudToastSupport Daily • in 9m100% <78•Mon 18 May 14:51:28Describe what you are looking forNikolay Yankov6 0•Messagest Add canvasO Files+Todayне ме пускаNikolay Yankov 2:17 PMЕй сегаГОТОВОLukas Kovalik 2:26 PMоще ведньж и в СФNikolay Yankov 2:27 PMГТОТОвОLukas Kovalik 2:27 PMработи вечеNikolay Yankov 2:27 PMимаше ли нещо за фиксLukas Kovalik 2:28 PMтрябва да си вързан към SF да работиNikolay Yankov 2:28 PMaxaaaNikolay Yankov 2:41 PMимаме approve на PRда го даваме за QА?Lukas Kovalik 2:42 PMдаMessage Nikolay Yankov...
|
NULL
|
-8921439238283199288
|
NULL
|
visual_change
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpEUDOCKER881DEV SlackFileEditViewGoHistoryWindowHelpEUDOCKER881DEV (docker)782XI"@timestamp":"2026-05-18T11:51:20Z"sticsearch": "No livingconnections"}"tags" : ["warning"{"type" : "log""@timestamp": "2026-05-18T11:51:20Z","taskManager""taskManager"], "pid" :7,"message": "Failed"tags" : ["error"for work: Error: No Liconnections"}"@timestamp": "2026-05-18T11:51:21Z""tags": ["error""pid":7, "message" : "[ConnectionError]:getaddrinfo ENOTFOUND elasticsearelasticsearch:9200"}docker_lamp_12026-05-18 11:51:17 Running ['artisan'mailbox:skip-lists:refresh]. 4S DONEdocker_lamp_11 '/usr/local/bin/php' 'artisan' mailbox:skip-lists:refresh › */proc/1/fd/1'2>&1kibana1 {"type": "log", "@timestamp" : "2026-05-18T11:51:23Z", "tags" : ["warning","elasticsearch", "data"], "pid" :7,"message" : "Unable torevive connection: [URL_WITH_CREDENTIALS] "2026-05-18T11:51:23Z","tags" : ["warning","elasticsearch", "data"], "pid" :7,"message": "No livingconnections"}kibana1 {"type": "log""@timestamp": "2026-05-18T11:51:23Z", "tags" : ["error"ns","taskManager""taskManager"], "pid" :7, "message" : "Failed,"plugito poll for work: Error: No Livingconnections"}kibana1 {"type" : "log""@timestamp" : "2026-05-18T11:51:23Z""tags" : ["error","elasticsearch".,"data"], "pid" :7, "message" : "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}kibana1 {"type" : "log","@timestamp": "2026-05-18T11:51:23Z","tags" : ["error","elasticsearch", "data"], "pid" :7,"message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}docker_lamp_12026-05-18 11:51:21 Running ['artisan' mailbox:batch:process --max-batches=15]4s DONEdocker_lamp_11 '/usr/local/bin/php' 'artisan'mailbox:batch:process --max-batches=15 > */proc/1/fd/1' 2>&1kibanaI {"type" : "log", "@timestamp" : "2026-05-18T11:51:26Z""tags" : ["warning", "elasticsearch", "data"], "pid":7, "message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T11:51:26Z" , "tags" : ["warning", "elasticsearch", "data"],"pid":7, "message": "No livingconnections"}kibana1 {"type" : "log"!"@timestamp":"2026-05-18T11:51:26Z", "tags" : ["error"ns", "taskManager"vingconnections"}"taskManager"], "pid" :7, "message" : "Failed to poll for work: Error: No Likibana1 {"type": "log", "@timestamp": "2026-05-18T11:51:27Z", "tags" : ["error","elasticsearch", "data"], "pid" :7,"message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearchelasticsearch:9200"}View in Docker Desktop• View ConfigEnable WatchHomeDMsActivityFilesLaterMore-Jiminny ...Metrotrtencee# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...0 Direct messagesNikolay YankovR. Aneliya Angelovaão Stefka Stoyanova. Stoyan Tomov€. Vasil VasilevGalya DimitrovaLe Todor Stamatov "N. Mario GeorgievNikolay IvanovLo James Graham *2 Stoyan Tanev&. Steliyan Georgiev&e Petko KashinskiE. Lukas Kovalik y...AppsJira CloudToastSupport Daily • in 9m100% <78•Mon 18 May 14:51:28Describe what you are looking forNikolay Yankov6 0•Messagest Add canvasO Files+Todayне ме пускаNikolay Yankov 2:17 PMЕй сегаГОТОВОLukas Kovalik 2:26 PMоще ведньж и в СФNikolay Yankov 2:27 PMГТОТОвОLukas Kovalik 2:27 PMработи вечеNikolay Yankov 2:27 PMимаше ли нещо за фиксLukas Kovalik 2:28 PMтрябва да си вързан към SF да работиNikolay Yankov 2:28 PMaxaaaNikolay Yankov 2:41 PMимаме approve на PRда го даваме за QА?Lukas Kovalik 2:42 PMдаMessage Nikolay Yankov...
|
53216
|
NULL
|
NULL
|
NULL
|
|
53090
|
1861
|
4
|
2026-05-18T11:35:36.955521+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779104136955_m2.jpg...
|
PhpStorm
|
faVsco.js – Constants.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
namespace Jiminny\Component\SCIM;
use Jiminny\Component\SCIM\Builders\Filters;
class Constants
{
/**
* HTTP codes
*/
public const HTTP_OK = 200;
public const HTTP_CREATED = 201;
public const HTTP_NO_CONTENT = 204;
public const HTTP_NOT_FOUND = 404;
public const HTTP_BAD_REQUEST = 400;
public const HTTP_ACCESS_DENIED = 403;
public const HTTP_ERROR = 501;
/**
* Users resource constants
*/
public const USER_FIRST_NAME = 'givenName';
public const USER_FAMILY_NAME = 'familyName';
public const USER_STATUS = 'Active';
public const USER_USERNAME = 'UserName';
public const USER_EXTERNAL_ID = 'externalId';
public const USER_FIELDS = [
self::USER_FIRST_NAME,
self::USER_FAMILY_NAME,
self::USER_STATUS,
self::USER_USERNAME,
];
public const META_OPERATIONS_REPLACE = 'replace';
public const META_OPERATIONS_REPLACE_UPPER = 'Replace';
public const META_OPERATIONS_ADD = 'add';
public const META_OPERATIONS_ADD_UPPER = 'Add';
public const META_OPERATIONS_REMOVE_UPPER = 'Remove';
public const META_OPERATIONS_REMOVE = 'remove';
public const META_ID = 'id';
public const META_PHONE_NUMBERS = 'phoneNumbers';
public const META_TITLE = 'title';
public const META_ROLES = 'roles';
public const META_PATH = 'path';
public const META_ENTERPRISE_SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';
public const META_DEPARTMENT = 'department';
public const META_META = 'meta';
public const META_TYPE = 'type';
public const META_VALUE = 'value';
public const META_OPERATIONS = 'Operations';
public const META_OP = 'op';
public const META_RESOURCE_TYPE = 'resourceType';
public const META_CREATED = 'created';
public const META_LAST_MODIFIED = 'lastModified';
public const META_FORMATTED = 'formatted';
public const META_EMAILS = 'emails';
public const META_USERNAME = 'userName';
public const META_NAME = 'name';
public const META_STATUS = 'active';
public const META_PRIMARY = 'primary';
public const META_ERROR_STATUS = 'status';
public const META_ERROR_DETAIL = 'detail';
public const META_LIST_TOTAL_RESULTS = 'totalResults';
public const META_LIST_RESOURCES = 'Resources';
public const META_LIST_START_INDEX = 'startIndex';
public const META_LIST_COUNT = 'count';
public const META_LIST_ITEMS_PER_PAGE = 'itemsPerPage';
public const META_SCHEMAS = 'schemas';
public const META_FILTER = 'filter';
public const META_TYPE_WORK = 'work';
public const META_PHONE_NUMBER_TYPE_MOBILE = 'mobile';
public const META_EMAIL_TYPE_HOME = 'home';
public const META_CONTAINER_NAME = 'name';
public const META_CONTAINER_EMAILS = 'emails';
public const RESOURCE_TYPE_USER = 'User';
public const USER_PATCH_ATTR_TITLE = 'title';
public const USER_PATCH_ATTR_ACTIVE = 'active';
public const USER_PATCH_ATTR_USERNAME = 'userName';
public const USER_PATCH_ATTR_FIRST_NAME = 'name.givenName';
public const USER_PATCH_ATTR_LAST_NAME = 'name.familyName';
public const USER_PATCH_ATTR_PRIMARY_EMAIL = 'emails[type eq "work"].value';
public const USER_PATCH_ATTR_SECONDARY_EMAIL = 'emails[type eq "home"].value';
public const USER_PATCH_ATTR_PHONE_NUMBER = 'phoneNumbers[type eq "work"].value';
public const USER_PATCH_ATTR_PHONE_NUMBER_MOBILE = 'phoneNumbers[type eq "mobile"].value';
public const USER_PATCH_ATTR_ROLES = 'roles';
public const USER_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [
self::USER_PATCH_ATTR_TITLE => Mutators\Attributes\User\TitleAttr::class,
self::USER_PATCH_ATTR_ACTIVE => Mutators\Attributes\User\ActiveAttr::class,
self::USER_PATCH_ATTR_USERNAME => Mutators\Attributes\User\UsernameAttr::class,
self::USER_PATCH_ATTR_FIRST_NAME => Mutators\Attributes\User\FirstNameAttr::class,
self::USER_PATCH_ATTR_LAST_NAME => Mutators\Attributes\User\LastNameAttr::class,
self::USER_PATCH_ATTR_PRIMARY_EMAIL => Mutators\Attributes\User\PrimaryEmailAttr::class,
self::USER_PATCH_ATTR_SECONDARY_EMAIL => Mutators\Attributes\User\SecondaryEmailAttr::class,
self::USER_PATCH_ATTR_PHONE_NUMBER => Mutators\Attributes\User\PhoneNumberPrimaryAttr::class,
self::USER_PATCH_ATTR_PHONE_NUMBER_MOBILE => Mutators\Attributes\User\PhoneNumberSecondaryAttr::class,
];
public const FILTER_OPERATOR_EQ = 'eq';
public const SUPPORTED_FILTERS_OPERATORS = [
self::FILTER_OPERATOR_EQ,
];
public const USER_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [
self::USER_FILTER_LOCAL_ID => Filters\User\LocalIdFilter::class,
self::USER_FILTER_USERNAME => Filters\User\UserNameFilter::class,
self::USER_FILTER_FIRST_NAME => Filters\User\FirstNameFilter::class,
self::USER_FILTER_LAST_NAME => Filters\User\LastNameFilter::class,
self::USER_FILTER_EXTERNAL_ID => Filters\User\ExternalIdFilter::class,
self::USER_FILTER_DISPLAY_NAME => Filters\User\DisplayNameFilter::class,
];
public const USER_FILTER_LOCAL_ID = 'id';
public const USER_FILTER_USERNAME = 'userName';
public const USER_FILTER_FIRST_NAME = 'givenName';
public const USER_FILTER_LAST_NAME = 'familyName';
public const USER_FILTER_EXTERNAL_ID = 'externalId';
public const USER_FILTER_DISPLAY_NAME = 'DisplayName';
public const SCIM_SUPPORTED_RESOURCES = [
self::USER_RESOURCE_PREFIX,
self::GROUP_RESOURCE_PREFIX,
];
public const USER_RESOURCE_PREFIX = 'Users';
public const GROUP_RESOURCE_PREFIX = 'Groups';
public const OUTGOING_SCHEMAS_SUPPORTED = [
self::OUTGOING_CORE_USER,
];
/**
* Outgoing supported schemas
*/
public const OUTGOING_CORE_USER = 'urn:ietf:params:scim:schemas:core:2.0:User';
public const OUTGOING_ERROR = 'urn:ietf:params:scim:api:messages:2.0:Error';
public const OUTGOING_LIST_RESPONSE = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';
public const OUTGOING_CORE_GROUP = 'urn:ietf:params:scim:schemas:core:2.0:Group';
/**
* Groups resource constants
*/
public const GROUP_ATTRIBUTE_DISPLAY_NAME = 'displayName';
public const GROUP_ATTRIBUTE_EXTERNAL_ID = 'externalId';
public const GROUP_ATTRIBUTE_ID = 'id';
public const RESOURCE_TYPE_GROUP = 'Group';
public const GROUP_FILTER_QUERY_NAME = 'filter';
public const GROUP_EXCLUDED_ATTRIBUTES = 'excludedAttributes';
public const GROUP_SUPPORTED_FILTER_ATTRIBUTES = [
self::GROUP_ATTRIBUTE_DISPLAY_NAME,
];
public const GROUP_MEMBERS = 'members';
public const SUPPORTED_PATCH_OPERATIONS = [
self::META_OPERATIONS_ADD,
self::META_OPERATIONS_REPLACE,
self::META_OPERATIONS_REMOVE,
];
public const GROUP_PATCH_ATTRIBUTE_MEMBERS = 'members';
public const GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME = 'displayName';
public const GROUP_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [
self::GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME => Mutators\Attributes\Group\DisplayNameAttr::class,
self::GROUP_PATCH_ATTRIBUTE_MEMBERS => Mutators\Attributes\Group\MembersAttr::class,
];
public const GROUP_FILTER_DISPLAY_NAME = 'displayname';
public const GROUP_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [
self::GROUP_FILTER_DISPLAY_NAME => Filters\Group\DisplayNameFilter::class,
];
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results...
|
[{"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":"master, menu","depth":5,"bounds":{"left":0.064494684,"top":0.019952115,"width":0.040226065,"height":0.025538707},"on_screen":true,"help_text":"Git Branch: master<br/>114 incoming commits<br/>","role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Start Listening for PHP Debug Connections","depth":5,"bounds":{"left":0.8081782,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"AskJiminnyReportActivityServiceTest","depth":6,"bounds":{"left":0.8234708,"top":0.019952115,"width":0.09208777,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9155585,"top":0.019952115,"width":0.011303191,"height":0.025538707},"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'AskJiminnyReportActivityServiceTest'","depth":6,"bounds":{"left":0.9268617,"top":0.019952115,"width":0.011303191,"height":0.025538707},"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":"AXTextArea","text":"<?php\n\nnamespace Jiminny\\Component\\SCIM;\n\nuse Jiminny\\Component\\SCIM\\Builders\\Filters;\n\nclass Constants\n{\n /**\n * HTTP codes\n */\n public const HTTP_OK = 200;\n public const HTTP_CREATED = 201;\n public const HTTP_NO_CONTENT = 204;\n\n public const HTTP_NOT_FOUND = 404;\n public const HTTP_BAD_REQUEST = 400;\n public const HTTP_ACCESS_DENIED = 403;\n\n public const HTTP_ERROR = 501;\n\n /**\n * Users resource constants\n */\n public const USER_FIRST_NAME = 'givenName';\n public const USER_FAMILY_NAME = 'familyName';\n public const USER_STATUS = 'Active';\n public const USER_USERNAME = 'UserName';\n public const USER_EXTERNAL_ID = 'externalId';\n\n public const USER_FIELDS = [\n self::USER_FIRST_NAME,\n self::USER_FAMILY_NAME,\n self::USER_STATUS,\n self::USER_USERNAME,\n ];\n\n public const META_OPERATIONS_REPLACE = 'replace';\n public const META_OPERATIONS_REPLACE_UPPER = 'Replace';\n public const META_OPERATIONS_ADD = 'add';\n public const META_OPERATIONS_ADD_UPPER = 'Add';\n public const META_OPERATIONS_REMOVE_UPPER = 'Remove';\n public const META_OPERATIONS_REMOVE = 'remove';\n\n public const META_ID = 'id';\n public const META_PHONE_NUMBERS = 'phoneNumbers';\n public const META_TITLE = 'title';\n public const META_ROLES = 'roles';\n public const META_PATH = 'path';\n public const META_ENTERPRISE_SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';\n public const META_DEPARTMENT = 'department';\n public const META_META = 'meta';\n public const META_TYPE = 'type';\n public const META_VALUE = 'value';\n public const META_OPERATIONS = 'Operations';\n public const META_OP = 'op';\n public const META_RESOURCE_TYPE = 'resourceType';\n public const META_CREATED = 'created';\n public const META_LAST_MODIFIED = 'lastModified';\n public const META_FORMATTED = 'formatted';\n public const META_EMAILS = 'emails';\n public const META_USERNAME = 'userName';\n public const META_NAME = 'name';\n public const META_STATUS = 'active';\n public const META_PRIMARY = 'primary';\n public const META_ERROR_STATUS = 'status';\n public const META_ERROR_DETAIL = 'detail';\n public const META_LIST_TOTAL_RESULTS = 'totalResults';\n public const META_LIST_RESOURCES = 'Resources';\n public const META_LIST_START_INDEX = 'startIndex';\n public const META_LIST_COUNT = 'count';\n public const META_LIST_ITEMS_PER_PAGE = 'itemsPerPage';\n public const META_SCHEMAS = 'schemas';\n public const META_FILTER = 'filter';\n public const META_TYPE_WORK = 'work';\n public const META_PHONE_NUMBER_TYPE_MOBILE = 'mobile';\n public const META_EMAIL_TYPE_HOME = 'home';\n public const META_CONTAINER_NAME = 'name';\n public const META_CONTAINER_EMAILS = 'emails';\n\n public const RESOURCE_TYPE_USER = 'User';\n\n public const USER_PATCH_ATTR_TITLE = 'title';\n public const USER_PATCH_ATTR_ACTIVE = 'active';\n public const USER_PATCH_ATTR_USERNAME = 'userName';\n public const USER_PATCH_ATTR_FIRST_NAME = 'name.givenName';\n public const USER_PATCH_ATTR_LAST_NAME = 'name.familyName';\n public const USER_PATCH_ATTR_PRIMARY_EMAIL = 'emails[type eq \"work\"].value';\n public const USER_PATCH_ATTR_SECONDARY_EMAIL = 'emails[type eq \"home\"].value';\n public const USER_PATCH_ATTR_PHONE_NUMBER = 'phoneNumbers[type eq \"work\"].value';\n public const USER_PATCH_ATTR_PHONE_NUMBER_MOBILE = 'phoneNumbers[type eq \"mobile\"].value';\n public const USER_PATCH_ATTR_ROLES = 'roles';\n\n public const USER_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [\n self::USER_PATCH_ATTR_TITLE => Mutators\\Attributes\\User\\TitleAttr::class,\n self::USER_PATCH_ATTR_ACTIVE => Mutators\\Attributes\\User\\ActiveAttr::class,\n self::USER_PATCH_ATTR_USERNAME => Mutators\\Attributes\\User\\UsernameAttr::class,\n self::USER_PATCH_ATTR_FIRST_NAME => Mutators\\Attributes\\User\\FirstNameAttr::class,\n self::USER_PATCH_ATTR_LAST_NAME => Mutators\\Attributes\\User\\LastNameAttr::class,\n self::USER_PATCH_ATTR_PRIMARY_EMAIL => Mutators\\Attributes\\User\\PrimaryEmailAttr::class,\n self::USER_PATCH_ATTR_SECONDARY_EMAIL => Mutators\\Attributes\\User\\SecondaryEmailAttr::class,\n self::USER_PATCH_ATTR_PHONE_NUMBER => Mutators\\Attributes\\User\\PhoneNumberPrimaryAttr::class,\n self::USER_PATCH_ATTR_PHONE_NUMBER_MOBILE => Mutators\\Attributes\\User\\PhoneNumberSecondaryAttr::class,\n ];\n\n public const FILTER_OPERATOR_EQ = 'eq';\n\n public const SUPPORTED_FILTERS_OPERATORS = [\n self::FILTER_OPERATOR_EQ,\n ];\n\n public const USER_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [\n self::USER_FILTER_LOCAL_ID => Filters\\User\\LocalIdFilter::class,\n self::USER_FILTER_USERNAME => Filters\\User\\UserNameFilter::class,\n self::USER_FILTER_FIRST_NAME => Filters\\User\\FirstNameFilter::class,\n self::USER_FILTER_LAST_NAME => Filters\\User\\LastNameFilter::class,\n self::USER_FILTER_EXTERNAL_ID => Filters\\User\\ExternalIdFilter::class,\n self::USER_FILTER_DISPLAY_NAME => Filters\\User\\DisplayNameFilter::class,\n ];\n\n public const USER_FILTER_LOCAL_ID = 'id';\n public const USER_FILTER_USERNAME = 'userName';\n public const USER_FILTER_FIRST_NAME = 'givenName';\n public const USER_FILTER_LAST_NAME = 'familyName';\n public const USER_FILTER_EXTERNAL_ID = 'externalId';\n public const USER_FILTER_DISPLAY_NAME = 'DisplayName';\n\n public const SCIM_SUPPORTED_RESOURCES = [\n self::USER_RESOURCE_PREFIX,\n self::GROUP_RESOURCE_PREFIX,\n ];\n\n public const USER_RESOURCE_PREFIX = 'Users';\n public const GROUP_RESOURCE_PREFIX = 'Groups';\n\n public const OUTGOING_SCHEMAS_SUPPORTED = [\n self::OUTGOING_CORE_USER,\n\n ];\n\n /**\n * Outgoing supported schemas\n */\n public const OUTGOING_CORE_USER = 'urn:ietf:params:scim:schemas:core:2.0:User';\n public const OUTGOING_ERROR = 'urn:ietf:params:scim:api:messages:2.0:Error';\n public const OUTGOING_LIST_RESPONSE = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';\n\n public const OUTGOING_CORE_GROUP = 'urn:ietf:params:scim:schemas:core:2.0:Group';\n\n /**\n * Groups resource constants\n */\n public const GROUP_ATTRIBUTE_DISPLAY_NAME = 'displayName';\n public const GROUP_ATTRIBUTE_EXTERNAL_ID = 'externalId';\n public const GROUP_ATTRIBUTE_ID = 'id';\n public const RESOURCE_TYPE_GROUP = 'Group';\n public const GROUP_FILTER_QUERY_NAME = 'filter';\n public const GROUP_EXCLUDED_ATTRIBUTES = 'excludedAttributes';\n\n public const GROUP_SUPPORTED_FILTER_ATTRIBUTES = [\n self::GROUP_ATTRIBUTE_DISPLAY_NAME,\n ];\n\n public const GROUP_MEMBERS = 'members';\n\n public const SUPPORTED_PATCH_OPERATIONS = [\n self::META_OPERATIONS_ADD,\n self::META_OPERATIONS_REPLACE,\n self::META_OPERATIONS_REMOVE,\n ];\n\n public const GROUP_PATCH_ATTRIBUTE_MEMBERS = 'members';\n public const GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME = 'displayName';\n\n public const GROUP_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [\n self::GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME => Mutators\\Attributes\\Group\\DisplayNameAttr::class,\n self::GROUP_PATCH_ATTRIBUTE_MEMBERS => Mutators\\Attributes\\Group\\MembersAttr::class,\n ];\n\n public const GROUP_FILTER_DISPLAY_NAME = 'displayname';\n\n public const GROUP_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [\n self::GROUP_FILTER_DISPLAY_NAME => Filters\\Group\\DisplayNameFilter::class,\n ];\n}","depth":4,"on_screen":true,"value":"<?php\n\nnamespace Jiminny\\Component\\SCIM;\n\nuse Jiminny\\Component\\SCIM\\Builders\\Filters;\n\nclass Constants\n{\n /**\n * HTTP codes\n */\n public const HTTP_OK = 200;\n public const HTTP_CREATED = 201;\n public const HTTP_NO_CONTENT = 204;\n\n public const HTTP_NOT_FOUND = 404;\n public const HTTP_BAD_REQUEST = 400;\n public const HTTP_ACCESS_DENIED = 403;\n\n public const HTTP_ERROR = 501;\n\n /**\n * Users resource constants\n */\n public const USER_FIRST_NAME = 'givenName';\n public const USER_FAMILY_NAME = 'familyName';\n public const USER_STATUS = 'Active';\n public const USER_USERNAME = 'UserName';\n public const USER_EXTERNAL_ID = 'externalId';\n\n public const USER_FIELDS = [\n self::USER_FIRST_NAME,\n self::USER_FAMILY_NAME,\n self::USER_STATUS,\n self::USER_USERNAME,\n ];\n\n public const META_OPERATIONS_REPLACE = 'replace';\n public const META_OPERATIONS_REPLACE_UPPER = 'Replace';\n public const META_OPERATIONS_ADD = 'add';\n public const META_OPERATIONS_ADD_UPPER = 'Add';\n public const META_OPERATIONS_REMOVE_UPPER = 'Remove';\n public const META_OPERATIONS_REMOVE = 'remove';\n\n public const META_ID = 'id';\n public const META_PHONE_NUMBERS = 'phoneNumbers';\n public const META_TITLE = 'title';\n public const META_ROLES = 'roles';\n public const META_PATH = 'path';\n public const META_ENTERPRISE_SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';\n public const META_DEPARTMENT = 'department';\n public const META_META = 'meta';\n public const META_TYPE = 'type';\n public const META_VALUE = 'value';\n public const META_OPERATIONS = 'Operations';\n public const META_OP = 'op';\n public const META_RESOURCE_TYPE = 'resourceType';\n public const META_CREATED = 'created';\n public const META_LAST_MODIFIED = 'lastModified';\n public const META_FORMATTED = 'formatted';\n public const META_EMAILS = 'emails';\n public const META_USERNAME = 'userName';\n public const META_NAME = 'name';\n public const META_STATUS = 'active';\n public const META_PRIMARY = 'primary';\n public const META_ERROR_STATUS = 'status';\n public const META_ERROR_DETAIL = 'detail';\n public const META_LIST_TOTAL_RESULTS = 'totalResults';\n public const META_LIST_RESOURCES = 'Resources';\n public const META_LIST_START_INDEX = 'startIndex';\n public const META_LIST_COUNT = 'count';\n public const META_LIST_ITEMS_PER_PAGE = 'itemsPerPage';\n public const META_SCHEMAS = 'schemas';\n public const META_FILTER = 'filter';\n public const META_TYPE_WORK = 'work';\n public const META_PHONE_NUMBER_TYPE_MOBILE = 'mobile';\n public const META_EMAIL_TYPE_HOME = 'home';\n public const META_CONTAINER_NAME = 'name';\n public const META_CONTAINER_EMAILS = 'emails';\n\n public const RESOURCE_TYPE_USER = 'User';\n\n public const USER_PATCH_ATTR_TITLE = 'title';\n public const USER_PATCH_ATTR_ACTIVE = 'active';\n public const USER_PATCH_ATTR_USERNAME = 'userName';\n public const USER_PATCH_ATTR_FIRST_NAME = 'name.givenName';\n public const USER_PATCH_ATTR_LAST_NAME = 'name.familyName';\n public const USER_PATCH_ATTR_PRIMARY_EMAIL = 'emails[type eq \"work\"].value';\n public const USER_PATCH_ATTR_SECONDARY_EMAIL = 'emails[type eq \"home\"].value';\n public const USER_PATCH_ATTR_PHONE_NUMBER = 'phoneNumbers[type eq \"work\"].value';\n public const USER_PATCH_ATTR_PHONE_NUMBER_MOBILE = 'phoneNumbers[type eq \"mobile\"].value';\n public const USER_PATCH_ATTR_ROLES = 'roles';\n\n public const USER_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [\n self::USER_PATCH_ATTR_TITLE => Mutators\\Attributes\\User\\TitleAttr::class,\n self::USER_PATCH_ATTR_ACTIVE => Mutators\\Attributes\\User\\ActiveAttr::class,\n self::USER_PATCH_ATTR_USERNAME => Mutators\\Attributes\\User\\UsernameAttr::class,\n self::USER_PATCH_ATTR_FIRST_NAME => Mutators\\Attributes\\User\\FirstNameAttr::class,\n self::USER_PATCH_ATTR_LAST_NAME => Mutators\\Attributes\\User\\LastNameAttr::class,\n self::USER_PATCH_ATTR_PRIMARY_EMAIL => Mutators\\Attributes\\User\\PrimaryEmailAttr::class,\n self::USER_PATCH_ATTR_SECONDARY_EMAIL => Mutators\\Attributes\\User\\SecondaryEmailAttr::class,\n self::USER_PATCH_ATTR_PHONE_NUMBER => Mutators\\Attributes\\User\\PhoneNumberPrimaryAttr::class,\n self::USER_PATCH_ATTR_PHONE_NUMBER_MOBILE => Mutators\\Attributes\\User\\PhoneNumberSecondaryAttr::class,\n ];\n\n public const FILTER_OPERATOR_EQ = 'eq';\n\n public const SUPPORTED_FILTERS_OPERATORS = [\n self::FILTER_OPERATOR_EQ,\n ];\n\n public const USER_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [\n self::USER_FILTER_LOCAL_ID => Filters\\User\\LocalIdFilter::class,\n self::USER_FILTER_USERNAME => Filters\\User\\UserNameFilter::class,\n self::USER_FILTER_FIRST_NAME => Filters\\User\\FirstNameFilter::class,\n self::USER_FILTER_LAST_NAME => Filters\\User\\LastNameFilter::class,\n self::USER_FILTER_EXTERNAL_ID => Filters\\User\\ExternalIdFilter::class,\n self::USER_FILTER_DISPLAY_NAME => Filters\\User\\DisplayNameFilter::class,\n ];\n\n public const USER_FILTER_LOCAL_ID = 'id';\n public const USER_FILTER_USERNAME = 'userName';\n public const USER_FILTER_FIRST_NAME = 'givenName';\n public const USER_FILTER_LAST_NAME = 'familyName';\n public const USER_FILTER_EXTERNAL_ID = 'externalId';\n public const USER_FILTER_DISPLAY_NAME = 'DisplayName';\n\n public const SCIM_SUPPORTED_RESOURCES = [\n self::USER_RESOURCE_PREFIX,\n self::GROUP_RESOURCE_PREFIX,\n ];\n\n public const USER_RESOURCE_PREFIX = 'Users';\n public const GROUP_RESOURCE_PREFIX = 'Groups';\n\n public const OUTGOING_SCHEMAS_SUPPORTED = [\n self::OUTGOING_CORE_USER,\n\n ];\n\n /**\n * Outgoing supported schemas\n */\n public const OUTGOING_CORE_USER = 'urn:ietf:params:scim:schemas:core:2.0:User';\n public const OUTGOING_ERROR = 'urn:ietf:params:scim:api:messages:2.0:Error';\n public const OUTGOING_LIST_RESPONSE = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';\n\n public const OUTGOING_CORE_GROUP = 'urn:ietf:params:scim:schemas:core:2.0:Group';\n\n /**\n * Groups resource constants\n */\n public const GROUP_ATTRIBUTE_DISPLAY_NAME = 'displayName';\n public const GROUP_ATTRIBUTE_EXTERNAL_ID = 'externalId';\n public const GROUP_ATTRIBUTE_ID = 'id';\n public const RESOURCE_TYPE_GROUP = 'Group';\n public const GROUP_FILTER_QUERY_NAME = 'filter';\n public const GROUP_EXCLUDED_ATTRIBUTES = 'excludedAttributes';\n\n public const GROUP_SUPPORTED_FILTER_ATTRIBUTES = [\n self::GROUP_ATTRIBUTE_DISPLAY_NAME,\n ];\n\n public const GROUP_MEMBERS = 'members';\n\n public const SUPPORTED_PATCH_OPERATIONS = [\n self::META_OPERATIONS_ADD,\n self::META_OPERATIONS_REPLACE,\n self::META_OPERATIONS_REMOVE,\n ];\n\n public const GROUP_PATCH_ATTRIBUTE_MEMBERS = 'members';\n public const GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME = 'displayName';\n\n public const GROUP_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [\n self::GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME => Mutators\\Attributes\\Group\\DisplayNameAttr::class,\n self::GROUP_PATCH_ATTRIBUTE_MEMBERS => Mutators\\Attributes\\Group\\MembersAttr::class,\n ];\n\n public const GROUP_FILTER_DISPLAY_NAME = 'displayname';\n\n public const GROUP_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [\n self::GROUP_FILTER_DISPLAY_NAME => Filters\\Group\\DisplayNameFilter::class,\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}]...
|
8112917949482775138
|
-4595477849910474289
|
idle
|
accessibility
|
NULL
|
Project: faVsco.js, menu
master, menu
Start Listen Project: faVsco.js, menu
master, menu
Start Listening for PHP Debug Connections
AskJiminnyReportActivityServiceTest
Run 'AskJiminnyReportActivityServiceTest'
Debug 'AskJiminnyReportActivityServiceTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
<?php
namespace Jiminny\Component\SCIM;
use Jiminny\Component\SCIM\Builders\Filters;
class Constants
{
/**
* HTTP codes
*/
public const HTTP_OK = 200;
public const HTTP_CREATED = 201;
public const HTTP_NO_CONTENT = 204;
public const HTTP_NOT_FOUND = 404;
public const HTTP_BAD_REQUEST = 400;
public const HTTP_ACCESS_DENIED = 403;
public const HTTP_ERROR = 501;
/**
* Users resource constants
*/
public const USER_FIRST_NAME = 'givenName';
public const USER_FAMILY_NAME = 'familyName';
public const USER_STATUS = 'Active';
public const USER_USERNAME = 'UserName';
public const USER_EXTERNAL_ID = 'externalId';
public const USER_FIELDS = [
self::USER_FIRST_NAME,
self::USER_FAMILY_NAME,
self::USER_STATUS,
self::USER_USERNAME,
];
public const META_OPERATIONS_REPLACE = 'replace';
public const META_OPERATIONS_REPLACE_UPPER = 'Replace';
public const META_OPERATIONS_ADD = 'add';
public const META_OPERATIONS_ADD_UPPER = 'Add';
public const META_OPERATIONS_REMOVE_UPPER = 'Remove';
public const META_OPERATIONS_REMOVE = 'remove';
public const META_ID = 'id';
public const META_PHONE_NUMBERS = 'phoneNumbers';
public const META_TITLE = 'title';
public const META_ROLES = 'roles';
public const META_PATH = 'path';
public const META_ENTERPRISE_SCHEMA = 'urn:ietf:params:scim:schemas:extension:enterprise:2.0:User';
public const META_DEPARTMENT = 'department';
public const META_META = 'meta';
public const META_TYPE = 'type';
public const META_VALUE = 'value';
public const META_OPERATIONS = 'Operations';
public const META_OP = 'op';
public const META_RESOURCE_TYPE = 'resourceType';
public const META_CREATED = 'created';
public const META_LAST_MODIFIED = 'lastModified';
public const META_FORMATTED = 'formatted';
public const META_EMAILS = 'emails';
public const META_USERNAME = 'userName';
public const META_NAME = 'name';
public const META_STATUS = 'active';
public const META_PRIMARY = 'primary';
public const META_ERROR_STATUS = 'status';
public const META_ERROR_DETAIL = 'detail';
public const META_LIST_TOTAL_RESULTS = 'totalResults';
public const META_LIST_RESOURCES = 'Resources';
public const META_LIST_START_INDEX = 'startIndex';
public const META_LIST_COUNT = 'count';
public const META_LIST_ITEMS_PER_PAGE = 'itemsPerPage';
public const META_SCHEMAS = 'schemas';
public const META_FILTER = 'filter';
public const META_TYPE_WORK = 'work';
public const META_PHONE_NUMBER_TYPE_MOBILE = 'mobile';
public const META_EMAIL_TYPE_HOME = 'home';
public const META_CONTAINER_NAME = 'name';
public const META_CONTAINER_EMAILS = 'emails';
public const RESOURCE_TYPE_USER = 'User';
public const USER_PATCH_ATTR_TITLE = 'title';
public const USER_PATCH_ATTR_ACTIVE = 'active';
public const USER_PATCH_ATTR_USERNAME = 'userName';
public const USER_PATCH_ATTR_FIRST_NAME = 'name.givenName';
public const USER_PATCH_ATTR_LAST_NAME = 'name.familyName';
public const USER_PATCH_ATTR_PRIMARY_EMAIL = 'emails[type eq "work"].value';
public const USER_PATCH_ATTR_SECONDARY_EMAIL = 'emails[type eq "home"].value';
public const USER_PATCH_ATTR_PHONE_NUMBER = 'phoneNumbers[type eq "work"].value';
public const USER_PATCH_ATTR_PHONE_NUMBER_MOBILE = 'phoneNumbers[type eq "mobile"].value';
public const USER_PATCH_ATTR_ROLES = 'roles';
public const USER_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [
self::USER_PATCH_ATTR_TITLE => Mutators\Attributes\User\TitleAttr::class,
self::USER_PATCH_ATTR_ACTIVE => Mutators\Attributes\User\ActiveAttr::class,
self::USER_PATCH_ATTR_USERNAME => Mutators\Attributes\User\UsernameAttr::class,
self::USER_PATCH_ATTR_FIRST_NAME => Mutators\Attributes\User\FirstNameAttr::class,
self::USER_PATCH_ATTR_LAST_NAME => Mutators\Attributes\User\LastNameAttr::class,
self::USER_PATCH_ATTR_PRIMARY_EMAIL => Mutators\Attributes\User\PrimaryEmailAttr::class,
self::USER_PATCH_ATTR_SECONDARY_EMAIL => Mutators\Attributes\User\SecondaryEmailAttr::class,
self::USER_PATCH_ATTR_PHONE_NUMBER => Mutators\Attributes\User\PhoneNumberPrimaryAttr::class,
self::USER_PATCH_ATTR_PHONE_NUMBER_MOBILE => Mutators\Attributes\User\PhoneNumberSecondaryAttr::class,
];
public const FILTER_OPERATOR_EQ = 'eq';
public const SUPPORTED_FILTERS_OPERATORS = [
self::FILTER_OPERATOR_EQ,
];
public const USER_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [
self::USER_FILTER_LOCAL_ID => Filters\User\LocalIdFilter::class,
self::USER_FILTER_USERNAME => Filters\User\UserNameFilter::class,
self::USER_FILTER_FIRST_NAME => Filters\User\FirstNameFilter::class,
self::USER_FILTER_LAST_NAME => Filters\User\LastNameFilter::class,
self::USER_FILTER_EXTERNAL_ID => Filters\User\ExternalIdFilter::class,
self::USER_FILTER_DISPLAY_NAME => Filters\User\DisplayNameFilter::class,
];
public const USER_FILTER_LOCAL_ID = 'id';
public const USER_FILTER_USERNAME = 'userName';
public const USER_FILTER_FIRST_NAME = 'givenName';
public const USER_FILTER_LAST_NAME = 'familyName';
public const USER_FILTER_EXTERNAL_ID = 'externalId';
public const USER_FILTER_DISPLAY_NAME = 'DisplayName';
public const SCIM_SUPPORTED_RESOURCES = [
self::USER_RESOURCE_PREFIX,
self::GROUP_RESOURCE_PREFIX,
];
public const USER_RESOURCE_PREFIX = 'Users';
public const GROUP_RESOURCE_PREFIX = 'Groups';
public const OUTGOING_SCHEMAS_SUPPORTED = [
self::OUTGOING_CORE_USER,
];
/**
* Outgoing supported schemas
*/
public const OUTGOING_CORE_USER = 'urn:ietf:params:scim:schemas:core:2.0:User';
public const OUTGOING_ERROR = 'urn:ietf:params:scim:api:messages:2.0:Error';
public const OUTGOING_LIST_RESPONSE = 'urn:ietf:params:scim:api:messages:2.0:ListResponse';
public const OUTGOING_CORE_GROUP = 'urn:ietf:params:scim:schemas:core:2.0:Group';
/**
* Groups resource constants
*/
public const GROUP_ATTRIBUTE_DISPLAY_NAME = 'displayName';
public const GROUP_ATTRIBUTE_EXTERNAL_ID = 'externalId';
public const GROUP_ATTRIBUTE_ID = 'id';
public const RESOURCE_TYPE_GROUP = 'Group';
public const GROUP_FILTER_QUERY_NAME = 'filter';
public const GROUP_EXCLUDED_ATTRIBUTES = 'excludedAttributes';
public const GROUP_SUPPORTED_FILTER_ATTRIBUTES = [
self::GROUP_ATTRIBUTE_DISPLAY_NAME,
];
public const GROUP_MEMBERS = 'members';
public const SUPPORTED_PATCH_OPERATIONS = [
self::META_OPERATIONS_ADD,
self::META_OPERATIONS_REPLACE,
self::META_OPERATIONS_REMOVE,
];
public const GROUP_PATCH_ATTRIBUTE_MEMBERS = 'members';
public const GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME = 'displayName';
public const GROUP_SUPPORTED_PATCH_ATTRIBUTES_MUTATORS = [
self::GROUP_PATCH_ATTRIBUTE_DISPLAY_NAME => Mutators\Attributes\Group\DisplayNameAttr::class,
self::GROUP_PATCH_ATTRIBUTE_MEMBERS => Mutators\Attributes\Group\MembersAttr::class,
];
public const GROUP_FILTER_DISPLAY_NAME = 'displayname';
public const GROUP_SUPPORTED_FILTER_ATTRIBUTES_QUERY_BUILDERS = [
self::GROUP_FILTER_DISPLAY_NAME => Filters\Group\DisplayNameFilter::class,
];
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
53089
|
1860
|
3
|
2026-05-18T11:35:24.210573+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-18/1779 /Users/lukas/.screenpipe/data/data/2026-05-18/1779104124210_m1.jpg...
|
PhpStorm
|
faVsco.js – Constants.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpEU (DOCKER81DE SlackFileEditViewGoHistoryWindowHelpEU (DOCKER81DEV (docker)₴2DOCKER (docker-compose)asticsearch", "data"],"pid":7,"message": "No livingconnections"}kibana1 {"type" : "log", "@timestamp":"2026-05-18T11:35:18Z", "tags" : ["error"ins","plug, "taskManager""taskManager"], "pid" :7, "message" : "Failed to pollfor work: Error: NoLiving connections"}kibana1 {"type": "log","@timestamp": "2026-05-18T11:35:19Z""tags" : ["warning"elasticsearch", "data"], "pid" :7,"message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T11:35: 197", "tags" : ["warning", "elasticsearch","data"], "pid" :7, "message" : "No livingconnections"}kibana1 {"type": "log", "@timestamp": "2026-05-18T11:35:19Z", "tags" : ["warning"ugins""licensing"],"pid" :7, "message" : "License informationcould not be obtained from Elasticsearch due to Error: No Living connections error"}kibana1 {"type" : "log","@timestamp" : "2026-05-18T11:35:19Z", "tags" : ["warning", "elasticsearch", "monitoring"], "pid":7, "message": "Unable to revive connection: [URL_WITH_CREDENTIALS] "2026-05-18T11:35:19Z","tags" : ["warning", "elasticsearch", "monitoring"],"pid" :7,"message":"No living connections"}kibana1 {"type":"log" ,"@timestamp":"2026-05-18T11:35:19Z"."tags" : ["warning","plugins","licensing"], "pid" :7, "message" : "License information could not be obtained from Elasticsearch dueto Error: No Livingconnectionskibana1 {"type" : "log""@timestamp" : "2026-05-18T11:35:21Z","tags" : ["error"ticsearch"arch, "data"], "pid" :7, "message" : "[ConnectionError]: getaddrinfo ENOTFOUND elasticseelasticsearch:9200"}kibana1 {"type" : "log""@timestamp" : "2026-05-18T11:35 :21Z","tags" : ["error", "elasticsearch","data"],"pid":7,'"message":"[ConnectionError]: getaddrinfo ENOTFOUND elasticsearchelasticsearch: 9200"}kibana1 {"type" : "log","@timestamp" : "2026-05-18T11:35:21Z" , "tags" : ["warning", "elasticsearch", "data"],"pid":7, "message": "Unable to revive connection: [URL_WITH_CREDENTIALS] "2026-05-18T11:35:21Z", "tags" : ["warning", "elasticsearch", "data"], "pid":7, "message": "No livingconnections"}kibana1 {"type" : "log".ins",,"@timestamp" : "2026-05-18T11:35:21Z","tags" : ["error", "plug, "taskManager", "taskManager"], "pid" :7, "message" : "Failed to poll for work: Error: NoLivingconnections"}docker_lamp_112026-05-18 11:35:15 Running ['artisan' dialers:monitor-activities].7S DONEdocker_lamp_11 • '/usr/local/bin/php' 'artisan' dialers:monitor-activities › '/proc/1/fd/1' 2>&1kibana1 {"type": "log", "@timestamp": "2026-05-18T11:35:23Z", "tags" : ["error", "elasticsearch", "data"],"pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}View in Docker Desktop• View ConfigEnable WatchHomeDMsActivityFilesLaterMore→Jiminny ...Metrorrtence# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...• Direct messages. Nikolay YankovR. Aneliya Angelovaão Stefka Stoyanova. Stoyan Tomov€. Vasil Vasilev% Galya DimitrovaLa Todor Stamatov ". Mario Georgiev. Nikolay IvanovLo James Graham *8 Stoyan Tanev&. Steliyan Georgiev&e Petko KashinskiE. Lukas Kovalik y...AppsJira CloudToastSupport Daily • in 25 ml100% <7Describe what you are looking forNikolay YankovMessagesAdd canvas@ Files• Add language |TodayCONNECT/SYNC SETTINGSImport Email Conversations'OLet's Get Started:8• Mon 18 May 14:35:246 0+Sign in with Googleне ме пускаNikolay Yankov 2:17 PMЕй сегаГОТОВОLukas Kovalik 2:26 PMоще ведньж и в СФNikolay Yankov 2:27 PMГТОТОВОLukas Kovalik 2:27 PMработи вечеNikolay Yankov 2:27 PMимаше ли нещо за фиксLukas Kovalik 2:28 PMтрябва да си вързан към SF да работиNikolay Yankov 2:28 PMaxaaaMessage Nikolay Yankov...
|
NULL
|
8200747228751208891
|
NULL
|
idle
|
ocr
|
NULL
|
SlackFileEditViewGoHistoryWindowHelpEU (DOCKER81DE SlackFileEditViewGoHistoryWindowHelpEU (DOCKER81DEV (docker)₴2DOCKER (docker-compose)asticsearch", "data"],"pid":7,"message": "No livingconnections"}kibana1 {"type" : "log", "@timestamp":"2026-05-18T11:35:18Z", "tags" : ["error"ins","plug, "taskManager""taskManager"], "pid" :7, "message" : "Failed to pollfor work: Error: NoLiving connections"}kibana1 {"type": "log","@timestamp": "2026-05-18T11:35:19Z""tags" : ["warning"elasticsearch", "data"], "pid" :7,"message" : "Unable to revive connection: [URL_WITH_CREDENTIALS] : "2026-05-18T11:35: 197", "tags" : ["warning", "elasticsearch","data"], "pid" :7, "message" : "No livingconnections"}kibana1 {"type": "log", "@timestamp": "2026-05-18T11:35:19Z", "tags" : ["warning"ugins""licensing"],"pid" :7, "message" : "License informationcould not be obtained from Elasticsearch due to Error: No Living connections error"}kibana1 {"type" : "log","@timestamp" : "2026-05-18T11:35:19Z", "tags" : ["warning", "elasticsearch", "monitoring"], "pid":7, "message": "Unable to revive connection: [URL_WITH_CREDENTIALS] "2026-05-18T11:35:19Z","tags" : ["warning", "elasticsearch", "monitoring"],"pid" :7,"message":"No living connections"}kibana1 {"type":"log" ,"@timestamp":"2026-05-18T11:35:19Z"."tags" : ["warning","plugins","licensing"], "pid" :7, "message" : "License information could not be obtained from Elasticsearch dueto Error: No Livingconnectionskibana1 {"type" : "log""@timestamp" : "2026-05-18T11:35:21Z","tags" : ["error"ticsearch"arch, "data"], "pid" :7, "message" : "[ConnectionError]: getaddrinfo ENOTFOUND elasticseelasticsearch:9200"}kibana1 {"type" : "log""@timestamp" : "2026-05-18T11:35 :21Z","tags" : ["error", "elasticsearch","data"],"pid":7,'"message":"[ConnectionError]: getaddrinfo ENOTFOUND elasticsearchelasticsearch: 9200"}kibana1 {"type" : "log","@timestamp" : "2026-05-18T11:35:21Z" , "tags" : ["warning", "elasticsearch", "data"],"pid":7, "message": "Unable to revive connection: [URL_WITH_CREDENTIALS] "2026-05-18T11:35:21Z", "tags" : ["warning", "elasticsearch", "data"], "pid":7, "message": "No livingconnections"}kibana1 {"type" : "log".ins",,"@timestamp" : "2026-05-18T11:35:21Z","tags" : ["error", "plug, "taskManager", "taskManager"], "pid" :7, "message" : "Failed to poll for work: Error: NoLivingconnections"}docker_lamp_112026-05-18 11:35:15 Running ['artisan' dialers:monitor-activities].7S DONEdocker_lamp_11 • '/usr/local/bin/php' 'artisan' dialers:monitor-activities › '/proc/1/fd/1' 2>&1kibana1 {"type": "log", "@timestamp": "2026-05-18T11:35:23Z", "tags" : ["error", "elasticsearch", "data"],"pid" :7, "message": "[ConnectionError]: getaddrinfo ENOTFOUND elasticsearch elasticsearch:9200"}View in Docker Desktop• View ConfigEnable WatchHomeDMsActivityFilesLaterMore→Jiminny ...Metrorrtence# product_launches# random# releases# sofia-office# support# thank-yous# the_people_of_jimi...• Direct messages. Nikolay YankovR. Aneliya Angelovaão Stefka Stoyanova. Stoyan Tomov€. Vasil Vasilev% Galya DimitrovaLa Todor Stamatov ". Mario Georgiev. Nikolay IvanovLo James Graham *8 Stoyan Tanev&. Steliyan Georgiev&e Petko KashinskiE. Lukas Kovalik y...AppsJira CloudToastSupport Daily • in 25 ml100% <7Describe what you are looking forNikolay YankovMessagesAdd canvas@ Files• Add language |TodayCONNECT/SYNC SETTINGSImport Email Conversations'OLet's Get Started:8• Mon 18 May 14:35:246 0+Sign in with Googleне ме пускаNikolay Yankov 2:17 PMЕй сегаГОТОВОLukas Kovalik 2:26 PMоще ведньж и в СФNikolay Yankov 2:27 PMГТОТОВОLukas Kovalik 2:27 PMработи вечеNikolay Yankov 2:27 PMимаше ли нещо за фиксLukas Kovalik 2:28 PMтрябва да си вързан към SF да работиNikolay Yankov 2:28 PMaxaaaMessage Nikolay Yankov...
|
NULL
|
NULL
|
NULL
|
NULL
|
|
45695
|
1638
|
21
|
2026-05-14T15:19:11.276115+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778771951276_m2.jpg...
|
PhpStorm
|
faVsco.js – Constants.php
|
1
|
NULL
|
monitor_2
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
8
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Component\Datadog;
final class Constants
{
public const float FULL_SAMPLE_RATE = 1.0;
public const string ELASTICSEARCH_REFRESH_WAITING_TIME = 'jiminny.elasticsearch.refresh.waiting_time';
public const string ELASTICSEARCH_INSTANT_INSERT = 'jiminny.elasticsearch.instant-write';
public const string ELASTICSEARCH_ASYNC_INSERT = 'jiminny.elasticsearch.async-write';
public const string ELASTICSEARCH_ASYNC_DELETE = 'jiminny.elasticsearch.async-delete';
public const string TRACK_IMPORTED = 'jiminny.track.imported';
public const string TRACK_NO_AUDIO = 'jiminny.track.no_audio';
public const string AUTOSCORE_CALCULATED = 'jiminny.autoscore.calculated';
public const string SCORECARD_CREATED = 'jiminny.scorecard.created';
public const string ACTIVITY_TRANSCRIPTION = 'jiminny.activity.transcription';
public const string ACTIVITIES_INSTANT_PROCESSED_COUNT = 'jiminny.activities.instant.processed.count';
public const string ACTIVITIES_PROCESSED_COUNT = 'jiminny.activities.processed.count';
public const string ACTIVITIES_NOT_PROCESSED_COUNT = 'jiminny.activities.not_processed.count';
public const string MEETINGS_CAPTURE_RATE = 'jiminny.conference';
public const string MEETINGS_CAPTURE_RATE_MEETING_STARTED = 'jiminny.conference.started';
public const string MEETINGS_CAPTURE_RATE_MEETING_ENDED = 'jiminny.conference.ended';
public const string MEETINGS_CAPTURE_RATE_FAILURE = 'jiminny.conference.failure';
public const string MEETINGS_CAPTURE_TIMING_BOT_DELAY = 'jiminny.conference.bot_delay';
public const string MEETINGS_CAPTURE_RATE_CAPTURE_RESULT = 'jiminny.conference.capture_result';
public const string CUSTOMER_API = 'jiminny.customer_api';
public const string ACTIVITY_LANGUAGE_DETECTION_SUCCESS = 'jiminny.activity.language_detection.success';
public const string ACTIVITY_LANGUAGE_DETECTION_FAIL = 'jiminny.activity.language_detection.fail';
public const string ASK_JIMINNY_DEAL_TEAM_REQUEST = 'jiminny.ask_jiminny_deals.team_write_requests';
public const string ASK_JIMINNY_DEAL_TEAM_READ_REQUEST = 'jiminny.ask_jiminny_deals.team_read_requests';
public const string CRM_AUTO_SYNC = 'jiminny.crm.auto-sync';
public const string ACTIVITIES_DIALERS_STATS = 'jiminny.activities.dialers.stats';
public const string ACTIVITIES_DIALERS_REASON_STATS = 'jiminny.activities.dialers.reason.stats';
public const string ACTIVITIES_DIALERS_TRACK_IMPORTED = 'jiminny.activities.dialers.track.imported';
public const string ACTIVITIES_DIALERS_TRACK_DURATION = 'jiminny.activities.dialers.track.duration';
public const string AI_AUTOMATION_CRM_WRITE_EXECUTED = 'jiminny.ai_automation.crm_update_executed';
public const string AUTOMATED_REPORTS = 'jiminny.automated_reports.usage';
public const string ASK_JIMINNY_REPORTS = 'jiminny.ask_jiminny_reports.usage';
public const string HUBSPOT_WEBHOOK_SYNC = 'jiminny.crm.hubspot_webhook_sync';
public const string AI_ACTIVITY_TYPE = 'jiminny.ai_activity_type';
public const string AI_CALL_SCORING = 'jiminny.ai_call_scoring';
public const string WEBHOOK_DELIVERY_SUCCESS = 'jiminny.webhook.delivery.success';
public const string WEBHOOK_DELIVERY_FAILED = 'jiminny.webhook.delivery.failed';
public const string ACTIVITY_PROCESSING_STEP_TIME = 'jiminny.activity.processing.step.time';
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
8
1
3
4
Previous Highlighted Error
Next Highlighted Error
SELECT
# DISTINCT
opp.id as opp_id, opp.uuid, opp.name,
# COUNT(dr.id) AS deal_risk_count,
# dr.id,
# cfd.value,
usr.name AS owner_name,
opp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,
usr.uuid as owner_uuid,
usr.photo_path as owner_photo,
usr.id AS owner_id,
jt.name as owner_job,
opp.stage_id, opp.stage_updated_at,
acc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,
rt.business_process_id AS pipeline_id
FROM opportunities opp
LEFT JOIN record_types rt ON opp.record_type_id = rt.id
LEFT JOIN users usr ON opp.user_id = usr.id
LEFT JOIN accounts acc ON opp.account_id = acc.id
LEFT JOIN job_titles jt ON usr.job_title_id = jt.id
# LEFT JOIN group_deal_risk_types gdrt ON gdrt.group_id = usr.group_id
# LEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id AND dr.group_deal_risk_type_id = gdrt.id
LEFT JOIN crm_field_data cfd ON (cfd.object_id = opp.id and cfd.crm_field_id = 66814)
WHERE opp.user_id IS NOT NULL
AND opp.deleted_at IS NULL
AND opp.is_closed = 1
AND opp.is_won = 0
AND opp.close_date >= '2024-01-01 00:00:00'
AND opp.close_date <= '2024-12-31 23:59:59'
AND usr.team_id = 1
# and opp.id = 4823179
GROUP BY opp.id, cfd.value
ORDER BY
# cfd.value
CAST(cfd.value AS UNSIGNED)
# owner_name
# (SELECT COUNT(dr.id)
# FROM deal_risks dr
# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id
# WHERE dr.opportunity_id = opp.id
# AND dr.is_active = 1
# AND gdrt.is_enabled = 1)
DESC
LIMIT 25
# OFFSET 0
;
select * from crm_fields where crm_configuration_id = 1 and object_type = 'opportunity';
select * from crm_layout_entities where crm_layout_id = 1493;
SELECT * FROM opportunities WHERE id = 4584045;
SELECT * FROM crm_field_data WHERE object_id = 4584045;
SELECT * FROM opportunities where team_id = 1 and crm_provider_id = '0061K00000lfb9IQAQ'
SELECT
opp.id as opportunity_id,
opp.name,
COUNT(dr.id) as risk_count
FROM opportunities opp
LEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id
WHERE opp.id IN (
6069574,8900938,9507638,9524799,9660490,9662824,9705675,9749758,4158460,4391812,6450439,4448422,5118945,5590675,4584045,7228149,9002408,9165534,9446720,9641778,9665149,9703344,9709280,5747948,4158491,6182565,6263970,5798120,5111315,4536978,6062352,6548383,6072095,6548225,4480986,5011422,6548381,8760540,8917554,9509986,9514392,9569009,9569011,9578490,9713604,5784397,7276612,7288405,8994421,9118219,9608148,9818911,4510535,6479693,5958049,6271674,6550448,4158331,4158483,6126571,6171615,6540943,4897466,5190896,5796182,5932762,8572433,8723698,8892697,9711001,9789264,4549188,6100831,6170064,6260799,6263653,6449936,6530871,6538978,7777651,8059269,8319918,8787049,8901150,9263153,9453207,9514738,9696700,9791062,5752018,6421452,7439134,7878923,9354763,9369285,9514396,9582506,9889949,9890216,4094311,4158495,4158496,6098128,5585661,3872564,6442149,5891604,6164746,6199593,6583474,6519684,9018490,9809006,4496897,5041324,5829430,6198319,6253504,6555763,7242914,7931055,8024125,8797814,8058559,8673347,8892695,8994420,9616219,9714970,9722004,9809439,9818918,6523177,8134147,9002915,9711422,9892713,9901719,9954210,9978435,5800810,6243518,6416114,6222251,6411974,6512456,5791953,6545606,9914780,5805540,6238986,6463838,6547680,9767049,9809437,9810885,9890855,6673493,9902036,4335521,6379871,6503799,6546077,8018765,9907556,9958433,9905855,9916179,9946741,9957877,5563344,6271838,6450815,7641128,7762567,7780592,8684810,8685786,8685787,8685788
)
GROUP BY opp.id;
SELECT COUNT(dr.id)
FROM deal_risks dr
JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id
WHERE dr.opportunity_id = 5563344
# AND gdrt.group_id = usr.group_id
EXPLAIN SELECT
opp.id as opp_id, opp.uuid, opp.name,
cfd.value,
cfv.sequence,
cfv.value,
# MAX(cfd.value) AS max_cfd_value,
usr.name AS owner_name,
opp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,
usr.uuid as owner_uuid,
usr.photo_path as owner_photo,
usr.id AS owner_id,
jt.name as owner_job,
opp.stage_id, opp.stage_updated_at,
acc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,
rt.business_process_id AS pipeline_id
FROM opportunities opp
LEFT JOIN record_types rt ON opp.record_type_id = rt.id
LEFT JOIN users usr ON opp.user_id = usr.id
LEFT JOIN accounts acc ON opp.account_id = acc.id
LEFT JOIN job_titles jt ON usr.job_title_id = jt.id
LEFT JOIN crm_field_data cfd ON cfd.id = (SELECT sub_cfd.id
FROM crm_field_data sub_cfd
WHERE sub_cfd.object_id = opp.id
AND sub_cfd.crm_field_id = 66810
ORDER BY sub_cfd.updated_at DESC
LIMIT 1)
LEFT JOIN crm_field_values cfv ON cfv.crm_field_id = 66810 AND cfv.value = cfd.value
WHERE opp.user_id IS NOT NULL
AND opp.deleted_at IS NULL
AND opp.is_closed = 0
# AND opp.is_closed = 1
# AND opp.is_won = 0
AND opp.close_date >= '2024-01-01 00:00:00'
AND opp.close_date <= '2024-12-31 23:59:59'
AND usr.team_id = 1
# and opp.id = 4823179
# GROUP BY opp.id
ORDER BY
cfv.sequence DESC,
# opp.name
# owner_name
cfd.value
# CAST(cfd.value AS UNSIGNED)
# CAST(MAX(cfd.value) AS UNSIGNED)
# (SELECT COUNT(dr.id)
# FROM deal_risks dr
# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id
# WHERE dr.opportunity_id = opp.id
# AND dr.is_active = 1 AND gdrt.is_enabled = 1)
DESC
# LIMIT 75, 25
;
SELECT * FROM crm_field_values WHERE crm_field_id = 66810;
SELECT f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value, fd.updated_at, fd.id, fd.created_at
FROM crm_fields f
INNER JOIN crm_field_data fd ON fd.crm_field_id = f.id
WHERE (f.crm_configuration_id = 1)
AND (f.object_type = 'opportunity')
# AND (fd.object_id IN (4158331,4158483,4158495,4158496,6069574,6263970,6171615,6540943,6545606,5829430,6198319,6263653,6548381,7242914,8797814,7228149,7439134,7878923,8134147,9002915,9118219,9165534,9354763,9369285,9446720))
AND (fd.object_id IN (4158460))
AND (f.crm_provider_id IN ('ForecastCategoryName'))
ORDER BY fd.object_id ASC, fd.updated_at DESC;
select * from crm_layouts where crm_configuration_id = 1;
select cf.* from crm_fields cf
join crm_layout_entities cle on cf.id = cle.crm_field_id
where crm_layout_id = 1493;
SELECT * FROM opportunities WHERE id = 4158460;
SELECT * FROM crm_field_data WHERE object_id = 4158460;
select * from users where team_id = 1;
SELECT * FROM users WHERE id = 7160;
select * from role_user where user_id = 3248;
select * from crm_field_values where crm_field_id = 66824;
SELECT * FROM users WHERE id = 23470;
select * from crm_configurations;
# [PASSWORD_DOTS]
select * from teams where id = 1038; # 23521, 966
select * from users where team_id = 1038;
select * from crm_configurations where id = 966;
SELECT * FROM activities WHERE uuid_to_bin('e8dc7c34-31f6-4430-bd81-2d9d8f00dd07') = uuid; # 54965762
SELECT * FROM activities WHERE uuid_to_bin('4b5727c0-69d1-428f-b8d9-b649055166e2') = uuid; # 54965764
SELECT * FROM participants WHERE activity_id = 54965764;
SELECT id, uuid, title, recording_state FROM activities WHERE uuid_to_bin('355f105d-5606-4379-b0c5-d91daf59f4ce') = uuid; # 54964075
SELECT * FROM participants WHERE activity_id = 54964075;
select f.id, slug, title, tf.team_id from team_features tf JOIN features f on tf.feature_id = f.id
where tf.team_id = 1038;
# [PASSWORD_DOTS] PD [PASSWORD_DOTS]
select * from teams where id = 1029;
SELECT * FROM crm_configurations WHERE id = 957;
SELECT * FROM activities WHERE uuid_to_bin('581a33cb-4343-44bd-ac0c-4a5cee71c5ec') = uuid; # 54963423
SELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433
SELECT * FROM activities WHERE uuid_to_bin('8b6bb2f7-e7a7-4aec-8806-fbfea7093ccd') = uuid; # 54963421
# [PASSWORD_DOTS] Close [PASSWORD_DOTS]
select * from teams where id = 1031;
SELECT * FROM crm_configurations WHERE id = 959;
SELECT * FROM activities WHERE uuid_to_bin('59c517e0-96c9-4dad-bfeb-b7bef72f8725') = uuid; # 54963517
SELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433
SELECT * FROM activities WHERE uuid_to_bin('d68311e3-ac34-49bd-bf04-88323a7e5352') = uuid; # 54966009
# [PASSWORD_DOTS] SF [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('2bd4cfa3-4eb5-4c77-84a7-9ed46a21c988') = uuid;
select * from roles;
select * from permissions;
select * from permission_role where permission_id = 136;
select * from migrations order by id desc;
select * from teams where id IN (1, 1037);
select * from crm_layouts where crm_configuration_id = 1;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 1493;
SELECT * FROM crm_fields WHERE id IN (1652,1661,66799,66814,66821,66836,66843,66846,66864,84752,182306,323580,380378);
select * from features;
select * from team_features where feature_id = 33;
select * from opportunities;
select * from teams;
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 = 1052 and sa.provider = 'hubspot';
SELECT * FROM accounts where id = 11512582;
select * from activities where account_id = 11512582;
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.15259309,"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":"#12066 on JY-20725-handle-HS-search-rate-limit, menu","depth":5,"bounds":{"left":0.19115691,"top":0.019952115,"width":0.122340426,"height":0.025538707},"on_screen":true,"help_text":"Pull request #12066 exists for current branch JY-20725-handle-HS-search-rate-limit, but local branch is out of sync with remote","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.8238032,"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":"HandleHubspotRateLimitTest","depth":6,"bounds":{"left":0.8390958,"top":0.019952115,"width":0.076130316,"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 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.91522604,"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 'HandleHubspotRateLimitTest'","depth":6,"bounds":{"left":0.9265292,"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.9378325,"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.96575797,"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.97706115,"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.98836434,"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":"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":"8","depth":4,"bounds":{"left":0.84109044,"top":0.12529927,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.8507314,"top":0.123703115,"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.8580452,"top":0.123703115,"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":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\Datadog;\n\nfinal class Constants\n{\n public const float FULL_SAMPLE_RATE = 1.0;\n\n public const string ELASTICSEARCH_REFRESH_WAITING_TIME = 'jiminny.elasticsearch.refresh.waiting_time';\n public const string ELASTICSEARCH_INSTANT_INSERT = 'jiminny.elasticsearch.instant-write';\n public const string ELASTICSEARCH_ASYNC_INSERT = 'jiminny.elasticsearch.async-write';\n public const string ELASTICSEARCH_ASYNC_DELETE = 'jiminny.elasticsearch.async-delete';\n public const string TRACK_IMPORTED = 'jiminny.track.imported';\n public const string TRACK_NO_AUDIO = 'jiminny.track.no_audio';\n public const string AUTOSCORE_CALCULATED = 'jiminny.autoscore.calculated';\n public const string SCORECARD_CREATED = 'jiminny.scorecard.created';\n public const string ACTIVITY_TRANSCRIPTION = 'jiminny.activity.transcription';\n public const string ACTIVITIES_INSTANT_PROCESSED_COUNT = 'jiminny.activities.instant.processed.count';\n public const string ACTIVITIES_PROCESSED_COUNT = 'jiminny.activities.processed.count';\n public const string ACTIVITIES_NOT_PROCESSED_COUNT = 'jiminny.activities.not_processed.count';\n public const string MEETINGS_CAPTURE_RATE = 'jiminny.conference';\n public const string MEETINGS_CAPTURE_RATE_MEETING_STARTED = 'jiminny.conference.started';\n public const string MEETINGS_CAPTURE_RATE_MEETING_ENDED = 'jiminny.conference.ended';\n public const string MEETINGS_CAPTURE_RATE_FAILURE = 'jiminny.conference.failure';\n public const string MEETINGS_CAPTURE_TIMING_BOT_DELAY = 'jiminny.conference.bot_delay';\n public const string MEETINGS_CAPTURE_RATE_CAPTURE_RESULT = 'jiminny.conference.capture_result';\n public const string CUSTOMER_API = 'jiminny.customer_api';\n public const string ACTIVITY_LANGUAGE_DETECTION_SUCCESS = 'jiminny.activity.language_detection.success';\n public const string ACTIVITY_LANGUAGE_DETECTION_FAIL = 'jiminny.activity.language_detection.fail';\n public const string ASK_JIMINNY_DEAL_TEAM_REQUEST = 'jiminny.ask_jiminny_deals.team_write_requests';\n public const string ASK_JIMINNY_DEAL_TEAM_READ_REQUEST = 'jiminny.ask_jiminny_deals.team_read_requests';\n public const string CRM_AUTO_SYNC = 'jiminny.crm.auto-sync';\n public const string ACTIVITIES_DIALERS_STATS = 'jiminny.activities.dialers.stats';\n public const string ACTIVITIES_DIALERS_REASON_STATS = 'jiminny.activities.dialers.reason.stats';\n public const string ACTIVITIES_DIALERS_TRACK_IMPORTED = 'jiminny.activities.dialers.track.imported';\n public const string ACTIVITIES_DIALERS_TRACK_DURATION = 'jiminny.activities.dialers.track.duration';\n public const string AI_AUTOMATION_CRM_WRITE_EXECUTED = 'jiminny.ai_automation.crm_update_executed';\n public const string AUTOMATED_REPORTS = 'jiminny.automated_reports.usage';\n public const string ASK_JIMINNY_REPORTS = 'jiminny.ask_jiminny_reports.usage';\n public const string HUBSPOT_WEBHOOK_SYNC = 'jiminny.crm.hubspot_webhook_sync';\n public const string AI_ACTIVITY_TYPE = 'jiminny.ai_activity_type';\n public const string AI_CALL_SCORING = 'jiminny.ai_call_scoring';\n public const string WEBHOOK_DELIVERY_SUCCESS = 'jiminny.webhook.delivery.success';\n public const string WEBHOOK_DELIVERY_FAILED = 'jiminny.webhook.delivery.failed';\n public const string ACTIVITY_PROCESSING_STEP_TIME = 'jiminny.activity.processing.step.time';\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\Datadog;\n\nfinal class Constants\n{\n public const float FULL_SAMPLE_RATE = 1.0;\n\n public const string ELASTICSEARCH_REFRESH_WAITING_TIME = 'jiminny.elasticsearch.refresh.waiting_time';\n public const string ELASTICSEARCH_INSTANT_INSERT = 'jiminny.elasticsearch.instant-write';\n public const string ELASTICSEARCH_ASYNC_INSERT = 'jiminny.elasticsearch.async-write';\n public const string ELASTICSEARCH_ASYNC_DELETE = 'jiminny.elasticsearch.async-delete';\n public const string TRACK_IMPORTED = 'jiminny.track.imported';\n public const string TRACK_NO_AUDIO = 'jiminny.track.no_audio';\n public const string AUTOSCORE_CALCULATED = 'jiminny.autoscore.calculated';\n public const string SCORECARD_CREATED = 'jiminny.scorecard.created';\n public const string ACTIVITY_TRANSCRIPTION = 'jiminny.activity.transcription';\n public const string ACTIVITIES_INSTANT_PROCESSED_COUNT = 'jiminny.activities.instant.processed.count';\n public const string ACTIVITIES_PROCESSED_COUNT = 'jiminny.activities.processed.count';\n public const string ACTIVITIES_NOT_PROCESSED_COUNT = 'jiminny.activities.not_processed.count';\n public const string MEETINGS_CAPTURE_RATE = 'jiminny.conference';\n public const string MEETINGS_CAPTURE_RATE_MEETING_STARTED = 'jiminny.conference.started';\n public const string MEETINGS_CAPTURE_RATE_MEETING_ENDED = 'jiminny.conference.ended';\n public const string MEETINGS_CAPTURE_RATE_FAILURE = 'jiminny.conference.failure';\n public const string MEETINGS_CAPTURE_TIMING_BOT_DELAY = 'jiminny.conference.bot_delay';\n public const string MEETINGS_CAPTURE_RATE_CAPTURE_RESULT = 'jiminny.conference.capture_result';\n public const string CUSTOMER_API = 'jiminny.customer_api';\n public const string ACTIVITY_LANGUAGE_DETECTION_SUCCESS = 'jiminny.activity.language_detection.success';\n public const string ACTIVITY_LANGUAGE_DETECTION_FAIL = 'jiminny.activity.language_detection.fail';\n public const string ASK_JIMINNY_DEAL_TEAM_REQUEST = 'jiminny.ask_jiminny_deals.team_write_requests';\n public const string ASK_JIMINNY_DEAL_TEAM_READ_REQUEST = 'jiminny.ask_jiminny_deals.team_read_requests';\n public const string CRM_AUTO_SYNC = 'jiminny.crm.auto-sync';\n public const string ACTIVITIES_DIALERS_STATS = 'jiminny.activities.dialers.stats';\n public const string ACTIVITIES_DIALERS_REASON_STATS = 'jiminny.activities.dialers.reason.stats';\n public const string ACTIVITIES_DIALERS_TRACK_IMPORTED = 'jiminny.activities.dialers.track.imported';\n public const string ACTIVITIES_DIALERS_TRACK_DURATION = 'jiminny.activities.dialers.track.duration';\n public const string AI_AUTOMATION_CRM_WRITE_EXECUTED = 'jiminny.ai_automation.crm_update_executed';\n public const string AUTOMATED_REPORTS = 'jiminny.automated_reports.usage';\n public const string ASK_JIMINNY_REPORTS = 'jiminny.ask_jiminny_reports.usage';\n public const string HUBSPOT_WEBHOOK_SYNC = 'jiminny.crm.hubspot_webhook_sync';\n public const string AI_ACTIVITY_TYPE = 'jiminny.ai_activity_type';\n public const string AI_CALL_SCORING = 'jiminny.ai_call_scoring';\n public const string WEBHOOK_DELIVERY_SUCCESS = 'jiminny.webhook.delivery.success';\n public const string WEBHOOK_DELIVERY_FAILED = 'jiminny.webhook.delivery.failed';\n public const string ACTIVITY_PROCESSING_STEP_TIME = 'jiminny.activity.processing.step.time';\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.86668885,"top":0.17318435,"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.8753325,"top":0.17318435,"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.8863032,"top":0.17318435,"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.8949468,"top":0.17318435,"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.90359044,"top":0.17318435,"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.91456115,"top":0.17318435,"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.9255319,"top":0.17318435,"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,"on_screen":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"on_screen":false,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"jiminny","depth":4,"bounds":{"left":0.9584442,"top":0.17318435,"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":"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":"8","depth":4,"bounds":{"left":0.93484044,"top":0.19792499,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"bounds":{"left":0.94481385,"top":0.19792499,"width":0.00731383,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"bounds":{"left":0.95412236,"top":0.19792499,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"4","depth":4,"bounds":{"left":0.9640958,"top":0.19792499,"width":0.007978723,"height":0.015163607},"on_screen":true,"role_description":"text"},{"role":"AXButton","text":"Previous Highlighted Error","depth":4,"bounds":{"left":0.9737367,"top":0.1963288,"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.98105055,"top":0.1963288,"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\n# DISTINCT\nopp.id as opp_id, opp.uuid, opp.name,\n# COUNT(dr.id) AS deal_risk_count,\n\n# dr.id,\n# cfd.value,\nusr.name AS owner_name,\nopp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,\nusr.uuid as owner_uuid,\nusr.photo_path as owner_photo,\nusr.id AS owner_id,\njt.name as owner_job,\nopp.stage_id, opp.stage_updated_at,\nacc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,\nrt.business_process_id AS pipeline_id\nFROM opportunities opp\nLEFT JOIN record_types rt ON opp.record_type_id = rt.id\nLEFT JOIN users usr ON opp.user_id = usr.id\nLEFT JOIN accounts acc ON opp.account_id = acc.id\nLEFT JOIN job_titles jt ON usr.job_title_id = jt.id\n\n# LEFT JOIN group_deal_risk_types gdrt ON gdrt.group_id = usr.group_id\n# LEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id AND dr.group_deal_risk_type_id = gdrt.id\n\nLEFT JOIN crm_field_data cfd ON (cfd.object_id = opp.id and cfd.crm_field_id = 66814)\n\nWHERE opp.user_id IS NOT NULL\nAND opp.deleted_at IS NULL\nAND opp.is_closed = 1\nAND opp.is_won = 0\nAND opp.close_date >= '2024-01-01 00:00:00'\nAND opp.close_date <= '2024-12-31 23:59:59'\nAND usr.team_id = 1\n\n# and opp.id = 4823179\n\nGROUP BY opp.id, cfd.value\nORDER BY\n# cfd.value\n CAST(cfd.value AS UNSIGNED)\n# owner_name\n# (SELECT COUNT(dr.id)\n# FROM deal_risks dr\n# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n# WHERE dr.opportunity_id = opp.id\n# AND dr.is_active = 1\n# AND gdrt.is_enabled = 1)\nDESC\nLIMIT 25\n# OFFSET 0\n;\n\nselect * from crm_fields where crm_configuration_id = 1 and object_type = 'opportunity';\nselect * from crm_layout_entities where crm_layout_id = 1493;\n\nSELECT * FROM opportunities WHERE id = 4584045;\nSELECT * FROM crm_field_data WHERE object_id = 4584045;\n\nSELECT * FROM opportunities where team_id = 1 and crm_provider_id = '0061K00000lfb9IQAQ'\n\nSELECT\n opp.id as opportunity_id,\n opp.name,\n COUNT(dr.id) as risk_count\nFROM opportunities opp\nLEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id\nWHERE opp.id IN (\n 6069574,8900938,9507638,9524799,9660490,9662824,9705675,9749758,4158460,4391812,6450439,4448422,5118945,5590675,4584045,7228149,9002408,9165534,9446720,9641778,9665149,9703344,9709280,5747948,4158491,6182565,6263970,5798120,5111315,4536978,6062352,6548383,6072095,6548225,4480986,5011422,6548381,8760540,8917554,9509986,9514392,9569009,9569011,9578490,9713604,5784397,7276612,7288405,8994421,9118219,9608148,9818911,4510535,6479693,5958049,6271674,6550448,4158331,4158483,6126571,6171615,6540943,4897466,5190896,5796182,5932762,8572433,8723698,8892697,9711001,9789264,4549188,6100831,6170064,6260799,6263653,6449936,6530871,6538978,7777651,8059269,8319918,8787049,8901150,9263153,9453207,9514738,9696700,9791062,5752018,6421452,7439134,7878923,9354763,9369285,9514396,9582506,9889949,9890216,4094311,4158495,4158496,6098128,5585661,3872564,6442149,5891604,6164746,6199593,6583474,6519684,9018490,9809006,4496897,5041324,5829430,6198319,6253504,6555763,7242914,7931055,8024125,8797814,8058559,8673347,8892695,8994420,9616219,9714970,9722004,9809439,9818918,6523177,8134147,9002915,9711422,9892713,9901719,9954210,9978435,5800810,6243518,6416114,6222251,6411974,6512456,5791953,6545606,9914780,5805540,6238986,6463838,6547680,9767049,9809437,9810885,9890855,6673493,9902036,4335521,6379871,6503799,6546077,8018765,9907556,9958433,9905855,9916179,9946741,9957877,5563344,6271838,6450815,7641128,7762567,7780592,8684810,8685786,8685787,8685788\n)\nGROUP BY opp.id;\n\nSELECT COUNT(dr.id)\n FROM deal_risks dr\n JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n WHERE dr.opportunity_id = 5563344\n# AND gdrt.group_id = usr.group_id\n\n\n\nEXPLAIN SELECT\n opp.id as opp_id, opp.uuid, opp.name,\n\ncfd.value,\ncfv.sequence,\ncfv.value,\n# MAX(cfd.value) AS max_cfd_value,\nusr.name AS owner_name,\nopp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,\nusr.uuid as owner_uuid,\nusr.photo_path as owner_photo,\nusr.id AS owner_id,\njt.name as owner_job,\nopp.stage_id, opp.stage_updated_at,\nacc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,\nrt.business_process_id AS pipeline_id\nFROM opportunities opp\n\nLEFT JOIN record_types rt ON opp.record_type_id = rt.id\nLEFT JOIN users usr ON opp.user_id = usr.id\nLEFT JOIN accounts acc ON opp.account_id = acc.id\nLEFT JOIN job_titles jt ON usr.job_title_id = jt.id\n\nLEFT JOIN crm_field_data cfd ON cfd.id = (SELECT sub_cfd.id\n FROM crm_field_data sub_cfd\n WHERE sub_cfd.object_id = opp.id\n AND sub_cfd.crm_field_id = 66810\n ORDER BY sub_cfd.updated_at DESC\n LIMIT 1)\n\nLEFT JOIN crm_field_values cfv ON cfv.crm_field_id = 66810 AND cfv.value = cfd.value\n\nWHERE opp.user_id IS NOT NULL\nAND opp.deleted_at IS NULL\nAND opp.is_closed = 0\n# AND opp.is_closed = 1\n# AND opp.is_won = 0\nAND opp.close_date >= '2024-01-01 00:00:00'\nAND opp.close_date <= '2024-12-31 23:59:59'\nAND usr.team_id = 1\n\n# and opp.id = 4823179\n\n# GROUP BY opp.id\nORDER BY\n cfv.sequence DESC,\n# opp.name\n# owner_name\n cfd.value\n# CAST(cfd.value AS UNSIGNED)\n# CAST(MAX(cfd.value) AS UNSIGNED)\n# (SELECT COUNT(dr.id)\n# FROM deal_risks dr\n# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n# WHERE dr.opportunity_id = opp.id\n# AND dr.is_active = 1 AND gdrt.is_enabled = 1)\nDESC\n# LIMIT 75, 25\n;\n\n\n\nSELECT * FROM crm_field_values WHERE crm_field_id = 66810;\n\nSELECT f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value, fd.updated_at, fd.id, fd.created_at\nFROM crm_fields f\nINNER JOIN crm_field_data fd ON fd.crm_field_id = f.id\n WHERE (f.crm_configuration_id = 1)\n AND (f.object_type = 'opportunity')\n# AND (fd.object_id IN (4158331,4158483,4158495,4158496,6069574,6263970,6171615,6540943,6545606,5829430,6198319,6263653,6548381,7242914,8797814,7228149,7439134,7878923,8134147,9002915,9118219,9165534,9354763,9369285,9446720))\n AND (fd.object_id IN (4158460))\n AND (f.crm_provider_id IN ('ForecastCategoryName'))\n ORDER BY fd.object_id ASC, fd.updated_at DESC;\n\nselect * from crm_layouts where crm_configuration_id = 1;\nselect cf.* from crm_fields cf\njoin crm_layout_entities cle on cf.id = cle.crm_field_id\nwhere crm_layout_id = 1493;\n\nSELECT * FROM opportunities WHERE id = 4158460;\nSELECT * FROM crm_field_data WHERE object_id = 4158460;\n\nselect * from users where team_id = 1;\nSELECT * FROM users WHERE id = 7160;\nselect * from role_user where user_id = 3248;\n\nselect * from crm_field_values where crm_field_id = 66824;\n\nSELECT * FROM users WHERE id = 23470;\nselect * from crm_configurations;\n\n# ******************************************\nselect * from teams where id = 1038; # 23521, 966\nselect * from users where team_id = 1038;\nselect * from crm_configurations where id = 966;\nSELECT * FROM activities WHERE uuid_to_bin('e8dc7c34-31f6-4430-bd81-2d9d8f00dd07') = uuid; # 54965762\nSELECT * FROM activities WHERE uuid_to_bin('4b5727c0-69d1-428f-b8d9-b649055166e2') = uuid; # 54965764\nSELECT * FROM participants WHERE activity_id = 54965764;\n\nSELECT id, uuid, title, recording_state FROM activities WHERE uuid_to_bin('355f105d-5606-4379-b0c5-d91daf59f4ce') = uuid; # 54964075\nSELECT * FROM participants WHERE activity_id = 54964075;\nselect f.id, slug, title, tf.team_id from team_features tf JOIN features f on tf.feature_id = f.id\n where tf.team_id = 1038;\n\n\n# ****************************************** PD *************************\nselect * from teams where id = 1029;\nSELECT * FROM crm_configurations WHERE id = 957;\nSELECT * FROM activities WHERE uuid_to_bin('581a33cb-4343-44bd-ac0c-4a5cee71c5ec') = uuid; # 54963423\nSELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433\n\nSELECT * FROM activities WHERE uuid_to_bin('8b6bb2f7-e7a7-4aec-8806-fbfea7093ccd') = uuid; # 54963421\n\n# ****************************************** Close *************************\nselect * from teams where id = 1031;\nSELECT * FROM crm_configurations WHERE id = 959;\nSELECT * FROM activities WHERE uuid_to_bin('59c517e0-96c9-4dad-bfeb-b7bef72f8725') = uuid; # 54963517\n\n\nSELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433\n\nSELECT * FROM activities WHERE uuid_to_bin('d68311e3-ac34-49bd-bf04-88323a7e5352') = uuid; # 54966009\n\n# ****************************************** SF *************************\nSELECT * FROM activities WHERE uuid_to_bin('2bd4cfa3-4eb5-4c77-84a7-9ed46a21c988') = uuid;\n\nselect * from roles;\nselect * from permissions;\nselect * from permission_role where permission_id = 136;\n\nselect * from migrations order by id desc;\n\nselect * from teams where id IN (1, 1037);\nselect * from crm_layouts where crm_configuration_id = 1;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1493;\nSELECT * FROM crm_fields WHERE id IN (1652,1661,66799,66814,66821,66836,66843,66846,66864,84752,182306,323580,380378);\n\nselect * from features;\nselect * from team_features where feature_id = 33;\nselect * from opportunities;\n\nselect * from teams;\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 = 1052 and sa.provider = 'hubspot';\n\nSELECT * FROM accounts where id = 11512582;\nselect * from activities where account_id = 11512582;","depth":4,"on_screen":true,"value":"SELECT\n# DISTINCT\nopp.id as opp_id, opp.uuid, opp.name,\n# COUNT(dr.id) AS deal_risk_count,\n\n# dr.id,\n# cfd.value,\nusr.name AS owner_name,\nopp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,\nusr.uuid as owner_uuid,\nusr.photo_path as owner_photo,\nusr.id AS owner_id,\njt.name as owner_job,\nopp.stage_id, opp.stage_updated_at,\nacc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,\nrt.business_process_id AS pipeline_id\nFROM opportunities opp\nLEFT JOIN record_types rt ON opp.record_type_id = rt.id\nLEFT JOIN users usr ON opp.user_id = usr.id\nLEFT JOIN accounts acc ON opp.account_id = acc.id\nLEFT JOIN job_titles jt ON usr.job_title_id = jt.id\n\n# LEFT JOIN group_deal_risk_types gdrt ON gdrt.group_id = usr.group_id\n# LEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id AND dr.group_deal_risk_type_id = gdrt.id\n\nLEFT JOIN crm_field_data cfd ON (cfd.object_id = opp.id and cfd.crm_field_id = 66814)\n\nWHERE opp.user_id IS NOT NULL\nAND opp.deleted_at IS NULL\nAND opp.is_closed = 1\nAND opp.is_won = 0\nAND opp.close_date >= '2024-01-01 00:00:00'\nAND opp.close_date <= '2024-12-31 23:59:59'\nAND usr.team_id = 1\n\n# and opp.id = 4823179\n\nGROUP BY opp.id, cfd.value\nORDER BY\n# cfd.value\n CAST(cfd.value AS UNSIGNED)\n# owner_name\n# (SELECT COUNT(dr.id)\n# FROM deal_risks dr\n# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n# WHERE dr.opportunity_id = opp.id\n# AND dr.is_active = 1\n# AND gdrt.is_enabled = 1)\nDESC\nLIMIT 25\n# OFFSET 0\n;\n\nselect * from crm_fields where crm_configuration_id = 1 and object_type = 'opportunity';\nselect * from crm_layout_entities where crm_layout_id = 1493;\n\nSELECT * FROM opportunities WHERE id = 4584045;\nSELECT * FROM crm_field_data WHERE object_id = 4584045;\n\nSELECT * FROM opportunities where team_id = 1 and crm_provider_id = '0061K00000lfb9IQAQ'\n\nSELECT\n opp.id as opportunity_id,\n opp.name,\n COUNT(dr.id) as risk_count\nFROM opportunities opp\nLEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id\nWHERE opp.id IN (\n 6069574,8900938,9507638,9524799,9660490,9662824,9705675,9749758,4158460,4391812,6450439,4448422,5118945,5590675,4584045,7228149,9002408,9165534,9446720,9641778,9665149,9703344,9709280,5747948,4158491,6182565,6263970,5798120,5111315,4536978,6062352,6548383,6072095,6548225,4480986,5011422,6548381,8760540,8917554,9509986,9514392,9569009,9569011,9578490,9713604,5784397,7276612,7288405,8994421,9118219,9608148,9818911,4510535,6479693,5958049,6271674,6550448,4158331,4158483,6126571,6171615,6540943,4897466,5190896,5796182,5932762,8572433,8723698,8892697,9711001,9789264,4549188,6100831,6170064,6260799,6263653,6449936,6530871,6538978,7777651,8059269,8319918,8787049,8901150,9263153,9453207,9514738,9696700,9791062,5752018,6421452,7439134,7878923,9354763,9369285,9514396,9582506,9889949,9890216,4094311,4158495,4158496,6098128,5585661,3872564,6442149,5891604,6164746,6199593,6583474,6519684,9018490,9809006,4496897,5041324,5829430,6198319,6253504,6555763,7242914,7931055,8024125,8797814,8058559,8673347,8892695,8994420,9616219,9714970,9722004,9809439,9818918,6523177,8134147,9002915,9711422,9892713,9901719,9954210,9978435,5800810,6243518,6416114,6222251,6411974,6512456,5791953,6545606,9914780,5805540,6238986,6463838,6547680,9767049,9809437,9810885,9890855,6673493,9902036,4335521,6379871,6503799,6546077,8018765,9907556,9958433,9905855,9916179,9946741,9957877,5563344,6271838,6450815,7641128,7762567,7780592,8684810,8685786,8685787,8685788\n)\nGROUP BY opp.id;\n\nSELECT COUNT(dr.id)\n FROM deal_risks dr\n JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n WHERE dr.opportunity_id = 5563344\n# AND gdrt.group_id = usr.group_id\n\n\n\nEXPLAIN SELECT\n opp.id as opp_id, opp.uuid, opp.name,\n\ncfd.value,\ncfv.sequence,\ncfv.value,\n# MAX(cfd.value) AS max_cfd_value,\nusr.name AS owner_name,\nopp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,\nusr.uuid as owner_uuid,\nusr.photo_path as owner_photo,\nusr.id AS owner_id,\njt.name as owner_job,\nopp.stage_id, opp.stage_updated_at,\nacc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,\nrt.business_process_id AS pipeline_id\nFROM opportunities opp\n\nLEFT JOIN record_types rt ON opp.record_type_id = rt.id\nLEFT JOIN users usr ON opp.user_id = usr.id\nLEFT JOIN accounts acc ON opp.account_id = acc.id\nLEFT JOIN job_titles jt ON usr.job_title_id = jt.id\n\nLEFT JOIN crm_field_data cfd ON cfd.id = (SELECT sub_cfd.id\n FROM crm_field_data sub_cfd\n WHERE sub_cfd.object_id = opp.id\n AND sub_cfd.crm_field_id = 66810\n ORDER BY sub_cfd.updated_at DESC\n LIMIT 1)\n\nLEFT JOIN crm_field_values cfv ON cfv.crm_field_id = 66810 AND cfv.value = cfd.value\n\nWHERE opp.user_id IS NOT NULL\nAND opp.deleted_at IS NULL\nAND opp.is_closed = 0\n# AND opp.is_closed = 1\n# AND opp.is_won = 0\nAND opp.close_date >= '2024-01-01 00:00:00'\nAND opp.close_date <= '2024-12-31 23:59:59'\nAND usr.team_id = 1\n\n# and opp.id = 4823179\n\n# GROUP BY opp.id\nORDER BY\n cfv.sequence DESC,\n# opp.name\n# owner_name\n cfd.value\n# CAST(cfd.value AS UNSIGNED)\n# CAST(MAX(cfd.value) AS UNSIGNED)\n# (SELECT COUNT(dr.id)\n# FROM deal_risks dr\n# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n# WHERE dr.opportunity_id = opp.id\n# AND dr.is_active = 1 AND gdrt.is_enabled = 1)\nDESC\n# LIMIT 75, 25\n;\n\n\n\nSELECT * FROM crm_field_values WHERE crm_field_id = 66810;\n\nSELECT f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value, fd.updated_at, fd.id, fd.created_at\nFROM crm_fields f\nINNER JOIN crm_field_data fd ON fd.crm_field_id = f.id\n WHERE (f.crm_configuration_id = 1)\n AND (f.object_type = 'opportunity')\n# AND (fd.object_id IN (4158331,4158483,4158495,4158496,6069574,6263970,6171615,6540943,6545606,5829430,6198319,6263653,6548381,7242914,8797814,7228149,7439134,7878923,8134147,9002915,9118219,9165534,9354763,9369285,9446720))\n AND (fd.object_id IN (4158460))\n AND (f.crm_provider_id IN ('ForecastCategoryName'))\n ORDER BY fd.object_id ASC, fd.updated_at DESC;\n\nselect * from crm_layouts where crm_configuration_id = 1;\nselect cf.* from crm_fields cf\njoin crm_layout_entities cle on cf.id = cle.crm_field_id\nwhere crm_layout_id = 1493;\n\nSELECT * FROM opportunities WHERE id = 4158460;\nSELECT * FROM crm_field_data WHERE object_id = 4158460;\n\nselect * from users where team_id = 1;\nSELECT * FROM users WHERE id = 7160;\nselect * from role_user where user_id = 3248;\n\nselect * from crm_field_values where crm_field_id = 66824;\n\nSELECT * FROM users WHERE id = 23470;\nselect * from crm_configurations;\n\n# ******************************************\nselect * from teams where id = 1038; # 23521, 966\nselect * from users where team_id = 1038;\nselect * from crm_configurations where id = 966;\nSELECT * FROM activities WHERE uuid_to_bin('e8dc7c34-31f6-4430-bd81-2d9d8f00dd07') = uuid; # 54965762\nSELECT * FROM activities WHERE uuid_to_bin('4b5727c0-69d1-428f-b8d9-b649055166e2') = uuid; # 54965764\nSELECT * FROM participants WHERE activity_id = 54965764;\n\nSELECT id, uuid, title, recording_state FROM activities WHERE uuid_to_bin('355f105d-5606-4379-b0c5-d91daf59f4ce') = uuid; # 54964075\nSELECT * FROM participants WHERE activity_id = 54964075;\nselect f.id, slug, title, tf.team_id from team_features tf JOIN features f on tf.feature_id = f.id\n where tf.team_id = 1038;\n\n\n# ****************************************** PD *************************\nselect * from teams where id = 1029;\nSELECT * FROM crm_configurations WHERE id = 957;\nSELECT * FROM activities WHERE uuid_to_bin('581a33cb-4343-44bd-ac0c-4a5cee71c5ec') = uuid; # 54963423\nSELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433\n\nSELECT * FROM activities WHERE uuid_to_bin('8b6bb2f7-e7a7-4aec-8806-fbfea7093ccd') = uuid; # 54963421\n\n# ****************************************** Close *************************\nselect * from teams where id = 1031;\nSELECT * FROM crm_configurations WHERE id = 959;\nSELECT * FROM activities WHERE uuid_to_bin('59c517e0-96c9-4dad-bfeb-b7bef72f8725') = uuid; # 54963517\n\n\nSELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433\n\nSELECT * FROM activities WHERE uuid_to_bin('d68311e3-ac34-49bd-bf04-88323a7e5352') = uuid; # 54966009\n\n# ****************************************** SF *************************\nSELECT * FROM activities WHERE uuid_to_bin('2bd4cfa3-4eb5-4c77-84a7-9ed46a21c988') = uuid;\n\nselect * from roles;\nselect * from permissions;\nselect * from permission_role where permission_id = 136;\n\nselect * from migrations order by id desc;\n\nselect * from teams where id IN (1, 1037);\nselect * from crm_layouts where crm_configuration_id = 1;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1493;\nSELECT * FROM crm_fields WHERE id IN (1652,1661,66799,66814,66821,66836,66843,66846,66864,84752,182306,323580,380378);\n\nselect * from features;\nselect * from team_features where feature_id = 33;\nselect * from opportunities;\n\nselect * from teams;\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 = 1052 and sa.provider = 'hubspot';\n\nSELECT * FROM accounts where id = 11512582;\nselect * from activities where account_id = 11512582;","role_description":"text entry area","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.13863032,"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}]...
|
808832034558103158
|
6452459292784727903
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
8
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Component\Datadog;
final class Constants
{
public const float FULL_SAMPLE_RATE = 1.0;
public const string ELASTICSEARCH_REFRESH_WAITING_TIME = 'jiminny.elasticsearch.refresh.waiting_time';
public const string ELASTICSEARCH_INSTANT_INSERT = 'jiminny.elasticsearch.instant-write';
public const string ELASTICSEARCH_ASYNC_INSERT = 'jiminny.elasticsearch.async-write';
public const string ELASTICSEARCH_ASYNC_DELETE = 'jiminny.elasticsearch.async-delete';
public const string TRACK_IMPORTED = 'jiminny.track.imported';
public const string TRACK_NO_AUDIO = 'jiminny.track.no_audio';
public const string AUTOSCORE_CALCULATED = 'jiminny.autoscore.calculated';
public const string SCORECARD_CREATED = 'jiminny.scorecard.created';
public const string ACTIVITY_TRANSCRIPTION = 'jiminny.activity.transcription';
public const string ACTIVITIES_INSTANT_PROCESSED_COUNT = 'jiminny.activities.instant.processed.count';
public const string ACTIVITIES_PROCESSED_COUNT = 'jiminny.activities.processed.count';
public const string ACTIVITIES_NOT_PROCESSED_COUNT = 'jiminny.activities.not_processed.count';
public const string MEETINGS_CAPTURE_RATE = 'jiminny.conference';
public const string MEETINGS_CAPTURE_RATE_MEETING_STARTED = 'jiminny.conference.started';
public const string MEETINGS_CAPTURE_RATE_MEETING_ENDED = 'jiminny.conference.ended';
public const string MEETINGS_CAPTURE_RATE_FAILURE = 'jiminny.conference.failure';
public const string MEETINGS_CAPTURE_TIMING_BOT_DELAY = 'jiminny.conference.bot_delay';
public const string MEETINGS_CAPTURE_RATE_CAPTURE_RESULT = 'jiminny.conference.capture_result';
public const string CUSTOMER_API = 'jiminny.customer_api';
public const string ACTIVITY_LANGUAGE_DETECTION_SUCCESS = 'jiminny.activity.language_detection.success';
public const string ACTIVITY_LANGUAGE_DETECTION_FAIL = 'jiminny.activity.language_detection.fail';
public const string ASK_JIMINNY_DEAL_TEAM_REQUEST = 'jiminny.ask_jiminny_deals.team_write_requests';
public const string ASK_JIMINNY_DEAL_TEAM_READ_REQUEST = 'jiminny.ask_jiminny_deals.team_read_requests';
public const string CRM_AUTO_SYNC = 'jiminny.crm.auto-sync';
public const string ACTIVITIES_DIALERS_STATS = 'jiminny.activities.dialers.stats';
public const string ACTIVITIES_DIALERS_REASON_STATS = 'jiminny.activities.dialers.reason.stats';
public const string ACTIVITIES_DIALERS_TRACK_IMPORTED = 'jiminny.activities.dialers.track.imported';
public const string ACTIVITIES_DIALERS_TRACK_DURATION = 'jiminny.activities.dialers.track.duration';
public const string AI_AUTOMATION_CRM_WRITE_EXECUTED = 'jiminny.ai_automation.crm_update_executed';
public const string AUTOMATED_REPORTS = 'jiminny.automated_reports.usage';
public const string ASK_JIMINNY_REPORTS = 'jiminny.ask_jiminny_reports.usage';
public const string HUBSPOT_WEBHOOK_SYNC = 'jiminny.crm.hubspot_webhook_sync';
public const string AI_ACTIVITY_TYPE = 'jiminny.ai_activity_type';
public const string AI_CALL_SCORING = 'jiminny.ai_call_scoring';
public const string WEBHOOK_DELIVERY_SUCCESS = 'jiminny.webhook.delivery.success';
public const string WEBHOOK_DELIVERY_FAILED = 'jiminny.webhook.delivery.failed';
public const string ACTIVITY_PROCESSING_STEP_TIME = 'jiminny.activity.processing.step.time';
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
8
1
3
4
Previous Highlighted Error
Next Highlighted Error
SELECT
# DISTINCT
opp.id as opp_id, opp.uuid, opp.name,
# COUNT(dr.id) AS deal_risk_count,
# dr.id,
# cfd.value,
usr.name AS owner_name,
opp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,
usr.uuid as owner_uuid,
usr.photo_path as owner_photo,
usr.id AS owner_id,
jt.name as owner_job,
opp.stage_id, opp.stage_updated_at,
acc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,
rt.business_process_id AS pipeline_id
FROM opportunities opp
LEFT JOIN record_types rt ON opp.record_type_id = rt.id
LEFT JOIN users usr ON opp.user_id = usr.id
LEFT JOIN accounts acc ON opp.account_id = acc.id
LEFT JOIN job_titles jt ON usr.job_title_id = jt.id
# LEFT JOIN group_deal_risk_types gdrt ON gdrt.group_id = usr.group_id
# LEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id AND dr.group_deal_risk_type_id = gdrt.id
LEFT JOIN crm_field_data cfd ON (cfd.object_id = opp.id and cfd.crm_field_id = 66814)
WHERE opp.user_id IS NOT NULL
AND opp.deleted_at IS NULL
AND opp.is_closed = 1
AND opp.is_won = 0
AND opp.close_date >= '2024-01-01 00:00:00'
AND opp.close_date <= '2024-12-31 23:59:59'
AND usr.team_id = 1
# and opp.id = 4823179
GROUP BY opp.id, cfd.value
ORDER BY
# cfd.value
CAST(cfd.value AS UNSIGNED)
# owner_name
# (SELECT COUNT(dr.id)
# FROM deal_risks dr
# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id
# WHERE dr.opportunity_id = opp.id
# AND dr.is_active = 1
# AND gdrt.is_enabled = 1)
DESC
LIMIT 25
# OFFSET 0
;
select * from crm_fields where crm_configuration_id = 1 and object_type = 'opportunity';
select * from crm_layout_entities where crm_layout_id = 1493;
SELECT * FROM opportunities WHERE id = 4584045;
SELECT * FROM crm_field_data WHERE object_id = 4584045;
SELECT * FROM opportunities where team_id = 1 and crm_provider_id = '0061K00000lfb9IQAQ'
SELECT
opp.id as opportunity_id,
opp.name,
COUNT(dr.id) as risk_count
FROM opportunities opp
LEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id
WHERE opp.id IN (
6069574,8900938,9507638,9524799,9660490,9662824,9705675,9749758,4158460,4391812,6450439,4448422,5118945,5590675,4584045,7228149,9002408,9165534,9446720,9641778,9665149,9703344,9709280,5747948,4158491,6182565,6263970,5798120,5111315,4536978,6062352,6548383,6072095,6548225,4480986,5011422,6548381,8760540,8917554,9509986,9514392,9569009,9569011,9578490,9713604,5784397,7276612,7288405,8994421,9118219,9608148,9818911,4510535,6479693,5958049,6271674,6550448,4158331,4158483,6126571,6171615,6540943,4897466,5190896,5796182,5932762,8572433,8723698,8892697,9711001,9789264,4549188,6100831,6170064,6260799,6263653,6449936,6530871,6538978,7777651,8059269,8319918,8787049,8901150,9263153,9453207,9514738,9696700,9791062,5752018,6421452,7439134,7878923,9354763,9369285,9514396,9582506,9889949,9890216,4094311,4158495,4158496,6098128,5585661,3872564,6442149,5891604,6164746,6199593,6583474,6519684,9018490,9809006,4496897,5041324,5829430,6198319,6253504,6555763,7242914,7931055,8024125,8797814,8058559,8673347,8892695,8994420,9616219,9714970,9722004,9809439,9818918,6523177,8134147,9002915,9711422,9892713,9901719,9954210,9978435,5800810,6243518,6416114,6222251,6411974,6512456,5791953,6545606,9914780,5805540,6238986,6463838,6547680,9767049,9809437,9810885,9890855,6673493,9902036,4335521,6379871,6503799,6546077,8018765,9907556,9958433,9905855,9916179,9946741,9957877,5563344,6271838,6450815,7641128,7762567,7780592,8684810,8685786,8685787,8685788
)
GROUP BY opp.id;
SELECT COUNT(dr.id)
FROM deal_risks dr
JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id
WHERE dr.opportunity_id = 5563344
# AND gdrt.group_id = usr.group_id
EXPLAIN SELECT
opp.id as opp_id, opp.uuid, opp.name,
cfd.value,
cfv.sequence,
cfv.value,
# MAX(cfd.value) AS max_cfd_value,
usr.name AS owner_name,
opp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,
usr.uuid as owner_uuid,
usr.photo_path as owner_photo,
usr.id AS owner_id,
jt.name as owner_job,
opp.stage_id, opp.stage_updated_at,
acc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,
rt.business_process_id AS pipeline_id
FROM opportunities opp
LEFT JOIN record_types rt ON opp.record_type_id = rt.id
LEFT JOIN users usr ON opp.user_id = usr.id
LEFT JOIN accounts acc ON opp.account_id = acc.id
LEFT JOIN job_titles jt ON usr.job_title_id = jt.id
LEFT JOIN crm_field_data cfd ON cfd.id = (SELECT sub_cfd.id
FROM crm_field_data sub_cfd
WHERE sub_cfd.object_id = opp.id
AND sub_cfd.crm_field_id = 66810
ORDER BY sub_cfd.updated_at DESC
LIMIT 1)
LEFT JOIN crm_field_values cfv ON cfv.crm_field_id = 66810 AND cfv.value = cfd.value
WHERE opp.user_id IS NOT NULL
AND opp.deleted_at IS NULL
AND opp.is_closed = 0
# AND opp.is_closed = 1
# AND opp.is_won = 0
AND opp.close_date >= '2024-01-01 00:00:00'
AND opp.close_date <= '2024-12-31 23:59:59'
AND usr.team_id = 1
# and opp.id = 4823179
# GROUP BY opp.id
ORDER BY
cfv.sequence DESC,
# opp.name
# owner_name
cfd.value
# CAST(cfd.value AS UNSIGNED)
# CAST(MAX(cfd.value) AS UNSIGNED)
# (SELECT COUNT(dr.id)
# FROM deal_risks dr
# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id
# WHERE dr.opportunity_id = opp.id
# AND dr.is_active = 1 AND gdrt.is_enabled = 1)
DESC
# LIMIT 75, 25
;
SELECT * FROM crm_field_values WHERE crm_field_id = 66810;
SELECT f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value, fd.updated_at, fd.id, fd.created_at
FROM crm_fields f
INNER JOIN crm_field_data fd ON fd.crm_field_id = f.id
WHERE (f.crm_configuration_id = 1)
AND (f.object_type = 'opportunity')
# AND (fd.object_id IN (4158331,4158483,4158495,4158496,6069574,6263970,6171615,6540943,6545606,5829430,6198319,6263653,6548381,7242914,8797814,7228149,7439134,7878923,8134147,9002915,9118219,9165534,9354763,9369285,9446720))
AND (fd.object_id IN (4158460))
AND (f.crm_provider_id IN ('ForecastCategoryName'))
ORDER BY fd.object_id ASC, fd.updated_at DESC;
select * from crm_layouts where crm_configuration_id = 1;
select cf.* from crm_fields cf
join crm_layout_entities cle on cf.id = cle.crm_field_id
where crm_layout_id = 1493;
SELECT * FROM opportunities WHERE id = 4158460;
SELECT * FROM crm_field_data WHERE object_id = 4158460;
select * from users where team_id = 1;
SELECT * FROM users WHERE id = 7160;
select * from role_user where user_id = 3248;
select * from crm_field_values where crm_field_id = 66824;
SELECT * FROM users WHERE id = 23470;
select * from crm_configurations;
# [PASSWORD_DOTS]
select * from teams where id = 1038; # 23521, 966
select * from users where team_id = 1038;
select * from crm_configurations where id = 966;
SELECT * FROM activities WHERE uuid_to_bin('e8dc7c34-31f6-4430-bd81-2d9d8f00dd07') = uuid; # 54965762
SELECT * FROM activities WHERE uuid_to_bin('4b5727c0-69d1-428f-b8d9-b649055166e2') = uuid; # 54965764
SELECT * FROM participants WHERE activity_id = 54965764;
SELECT id, uuid, title, recording_state FROM activities WHERE uuid_to_bin('355f105d-5606-4379-b0c5-d91daf59f4ce') = uuid; # 54964075
SELECT * FROM participants WHERE activity_id = 54964075;
select f.id, slug, title, tf.team_id from team_features tf JOIN features f on tf.feature_id = f.id
where tf.team_id = 1038;
# [PASSWORD_DOTS] PD [PASSWORD_DOTS]
select * from teams where id = 1029;
SELECT * FROM crm_configurations WHERE id = 957;
SELECT * FROM activities WHERE uuid_to_bin('581a33cb-4343-44bd-ac0c-4a5cee71c5ec') = uuid; # 54963423
SELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433
SELECT * FROM activities WHERE uuid_to_bin('8b6bb2f7-e7a7-4aec-8806-fbfea7093ccd') = uuid; # 54963421
# [PASSWORD_DOTS] Close [PASSWORD_DOTS]
select * from teams where id = 1031;
SELECT * FROM crm_configurations WHERE id = 959;
SELECT * FROM activities WHERE uuid_to_bin('59c517e0-96c9-4dad-bfeb-b7bef72f8725') = uuid; # 54963517
SELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433
SELECT * FROM activities WHERE uuid_to_bin('d68311e3-ac34-49bd-bf04-88323a7e5352') = uuid; # 54966009
# [PASSWORD_DOTS] SF [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('2bd4cfa3-4eb5-4c77-84a7-9ed46a21c988') = uuid;
select * from roles;
select * from permissions;
select * from permission_role where permission_id = 136;
select * from migrations order by id desc;
select * from teams where id IN (1, 1037);
select * from crm_layouts where crm_configuration_id = 1;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 1493;
SELECT * FROM crm_fields WHERE id IN (1652,1661,66799,66814,66821,66836,66843,66846,66864,84752,182306,323580,380378);
select * from features;
select * from team_features where feature_id = 33;
select * from opportunities;
select * from teams;
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 = 1052 and sa.provider = 'hubspot';
SELECT * FROM accounts where id = 11512582;
select * from activities where account_id = 11512582;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
45693
|
NULL
|
NULL
|
NULL
|
|
45694
|
1637
|
15
|
2026-05-14T15:19:10.699126+00:00
|
/Users/lukas/.screenpipe/data/data/2026-05-14/1778 /Users/lukas/.screenpipe/data/data/2026-05-14/1778771950699_m1.jpg...
|
PhpStorm
|
faVsco.js – Constants.php
|
1
|
NULL
|
monitor_1
|
NULL
|
NULL
|
NULL
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
8
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Component\Datadog;
final class Constants
{
public const float FULL_SAMPLE_RATE = 1.0;
public const string ELASTICSEARCH_REFRESH_WAITING_TIME = 'jiminny.elasticsearch.refresh.waiting_time';
public const string ELASTICSEARCH_INSTANT_INSERT = 'jiminny.elasticsearch.instant-write';
public const string ELASTICSEARCH_ASYNC_INSERT = 'jiminny.elasticsearch.async-write';
public const string ELASTICSEARCH_ASYNC_DELETE = 'jiminny.elasticsearch.async-delete';
public const string TRACK_IMPORTED = 'jiminny.track.imported';
public const string TRACK_NO_AUDIO = 'jiminny.track.no_audio';
public const string AUTOSCORE_CALCULATED = 'jiminny.autoscore.calculated';
public const string SCORECARD_CREATED = 'jiminny.scorecard.created';
public const string ACTIVITY_TRANSCRIPTION = 'jiminny.activity.transcription';
public const string ACTIVITIES_INSTANT_PROCESSED_COUNT = 'jiminny.activities.instant.processed.count';
public const string ACTIVITIES_PROCESSED_COUNT = 'jiminny.activities.processed.count';
public const string ACTIVITIES_NOT_PROCESSED_COUNT = 'jiminny.activities.not_processed.count';
public const string MEETINGS_CAPTURE_RATE = 'jiminny.conference';
public const string MEETINGS_CAPTURE_RATE_MEETING_STARTED = 'jiminny.conference.started';
public const string MEETINGS_CAPTURE_RATE_MEETING_ENDED = 'jiminny.conference.ended';
public const string MEETINGS_CAPTURE_RATE_FAILURE = 'jiminny.conference.failure';
public const string MEETINGS_CAPTURE_TIMING_BOT_DELAY = 'jiminny.conference.bot_delay';
public const string MEETINGS_CAPTURE_RATE_CAPTURE_RESULT = 'jiminny.conference.capture_result';
public const string CUSTOMER_API = 'jiminny.customer_api';
public const string ACTIVITY_LANGUAGE_DETECTION_SUCCESS = 'jiminny.activity.language_detection.success';
public const string ACTIVITY_LANGUAGE_DETECTION_FAIL = 'jiminny.activity.language_detection.fail';
public const string ASK_JIMINNY_DEAL_TEAM_REQUEST = 'jiminny.ask_jiminny_deals.team_write_requests';
public const string ASK_JIMINNY_DEAL_TEAM_READ_REQUEST = 'jiminny.ask_jiminny_deals.team_read_requests';
public const string CRM_AUTO_SYNC = 'jiminny.crm.auto-sync';
public const string ACTIVITIES_DIALERS_STATS = 'jiminny.activities.dialers.stats';
public const string ACTIVITIES_DIALERS_REASON_STATS = 'jiminny.activities.dialers.reason.stats';
public const string ACTIVITIES_DIALERS_TRACK_IMPORTED = 'jiminny.activities.dialers.track.imported';
public const string ACTIVITIES_DIALERS_TRACK_DURATION = 'jiminny.activities.dialers.track.duration';
public const string AI_AUTOMATION_CRM_WRITE_EXECUTED = 'jiminny.ai_automation.crm_update_executed';
public const string AUTOMATED_REPORTS = 'jiminny.automated_reports.usage';
public const string ASK_JIMINNY_REPORTS = 'jiminny.ask_jiminny_reports.usage';
public const string HUBSPOT_WEBHOOK_SYNC = 'jiminny.crm.hubspot_webhook_sync';
public const string AI_ACTIVITY_TYPE = 'jiminny.ai_activity_type';
public const string AI_CALL_SCORING = 'jiminny.ai_call_scoring';
public const string WEBHOOK_DELIVERY_SUCCESS = 'jiminny.webhook.delivery.success';
public const string WEBHOOK_DELIVERY_FAILED = 'jiminny.webhook.delivery.failed';
public const string ACTIVITY_PROCESSING_STEP_TIME = 'jiminny.activity.processing.step.time';
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
8
1
3
4
Previous Highlighted Error
Next Highlighted Error
SELECT
# DISTINCT
opp.id as opp_id, opp.uuid, opp.name,
# COUNT(dr.id) AS deal_risk_count,
# dr.id,
# cfd.value,
usr.name AS owner_name,
opp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,
usr.uuid as owner_uuid,
usr.photo_path as owner_photo,
usr.id AS owner_id,
jt.name as owner_job,
opp.stage_id, opp.stage_updated_at,
acc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,
rt.business_process_id AS pipeline_id
FROM opportunities opp
LEFT JOIN record_types rt ON opp.record_type_id = rt.id
LEFT JOIN users usr ON opp.user_id = usr.id
LEFT JOIN accounts acc ON opp.account_id = acc.id
LEFT JOIN job_titles jt ON usr.job_title_id = jt.id
# LEFT JOIN group_deal_risk_types gdrt ON gdrt.group_id = usr.group_id
# LEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id AND dr.group_deal_risk_type_id = gdrt.id
LEFT JOIN crm_field_data cfd ON (cfd.object_id = opp.id and cfd.crm_field_id = 66814)
WHERE opp.user_id IS NOT NULL
AND opp.deleted_at IS NULL
AND opp.is_closed = 1
AND opp.is_won = 0
AND opp.close_date >= '2024-01-01 00:00:00'
AND opp.close_date <= '2024-12-31 23:59:59'
AND usr.team_id = 1
# and opp.id = 4823179
GROUP BY opp.id, cfd.value
ORDER BY
# cfd.value
CAST(cfd.value AS UNSIGNED)
# owner_name
# (SELECT COUNT(dr.id)
# FROM deal_risks dr
# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id
# WHERE dr.opportunity_id = opp.id
# AND dr.is_active = 1
# AND gdrt.is_enabled = 1)
DESC
LIMIT 25
# OFFSET 0
;
select * from crm_fields where crm_configuration_id = 1 and object_type = 'opportunity';
select * from crm_layout_entities where crm_layout_id = 1493;
SELECT * FROM opportunities WHERE id = 4584045;
SELECT * FROM crm_field_data WHERE object_id = 4584045;
SELECT * FROM opportunities where team_id = 1 and crm_provider_id = '0061K00000lfb9IQAQ'
SELECT
opp.id as opportunity_id,
opp.name,
COUNT(dr.id) as risk_count
FROM opportunities opp
LEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id
WHERE opp.id IN (
6069574,8900938,9507638,9524799,9660490,9662824,9705675,9749758,4158460,4391812,6450439,4448422,5118945,5590675,4584045,7228149,9002408,9165534,9446720,9641778,9665149,9703344,9709280,5747948,4158491,6182565,6263970,5798120,5111315,4536978,6062352,6548383,6072095,6548225,4480986,5011422,6548381,8760540,8917554,9509986,9514392,9569009,9569011,9578490,9713604,5784397,7276612,7288405,8994421,9118219,9608148,9818911,4510535,6479693,5958049,6271674,6550448,4158331,4158483,6126571,6171615,6540943,4897466,5190896,5796182,5932762,8572433,8723698,8892697,9711001,9789264,4549188,6100831,6170064,6260799,6263653,6449936,6530871,6538978,7777651,8059269,8319918,8787049,8901150,9263153,9453207,9514738,9696700,9791062,5752018,6421452,7439134,7878923,9354763,9369285,9514396,9582506,9889949,9890216,4094311,4158495,4158496,6098128,5585661,3872564,6442149,5891604,6164746,6199593,6583474,6519684,9018490,9809006,4496897,5041324,5829430,6198319,6253504,6555763,7242914,7931055,8024125,8797814,8058559,8673347,8892695,8994420,9616219,9714970,9722004,9809439,9818918,6523177,8134147,9002915,9711422,9892713,9901719,9954210,9978435,5800810,6243518,6416114,6222251,6411974,6512456,5791953,6545606,9914780,5805540,6238986,6463838,6547680,9767049,9809437,9810885,9890855,6673493,9902036,4335521,6379871,6503799,6546077,8018765,9907556,9958433,9905855,9916179,9946741,9957877,5563344,6271838,6450815,7641128,7762567,7780592,8684810,8685786,8685787,8685788
)
GROUP BY opp.id;
SELECT COUNT(dr.id)
FROM deal_risks dr
JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id
WHERE dr.opportunity_id = 5563344
# AND gdrt.group_id = usr.group_id
EXPLAIN SELECT
opp.id as opp_id, opp.uuid, opp.name,
cfd.value,
cfv.sequence,
cfv.value,
# MAX(cfd.value) AS max_cfd_value,
usr.name AS owner_name,
opp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,
usr.uuid as owner_uuid,
usr.photo_path as owner_photo,
usr.id AS owner_id,
jt.name as owner_job,
opp.stage_id, opp.stage_updated_at,
acc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,
rt.business_process_id AS pipeline_id
FROM opportunities opp
LEFT JOIN record_types rt ON opp.record_type_id = rt.id
LEFT JOIN users usr ON opp.user_id = usr.id
LEFT JOIN accounts acc ON opp.account_id = acc.id
LEFT JOIN job_titles jt ON usr.job_title_id = jt.id
LEFT JOIN crm_field_data cfd ON cfd.id = (SELECT sub_cfd.id
FROM crm_field_data sub_cfd
WHERE sub_cfd.object_id = opp.id
AND sub_cfd.crm_field_id = 66810
ORDER BY sub_cfd.updated_at DESC
LIMIT 1)
LEFT JOIN crm_field_values cfv ON cfv.crm_field_id = 66810 AND cfv.value = cfd.value
WHERE opp.user_id IS NOT NULL
AND opp.deleted_at IS NULL
AND opp.is_closed = 0
# AND opp.is_closed = 1
# AND opp.is_won = 0
AND opp.close_date >= '2024-01-01 00:00:00'
AND opp.close_date <= '2024-12-31 23:59:59'
AND usr.team_id = 1
# and opp.id = 4823179
# GROUP BY opp.id
ORDER BY
cfv.sequence DESC,
# opp.name
# owner_name
cfd.value
# CAST(cfd.value AS UNSIGNED)
# CAST(MAX(cfd.value) AS UNSIGNED)
# (SELECT COUNT(dr.id)
# FROM deal_risks dr
# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id
# WHERE dr.opportunity_id = opp.id
# AND dr.is_active = 1 AND gdrt.is_enabled = 1)
DESC
# LIMIT 75, 25
;
SELECT * FROM crm_field_values WHERE crm_field_id = 66810;
SELECT f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value, fd.updated_at, fd.id, fd.created_at
FROM crm_fields f
INNER JOIN crm_field_data fd ON fd.crm_field_id = f.id
WHERE (f.crm_configuration_id = 1)
AND (f.object_type = 'opportunity')
# AND (fd.object_id IN (4158331,4158483,4158495,4158496,6069574,6263970,6171615,6540943,6545606,5829430,6198319,6263653,6548381,7242914,8797814,7228149,7439134,7878923,8134147,9002915,9118219,9165534,9354763,9369285,9446720))
AND (fd.object_id IN (4158460))
AND (f.crm_provider_id IN ('ForecastCategoryName'))
ORDER BY fd.object_id ASC, fd.updated_at DESC;
select * from crm_layouts where crm_configuration_id = 1;
select cf.* from crm_fields cf
join crm_layout_entities cle on cf.id = cle.crm_field_id
where crm_layout_id = 1493;
SELECT * FROM opportunities WHERE id = 4158460;
SELECT * FROM crm_field_data WHERE object_id = 4158460;
select * from users where team_id = 1;
SELECT * FROM users WHERE id = 7160;
select * from role_user where user_id = 3248;
select * from crm_field_values where crm_field_id = 66824;
SELECT * FROM users WHERE id = 23470;
select * from crm_configurations;
# [PASSWORD_DOTS]
select * from teams where id = 1038; # 23521, 966
select * from users where team_id = 1038;
select * from crm_configurations where id = 966;
SELECT * FROM activities WHERE uuid_to_bin('e8dc7c34-31f6-4430-bd81-2d9d8f00dd07') = uuid; # 54965762
SELECT * FROM activities WHERE uuid_to_bin('4b5727c0-69d1-428f-b8d9-b649055166e2') = uuid; # 54965764
SELECT * FROM participants WHERE activity_id = 54965764;
SELECT id, uuid, title, recording_state FROM activities WHERE uuid_to_bin('355f105d-5606-4379-b0c5-d91daf59f4ce') = uuid; # 54964075
SELECT * FROM participants WHERE activity_id = 54964075;
select f.id, slug, title, tf.team_id from team_features tf JOIN features f on tf.feature_id = f.id
where tf.team_id = 1038;
# [PASSWORD_DOTS] PD [PASSWORD_DOTS]
select * from teams where id = 1029;
SELECT * FROM crm_configurations WHERE id = 957;
SELECT * FROM activities WHERE uuid_to_bin('581a33cb-4343-44bd-ac0c-4a5cee71c5ec') = uuid; # 54963423
SELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433
SELECT * FROM activities WHERE uuid_to_bin('8b6bb2f7-e7a7-4aec-8806-fbfea7093ccd') = uuid; # 54963421
# [PASSWORD_DOTS] Close [PASSWORD_DOTS]
select * from teams where id = 1031;
SELECT * FROM crm_configurations WHERE id = 959;
SELECT * FROM activities WHERE uuid_to_bin('59c517e0-96c9-4dad-bfeb-b7bef72f8725') = uuid; # 54963517
SELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433
SELECT * FROM activities WHERE uuid_to_bin('d68311e3-ac34-49bd-bf04-88323a7e5352') = uuid; # 54966009
# [PASSWORD_DOTS] SF [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('2bd4cfa3-4eb5-4c77-84a7-9ed46a21c988') = uuid;
select * from roles;
select * from permissions;
select * from permission_role where permission_id = 136;
select * from migrations order by id desc;
select * from teams where id IN (1, 1037);
select * from crm_layouts where crm_configuration_id = 1;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 1493;
SELECT * FROM crm_fields WHERE id IN (1652,1661,66799,66814,66821,66836,66843,66846,66864,84752,182306,323580,380378);
select * from features;
select * from team_features where feature_id = 33;
select * from opportunities;
select * from teams;
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 = 1052 and sa.provider = 'hubspot';
SELECT * FROM accounts where id = 11512582;
select * from activities where account_id = 11512582;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
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":"#12066 on JY-20725-handle-HS-search-rate-limit, menu","depth":5,"on_screen":true,"help_text":"Pull request #12066 exists for current branch JY-20725-handle-HS-search-rate-limit, but local branch is out of sync with remote","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":"HandleHubspotRateLimitTest","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Run 'HandleHubspotRateLimitTest'","depth":6,"on_screen":true,"role_description":"button","is_enabled":true,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Debug 'HandleHubspotRateLimitTest'","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":"8","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\\Component\\Datadog;\n\nfinal class Constants\n{\n public const float FULL_SAMPLE_RATE = 1.0;\n\n public const string ELASTICSEARCH_REFRESH_WAITING_TIME = 'jiminny.elasticsearch.refresh.waiting_time';\n public const string ELASTICSEARCH_INSTANT_INSERT = 'jiminny.elasticsearch.instant-write';\n public const string ELASTICSEARCH_ASYNC_INSERT = 'jiminny.elasticsearch.async-write';\n public const string ELASTICSEARCH_ASYNC_DELETE = 'jiminny.elasticsearch.async-delete';\n public const string TRACK_IMPORTED = 'jiminny.track.imported';\n public const string TRACK_NO_AUDIO = 'jiminny.track.no_audio';\n public const string AUTOSCORE_CALCULATED = 'jiminny.autoscore.calculated';\n public const string SCORECARD_CREATED = 'jiminny.scorecard.created';\n public const string ACTIVITY_TRANSCRIPTION = 'jiminny.activity.transcription';\n public const string ACTIVITIES_INSTANT_PROCESSED_COUNT = 'jiminny.activities.instant.processed.count';\n public const string ACTIVITIES_PROCESSED_COUNT = 'jiminny.activities.processed.count';\n public const string ACTIVITIES_NOT_PROCESSED_COUNT = 'jiminny.activities.not_processed.count';\n public const string MEETINGS_CAPTURE_RATE = 'jiminny.conference';\n public const string MEETINGS_CAPTURE_RATE_MEETING_STARTED = 'jiminny.conference.started';\n public const string MEETINGS_CAPTURE_RATE_MEETING_ENDED = 'jiminny.conference.ended';\n public const string MEETINGS_CAPTURE_RATE_FAILURE = 'jiminny.conference.failure';\n public const string MEETINGS_CAPTURE_TIMING_BOT_DELAY = 'jiminny.conference.bot_delay';\n public const string MEETINGS_CAPTURE_RATE_CAPTURE_RESULT = 'jiminny.conference.capture_result';\n public const string CUSTOMER_API = 'jiminny.customer_api';\n public const string ACTIVITY_LANGUAGE_DETECTION_SUCCESS = 'jiminny.activity.language_detection.success';\n public const string ACTIVITY_LANGUAGE_DETECTION_FAIL = 'jiminny.activity.language_detection.fail';\n public const string ASK_JIMINNY_DEAL_TEAM_REQUEST = 'jiminny.ask_jiminny_deals.team_write_requests';\n public const string ASK_JIMINNY_DEAL_TEAM_READ_REQUEST = 'jiminny.ask_jiminny_deals.team_read_requests';\n public const string CRM_AUTO_SYNC = 'jiminny.crm.auto-sync';\n public const string ACTIVITIES_DIALERS_STATS = 'jiminny.activities.dialers.stats';\n public const string ACTIVITIES_DIALERS_REASON_STATS = 'jiminny.activities.dialers.reason.stats';\n public const string ACTIVITIES_DIALERS_TRACK_IMPORTED = 'jiminny.activities.dialers.track.imported';\n public const string ACTIVITIES_DIALERS_TRACK_DURATION = 'jiminny.activities.dialers.track.duration';\n public const string AI_AUTOMATION_CRM_WRITE_EXECUTED = 'jiminny.ai_automation.crm_update_executed';\n public const string AUTOMATED_REPORTS = 'jiminny.automated_reports.usage';\n public const string ASK_JIMINNY_REPORTS = 'jiminny.ask_jiminny_reports.usage';\n public const string HUBSPOT_WEBHOOK_SYNC = 'jiminny.crm.hubspot_webhook_sync';\n public const string AI_ACTIVITY_TYPE = 'jiminny.ai_activity_type';\n public const string AI_CALL_SCORING = 'jiminny.ai_call_scoring';\n public const string WEBHOOK_DELIVERY_SUCCESS = 'jiminny.webhook.delivery.success';\n public const string WEBHOOK_DELIVERY_FAILED = 'jiminny.webhook.delivery.failed';\n public const string ACTIVITY_PROCESSING_STEP_TIME = 'jiminny.activity.processing.step.time';\n}","depth":4,"on_screen":true,"value":"<?php\n\ndeclare(strict_types=1);\n\nnamespace Jiminny\\Component\\Datadog;\n\nfinal class Constants\n{\n public const float FULL_SAMPLE_RATE = 1.0;\n\n public const string ELASTICSEARCH_REFRESH_WAITING_TIME = 'jiminny.elasticsearch.refresh.waiting_time';\n public const string ELASTICSEARCH_INSTANT_INSERT = 'jiminny.elasticsearch.instant-write';\n public const string ELASTICSEARCH_ASYNC_INSERT = 'jiminny.elasticsearch.async-write';\n public const string ELASTICSEARCH_ASYNC_DELETE = 'jiminny.elasticsearch.async-delete';\n public const string TRACK_IMPORTED = 'jiminny.track.imported';\n public const string TRACK_NO_AUDIO = 'jiminny.track.no_audio';\n public const string AUTOSCORE_CALCULATED = 'jiminny.autoscore.calculated';\n public const string SCORECARD_CREATED = 'jiminny.scorecard.created';\n public const string ACTIVITY_TRANSCRIPTION = 'jiminny.activity.transcription';\n public const string ACTIVITIES_INSTANT_PROCESSED_COUNT = 'jiminny.activities.instant.processed.count';\n public const string ACTIVITIES_PROCESSED_COUNT = 'jiminny.activities.processed.count';\n public const string ACTIVITIES_NOT_PROCESSED_COUNT = 'jiminny.activities.not_processed.count';\n public const string MEETINGS_CAPTURE_RATE = 'jiminny.conference';\n public const string MEETINGS_CAPTURE_RATE_MEETING_STARTED = 'jiminny.conference.started';\n public const string MEETINGS_CAPTURE_RATE_MEETING_ENDED = 'jiminny.conference.ended';\n public const string MEETINGS_CAPTURE_RATE_FAILURE = 'jiminny.conference.failure';\n public const string MEETINGS_CAPTURE_TIMING_BOT_DELAY = 'jiminny.conference.bot_delay';\n public const string MEETINGS_CAPTURE_RATE_CAPTURE_RESULT = 'jiminny.conference.capture_result';\n public const string CUSTOMER_API = 'jiminny.customer_api';\n public const string ACTIVITY_LANGUAGE_DETECTION_SUCCESS = 'jiminny.activity.language_detection.success';\n public const string ACTIVITY_LANGUAGE_DETECTION_FAIL = 'jiminny.activity.language_detection.fail';\n public const string ASK_JIMINNY_DEAL_TEAM_REQUEST = 'jiminny.ask_jiminny_deals.team_write_requests';\n public const string ASK_JIMINNY_DEAL_TEAM_READ_REQUEST = 'jiminny.ask_jiminny_deals.team_read_requests';\n public const string CRM_AUTO_SYNC = 'jiminny.crm.auto-sync';\n public const string ACTIVITIES_DIALERS_STATS = 'jiminny.activities.dialers.stats';\n public const string ACTIVITIES_DIALERS_REASON_STATS = 'jiminny.activities.dialers.reason.stats';\n public const string ACTIVITIES_DIALERS_TRACK_IMPORTED = 'jiminny.activities.dialers.track.imported';\n public const string ACTIVITIES_DIALERS_TRACK_DURATION = 'jiminny.activities.dialers.track.duration';\n public const string AI_AUTOMATION_CRM_WRITE_EXECUTED = 'jiminny.ai_automation.crm_update_executed';\n public const string AUTOMATED_REPORTS = 'jiminny.automated_reports.usage';\n public const string ASK_JIMINNY_REPORTS = 'jiminny.ask_jiminny_reports.usage';\n public const string HUBSPOT_WEBHOOK_SYNC = 'jiminny.crm.hubspot_webhook_sync';\n public const string AI_ACTIVITY_TYPE = 'jiminny.ai_activity_type';\n public const string AI_CALL_SCORING = 'jiminny.ai_call_scoring';\n public const string WEBHOOK_DELIVERY_SUCCESS = 'jiminny.webhook.delivery.success';\n public const string WEBHOOK_DELIVERY_FAILED = 'jiminny.webhook.delivery.failed';\n public const string ACTIVITY_PROCESSING_STEP_TIME = 'jiminny.activity.processing.step.time';\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":false,"role_description":"button","is_enabled":false,"is_focused":false,"is_selected":false,"is_expanded":false},{"role":"AXButton","text":"Playground","depth":4,"on_screen":false,"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":"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":"8","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"1","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"3","depth":4,"on_screen":true,"role_description":"text"},{"role":"AXStaticText","text":"4","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":"SELECT\n# DISTINCT\nopp.id as opp_id, opp.uuid, opp.name,\n# COUNT(dr.id) AS deal_risk_count,\n\n# dr.id,\n# cfd.value,\nusr.name AS owner_name,\nopp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,\nusr.uuid as owner_uuid,\nusr.photo_path as owner_photo,\nusr.id AS owner_id,\njt.name as owner_job,\nopp.stage_id, opp.stage_updated_at,\nacc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,\nrt.business_process_id AS pipeline_id\nFROM opportunities opp\nLEFT JOIN record_types rt ON opp.record_type_id = rt.id\nLEFT JOIN users usr ON opp.user_id = usr.id\nLEFT JOIN accounts acc ON opp.account_id = acc.id\nLEFT JOIN job_titles jt ON usr.job_title_id = jt.id\n\n# LEFT JOIN group_deal_risk_types gdrt ON gdrt.group_id = usr.group_id\n# LEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id AND dr.group_deal_risk_type_id = gdrt.id\n\nLEFT JOIN crm_field_data cfd ON (cfd.object_id = opp.id and cfd.crm_field_id = 66814)\n\nWHERE opp.user_id IS NOT NULL\nAND opp.deleted_at IS NULL\nAND opp.is_closed = 1\nAND opp.is_won = 0\nAND opp.close_date >= '2024-01-01 00:00:00'\nAND opp.close_date <= '2024-12-31 23:59:59'\nAND usr.team_id = 1\n\n# and opp.id = 4823179\n\nGROUP BY opp.id, cfd.value\nORDER BY\n# cfd.value\n CAST(cfd.value AS UNSIGNED)\n# owner_name\n# (SELECT COUNT(dr.id)\n# FROM deal_risks dr\n# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n# WHERE dr.opportunity_id = opp.id\n# AND dr.is_active = 1\n# AND gdrt.is_enabled = 1)\nDESC\nLIMIT 25\n# OFFSET 0\n;\n\nselect * from crm_fields where crm_configuration_id = 1 and object_type = 'opportunity';\nselect * from crm_layout_entities where crm_layout_id = 1493;\n\nSELECT * FROM opportunities WHERE id = 4584045;\nSELECT * FROM crm_field_data WHERE object_id = 4584045;\n\nSELECT * FROM opportunities where team_id = 1 and crm_provider_id = '0061K00000lfb9IQAQ'\n\nSELECT\n opp.id as opportunity_id,\n opp.name,\n COUNT(dr.id) as risk_count\nFROM opportunities opp\nLEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id\nWHERE opp.id IN (\n 6069574,8900938,9507638,9524799,9660490,9662824,9705675,9749758,4158460,4391812,6450439,4448422,5118945,5590675,4584045,7228149,9002408,9165534,9446720,9641778,9665149,9703344,9709280,5747948,4158491,6182565,6263970,5798120,5111315,4536978,6062352,6548383,6072095,6548225,4480986,5011422,6548381,8760540,8917554,9509986,9514392,9569009,9569011,9578490,9713604,5784397,7276612,7288405,8994421,9118219,9608148,9818911,4510535,6479693,5958049,6271674,6550448,4158331,4158483,6126571,6171615,6540943,4897466,5190896,5796182,5932762,8572433,8723698,8892697,9711001,9789264,4549188,6100831,6170064,6260799,6263653,6449936,6530871,6538978,7777651,8059269,8319918,8787049,8901150,9263153,9453207,9514738,9696700,9791062,5752018,6421452,7439134,7878923,9354763,9369285,9514396,9582506,9889949,9890216,4094311,4158495,4158496,6098128,5585661,3872564,6442149,5891604,6164746,6199593,6583474,6519684,9018490,9809006,4496897,5041324,5829430,6198319,6253504,6555763,7242914,7931055,8024125,8797814,8058559,8673347,8892695,8994420,9616219,9714970,9722004,9809439,9818918,6523177,8134147,9002915,9711422,9892713,9901719,9954210,9978435,5800810,6243518,6416114,6222251,6411974,6512456,5791953,6545606,9914780,5805540,6238986,6463838,6547680,9767049,9809437,9810885,9890855,6673493,9902036,4335521,6379871,6503799,6546077,8018765,9907556,9958433,9905855,9916179,9946741,9957877,5563344,6271838,6450815,7641128,7762567,7780592,8684810,8685786,8685787,8685788\n)\nGROUP BY opp.id;\n\nSELECT COUNT(dr.id)\n FROM deal_risks dr\n JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n WHERE dr.opportunity_id = 5563344\n# AND gdrt.group_id = usr.group_id\n\n\n\nEXPLAIN SELECT\n opp.id as opp_id, opp.uuid, opp.name,\n\ncfd.value,\ncfv.sequence,\ncfv.value,\n# MAX(cfd.value) AS max_cfd_value,\nusr.name AS owner_name,\nopp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,\nusr.uuid as owner_uuid,\nusr.photo_path as owner_photo,\nusr.id AS owner_id,\njt.name as owner_job,\nopp.stage_id, opp.stage_updated_at,\nacc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,\nrt.business_process_id AS pipeline_id\nFROM opportunities opp\n\nLEFT JOIN record_types rt ON opp.record_type_id = rt.id\nLEFT JOIN users usr ON opp.user_id = usr.id\nLEFT JOIN accounts acc ON opp.account_id = acc.id\nLEFT JOIN job_titles jt ON usr.job_title_id = jt.id\n\nLEFT JOIN crm_field_data cfd ON cfd.id = (SELECT sub_cfd.id\n FROM crm_field_data sub_cfd\n WHERE sub_cfd.object_id = opp.id\n AND sub_cfd.crm_field_id = 66810\n ORDER BY sub_cfd.updated_at DESC\n LIMIT 1)\n\nLEFT JOIN crm_field_values cfv ON cfv.crm_field_id = 66810 AND cfv.value = cfd.value\n\nWHERE opp.user_id IS NOT NULL\nAND opp.deleted_at IS NULL\nAND opp.is_closed = 0\n# AND opp.is_closed = 1\n# AND opp.is_won = 0\nAND opp.close_date >= '2024-01-01 00:00:00'\nAND opp.close_date <= '2024-12-31 23:59:59'\nAND usr.team_id = 1\n\n# and opp.id = 4823179\n\n# GROUP BY opp.id\nORDER BY\n cfv.sequence DESC,\n# opp.name\n# owner_name\n cfd.value\n# CAST(cfd.value AS UNSIGNED)\n# CAST(MAX(cfd.value) AS UNSIGNED)\n# (SELECT COUNT(dr.id)\n# FROM deal_risks dr\n# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n# WHERE dr.opportunity_id = opp.id\n# AND dr.is_active = 1 AND gdrt.is_enabled = 1)\nDESC\n# LIMIT 75, 25\n;\n\n\n\nSELECT * FROM crm_field_values WHERE crm_field_id = 66810;\n\nSELECT f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value, fd.updated_at, fd.id, fd.created_at\nFROM crm_fields f\nINNER JOIN crm_field_data fd ON fd.crm_field_id = f.id\n WHERE (f.crm_configuration_id = 1)\n AND (f.object_type = 'opportunity')\n# AND (fd.object_id IN (4158331,4158483,4158495,4158496,6069574,6263970,6171615,6540943,6545606,5829430,6198319,6263653,6548381,7242914,8797814,7228149,7439134,7878923,8134147,9002915,9118219,9165534,9354763,9369285,9446720))\n AND (fd.object_id IN (4158460))\n AND (f.crm_provider_id IN ('ForecastCategoryName'))\n ORDER BY fd.object_id ASC, fd.updated_at DESC;\n\nselect * from crm_layouts where crm_configuration_id = 1;\nselect cf.* from crm_fields cf\njoin crm_layout_entities cle on cf.id = cle.crm_field_id\nwhere crm_layout_id = 1493;\n\nSELECT * FROM opportunities WHERE id = 4158460;\nSELECT * FROM crm_field_data WHERE object_id = 4158460;\n\nselect * from users where team_id = 1;\nSELECT * FROM users WHERE id = 7160;\nselect * from role_user where user_id = 3248;\n\nselect * from crm_field_values where crm_field_id = 66824;\n\nSELECT * FROM users WHERE id = 23470;\nselect * from crm_configurations;\n\n# ******************************************\nselect * from teams where id = 1038; # 23521, 966\nselect * from users where team_id = 1038;\nselect * from crm_configurations where id = 966;\nSELECT * FROM activities WHERE uuid_to_bin('e8dc7c34-31f6-4430-bd81-2d9d8f00dd07') = uuid; # 54965762\nSELECT * FROM activities WHERE uuid_to_bin('4b5727c0-69d1-428f-b8d9-b649055166e2') = uuid; # 54965764\nSELECT * FROM participants WHERE activity_id = 54965764;\n\nSELECT id, uuid, title, recording_state FROM activities WHERE uuid_to_bin('355f105d-5606-4379-b0c5-d91daf59f4ce') = uuid; # 54964075\nSELECT * FROM participants WHERE activity_id = 54964075;\nselect f.id, slug, title, tf.team_id from team_features tf JOIN features f on tf.feature_id = f.id\n where tf.team_id = 1038;\n\n\n# ****************************************** PD *************************\nselect * from teams where id = 1029;\nSELECT * FROM crm_configurations WHERE id = 957;\nSELECT * FROM activities WHERE uuid_to_bin('581a33cb-4343-44bd-ac0c-4a5cee71c5ec') = uuid; # 54963423\nSELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433\n\nSELECT * FROM activities WHERE uuid_to_bin('8b6bb2f7-e7a7-4aec-8806-fbfea7093ccd') = uuid; # 54963421\n\n# ****************************************** Close *************************\nselect * from teams where id = 1031;\nSELECT * FROM crm_configurations WHERE id = 959;\nSELECT * FROM activities WHERE uuid_to_bin('59c517e0-96c9-4dad-bfeb-b7bef72f8725') = uuid; # 54963517\n\n\nSELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433\n\nSELECT * FROM activities WHERE uuid_to_bin('d68311e3-ac34-49bd-bf04-88323a7e5352') = uuid; # 54966009\n\n# ****************************************** SF *************************\nSELECT * FROM activities WHERE uuid_to_bin('2bd4cfa3-4eb5-4c77-84a7-9ed46a21c988') = uuid;\n\nselect * from roles;\nselect * from permissions;\nselect * from permission_role where permission_id = 136;\n\nselect * from migrations order by id desc;\n\nselect * from teams where id IN (1, 1037);\nselect * from crm_layouts where crm_configuration_id = 1;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1493;\nSELECT * FROM crm_fields WHERE id IN (1652,1661,66799,66814,66821,66836,66843,66846,66864,84752,182306,323580,380378);\n\nselect * from features;\nselect * from team_features where feature_id = 33;\nselect * from opportunities;\n\nselect * from teams;\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 = 1052 and sa.provider = 'hubspot';\n\nSELECT * FROM accounts where id = 11512582;\nselect * from activities where account_id = 11512582;","depth":4,"on_screen":true,"value":"SELECT\n# DISTINCT\nopp.id as opp_id, opp.uuid, opp.name,\n# COUNT(dr.id) AS deal_risk_count,\n\n# dr.id,\n# cfd.value,\nusr.name AS owner_name,\nopp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,\nusr.uuid as owner_uuid,\nusr.photo_path as owner_photo,\nusr.id AS owner_id,\njt.name as owner_job,\nopp.stage_id, opp.stage_updated_at,\nacc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,\nrt.business_process_id AS pipeline_id\nFROM opportunities opp\nLEFT JOIN record_types rt ON opp.record_type_id = rt.id\nLEFT JOIN users usr ON opp.user_id = usr.id\nLEFT JOIN accounts acc ON opp.account_id = acc.id\nLEFT JOIN job_titles jt ON usr.job_title_id = jt.id\n\n# LEFT JOIN group_deal_risk_types gdrt ON gdrt.group_id = usr.group_id\n# LEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id AND dr.group_deal_risk_type_id = gdrt.id\n\nLEFT JOIN crm_field_data cfd ON (cfd.object_id = opp.id and cfd.crm_field_id = 66814)\n\nWHERE opp.user_id IS NOT NULL\nAND opp.deleted_at IS NULL\nAND opp.is_closed = 1\nAND opp.is_won = 0\nAND opp.close_date >= '2024-01-01 00:00:00'\nAND opp.close_date <= '2024-12-31 23:59:59'\nAND usr.team_id = 1\n\n# and opp.id = 4823179\n\nGROUP BY opp.id, cfd.value\nORDER BY\n# cfd.value\n CAST(cfd.value AS UNSIGNED)\n# owner_name\n# (SELECT COUNT(dr.id)\n# FROM deal_risks dr\n# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n# WHERE dr.opportunity_id = opp.id\n# AND dr.is_active = 1\n# AND gdrt.is_enabled = 1)\nDESC\nLIMIT 25\n# OFFSET 0\n;\n\nselect * from crm_fields where crm_configuration_id = 1 and object_type = 'opportunity';\nselect * from crm_layout_entities where crm_layout_id = 1493;\n\nSELECT * FROM opportunities WHERE id = 4584045;\nSELECT * FROM crm_field_data WHERE object_id = 4584045;\n\nSELECT * FROM opportunities where team_id = 1 and crm_provider_id = '0061K00000lfb9IQAQ'\n\nSELECT\n opp.id as opportunity_id,\n opp.name,\n COUNT(dr.id) as risk_count\nFROM opportunities opp\nLEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id\nWHERE opp.id IN (\n 6069574,8900938,9507638,9524799,9660490,9662824,9705675,9749758,4158460,4391812,6450439,4448422,5118945,5590675,4584045,7228149,9002408,9165534,9446720,9641778,9665149,9703344,9709280,5747948,4158491,6182565,6263970,5798120,5111315,4536978,6062352,6548383,6072095,6548225,4480986,5011422,6548381,8760540,8917554,9509986,9514392,9569009,9569011,9578490,9713604,5784397,7276612,7288405,8994421,9118219,9608148,9818911,4510535,6479693,5958049,6271674,6550448,4158331,4158483,6126571,6171615,6540943,4897466,5190896,5796182,5932762,8572433,8723698,8892697,9711001,9789264,4549188,6100831,6170064,6260799,6263653,6449936,6530871,6538978,7777651,8059269,8319918,8787049,8901150,9263153,9453207,9514738,9696700,9791062,5752018,6421452,7439134,7878923,9354763,9369285,9514396,9582506,9889949,9890216,4094311,4158495,4158496,6098128,5585661,3872564,6442149,5891604,6164746,6199593,6583474,6519684,9018490,9809006,4496897,5041324,5829430,6198319,6253504,6555763,7242914,7931055,8024125,8797814,8058559,8673347,8892695,8994420,9616219,9714970,9722004,9809439,9818918,6523177,8134147,9002915,9711422,9892713,9901719,9954210,9978435,5800810,6243518,6416114,6222251,6411974,6512456,5791953,6545606,9914780,5805540,6238986,6463838,6547680,9767049,9809437,9810885,9890855,6673493,9902036,4335521,6379871,6503799,6546077,8018765,9907556,9958433,9905855,9916179,9946741,9957877,5563344,6271838,6450815,7641128,7762567,7780592,8684810,8685786,8685787,8685788\n)\nGROUP BY opp.id;\n\nSELECT COUNT(dr.id)\n FROM deal_risks dr\n JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n WHERE dr.opportunity_id = 5563344\n# AND gdrt.group_id = usr.group_id\n\n\n\nEXPLAIN SELECT\n opp.id as opp_id, opp.uuid, opp.name,\n\ncfd.value,\ncfv.sequence,\ncfv.value,\n# MAX(cfd.value) AS max_cfd_value,\nusr.name AS owner_name,\nopp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,\nusr.uuid as owner_uuid,\nusr.photo_path as owner_photo,\nusr.id AS owner_id,\njt.name as owner_job,\nopp.stage_id, opp.stage_updated_at,\nacc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,\nrt.business_process_id AS pipeline_id\nFROM opportunities opp\n\nLEFT JOIN record_types rt ON opp.record_type_id = rt.id\nLEFT JOIN users usr ON opp.user_id = usr.id\nLEFT JOIN accounts acc ON opp.account_id = acc.id\nLEFT JOIN job_titles jt ON usr.job_title_id = jt.id\n\nLEFT JOIN crm_field_data cfd ON cfd.id = (SELECT sub_cfd.id\n FROM crm_field_data sub_cfd\n WHERE sub_cfd.object_id = opp.id\n AND sub_cfd.crm_field_id = 66810\n ORDER BY sub_cfd.updated_at DESC\n LIMIT 1)\n\nLEFT JOIN crm_field_values cfv ON cfv.crm_field_id = 66810 AND cfv.value = cfd.value\n\nWHERE opp.user_id IS NOT NULL\nAND opp.deleted_at IS NULL\nAND opp.is_closed = 0\n# AND opp.is_closed = 1\n# AND opp.is_won = 0\nAND opp.close_date >= '2024-01-01 00:00:00'\nAND opp.close_date <= '2024-12-31 23:59:59'\nAND usr.team_id = 1\n\n# and opp.id = 4823179\n\n# GROUP BY opp.id\nORDER BY\n cfv.sequence DESC,\n# opp.name\n# owner_name\n cfd.value\n# CAST(cfd.value AS UNSIGNED)\n# CAST(MAX(cfd.value) AS UNSIGNED)\n# (SELECT COUNT(dr.id)\n# FROM deal_risks dr\n# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id\n# WHERE dr.opportunity_id = opp.id\n# AND dr.is_active = 1 AND gdrt.is_enabled = 1)\nDESC\n# LIMIT 75, 25\n;\n\n\n\nSELECT * FROM crm_field_values WHERE crm_field_id = 66810;\n\nSELECT f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value, fd.updated_at, fd.id, fd.created_at\nFROM crm_fields f\nINNER JOIN crm_field_data fd ON fd.crm_field_id = f.id\n WHERE (f.crm_configuration_id = 1)\n AND (f.object_type = 'opportunity')\n# AND (fd.object_id IN (4158331,4158483,4158495,4158496,6069574,6263970,6171615,6540943,6545606,5829430,6198319,6263653,6548381,7242914,8797814,7228149,7439134,7878923,8134147,9002915,9118219,9165534,9354763,9369285,9446720))\n AND (fd.object_id IN (4158460))\n AND (f.crm_provider_id IN ('ForecastCategoryName'))\n ORDER BY fd.object_id ASC, fd.updated_at DESC;\n\nselect * from crm_layouts where crm_configuration_id = 1;\nselect cf.* from crm_fields cf\njoin crm_layout_entities cle on cf.id = cle.crm_field_id\nwhere crm_layout_id = 1493;\n\nSELECT * FROM opportunities WHERE id = 4158460;\nSELECT * FROM crm_field_data WHERE object_id = 4158460;\n\nselect * from users where team_id = 1;\nSELECT * FROM users WHERE id = 7160;\nselect * from role_user where user_id = 3248;\n\nselect * from crm_field_values where crm_field_id = 66824;\n\nSELECT * FROM users WHERE id = 23470;\nselect * from crm_configurations;\n\n# ******************************************\nselect * from teams where id = 1038; # 23521, 966\nselect * from users where team_id = 1038;\nselect * from crm_configurations where id = 966;\nSELECT * FROM activities WHERE uuid_to_bin('e8dc7c34-31f6-4430-bd81-2d9d8f00dd07') = uuid; # 54965762\nSELECT * FROM activities WHERE uuid_to_bin('4b5727c0-69d1-428f-b8d9-b649055166e2') = uuid; # 54965764\nSELECT * FROM participants WHERE activity_id = 54965764;\n\nSELECT id, uuid, title, recording_state FROM activities WHERE uuid_to_bin('355f105d-5606-4379-b0c5-d91daf59f4ce') = uuid; # 54964075\nSELECT * FROM participants WHERE activity_id = 54964075;\nselect f.id, slug, title, tf.team_id from team_features tf JOIN features f on tf.feature_id = f.id\n where tf.team_id = 1038;\n\n\n# ****************************************** PD *************************\nselect * from teams where id = 1029;\nSELECT * FROM crm_configurations WHERE id = 957;\nSELECT * FROM activities WHERE uuid_to_bin('581a33cb-4343-44bd-ac0c-4a5cee71c5ec') = uuid; # 54963423\nSELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433\n\nSELECT * FROM activities WHERE uuid_to_bin('8b6bb2f7-e7a7-4aec-8806-fbfea7093ccd') = uuid; # 54963421\n\n# ****************************************** Close *************************\nselect * from teams where id = 1031;\nSELECT * FROM crm_configurations WHERE id = 959;\nSELECT * FROM activities WHERE uuid_to_bin('59c517e0-96c9-4dad-bfeb-b7bef72f8725') = uuid; # 54963517\n\n\nSELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433\n\nSELECT * FROM activities WHERE uuid_to_bin('d68311e3-ac34-49bd-bf04-88323a7e5352') = uuid; # 54966009\n\n# ****************************************** SF *************************\nSELECT * FROM activities WHERE uuid_to_bin('2bd4cfa3-4eb5-4c77-84a7-9ed46a21c988') = uuid;\n\nselect * from roles;\nselect * from permissions;\nselect * from permission_role where permission_id = 136;\n\nselect * from migrations order by id desc;\n\nselect * from teams where id IN (1, 1037);\nselect * from crm_layouts where crm_configuration_id = 1;\nSELECT * FROM crm_layout_entities WHERE crm_layout_id = 1493;\nSELECT * FROM crm_fields WHERE id IN (1652,1661,66799,66814,66821,66836,66843,66846,66864,84752,182306,323580,380378);\n\nselect * from features;\nselect * from team_features where feature_id = 33;\nselect * from opportunities;\n\nselect * from teams;\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 = 1052 and sa.provider = 'hubspot';\n\nSELECT * FROM accounts where id = 11512582;\nselect * from activities where account_id = 11512582;","role_description":"text entry area","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,"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.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":"Expand Selected","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":"Collapse All","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":"Options","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":"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}]...
|
808832034558103158
|
6452459292784727903
|
visual_change
|
accessibility
|
NULL
|
Project: faVsco.js, menu
#12066 on JY-20725-handle Project: faVsco.js, menu
#12066 on JY-20725-handle-HS-search-rate-limit, menu
Start Listening for PHP Debug Connections
HandleHubspotRateLimitTest
Run 'HandleHubspotRateLimitTest'
Debug 'HandleHubspotRateLimitTest'
More Actions
JetBrains AI
Search Everywhere
IDE and Project Settings
Sync Changes
Hide This Notification
Code changed:
Hide
8
Previous Highlighted Error
Next Highlighted Error
<?php
declare(strict_types=1);
namespace Jiminny\Component\Datadog;
final class Constants
{
public const float FULL_SAMPLE_RATE = 1.0;
public const string ELASTICSEARCH_REFRESH_WAITING_TIME = 'jiminny.elasticsearch.refresh.waiting_time';
public const string ELASTICSEARCH_INSTANT_INSERT = 'jiminny.elasticsearch.instant-write';
public const string ELASTICSEARCH_ASYNC_INSERT = 'jiminny.elasticsearch.async-write';
public const string ELASTICSEARCH_ASYNC_DELETE = 'jiminny.elasticsearch.async-delete';
public const string TRACK_IMPORTED = 'jiminny.track.imported';
public const string TRACK_NO_AUDIO = 'jiminny.track.no_audio';
public const string AUTOSCORE_CALCULATED = 'jiminny.autoscore.calculated';
public const string SCORECARD_CREATED = 'jiminny.scorecard.created';
public const string ACTIVITY_TRANSCRIPTION = 'jiminny.activity.transcription';
public const string ACTIVITIES_INSTANT_PROCESSED_COUNT = 'jiminny.activities.instant.processed.count';
public const string ACTIVITIES_PROCESSED_COUNT = 'jiminny.activities.processed.count';
public const string ACTIVITIES_NOT_PROCESSED_COUNT = 'jiminny.activities.not_processed.count';
public const string MEETINGS_CAPTURE_RATE = 'jiminny.conference';
public const string MEETINGS_CAPTURE_RATE_MEETING_STARTED = 'jiminny.conference.started';
public const string MEETINGS_CAPTURE_RATE_MEETING_ENDED = 'jiminny.conference.ended';
public const string MEETINGS_CAPTURE_RATE_FAILURE = 'jiminny.conference.failure';
public const string MEETINGS_CAPTURE_TIMING_BOT_DELAY = 'jiminny.conference.bot_delay';
public const string MEETINGS_CAPTURE_RATE_CAPTURE_RESULT = 'jiminny.conference.capture_result';
public const string CUSTOMER_API = 'jiminny.customer_api';
public const string ACTIVITY_LANGUAGE_DETECTION_SUCCESS = 'jiminny.activity.language_detection.success';
public const string ACTIVITY_LANGUAGE_DETECTION_FAIL = 'jiminny.activity.language_detection.fail';
public const string ASK_JIMINNY_DEAL_TEAM_REQUEST = 'jiminny.ask_jiminny_deals.team_write_requests';
public const string ASK_JIMINNY_DEAL_TEAM_READ_REQUEST = 'jiminny.ask_jiminny_deals.team_read_requests';
public const string CRM_AUTO_SYNC = 'jiminny.crm.auto-sync';
public const string ACTIVITIES_DIALERS_STATS = 'jiminny.activities.dialers.stats';
public const string ACTIVITIES_DIALERS_REASON_STATS = 'jiminny.activities.dialers.reason.stats';
public const string ACTIVITIES_DIALERS_TRACK_IMPORTED = 'jiminny.activities.dialers.track.imported';
public const string ACTIVITIES_DIALERS_TRACK_DURATION = 'jiminny.activities.dialers.track.duration';
public const string AI_AUTOMATION_CRM_WRITE_EXECUTED = 'jiminny.ai_automation.crm_update_executed';
public const string AUTOMATED_REPORTS = 'jiminny.automated_reports.usage';
public const string ASK_JIMINNY_REPORTS = 'jiminny.ask_jiminny_reports.usage';
public const string HUBSPOT_WEBHOOK_SYNC = 'jiminny.crm.hubspot_webhook_sync';
public const string AI_ACTIVITY_TYPE = 'jiminny.ai_activity_type';
public const string AI_CALL_SCORING = 'jiminny.ai_call_scoring';
public const string WEBHOOK_DELIVERY_SUCCESS = 'jiminny.webhook.delivery.success';
public const string WEBHOOK_DELIVERY_FAILED = 'jiminny.webhook.delivery.failed';
public const string ACTIVITY_PROCESSING_STEP_TIME = 'jiminny.activity.processing.step.time';
}
Execute
Explain Plan
Browse Query History
View Parameters
Open Query Execution Settings…
In-Editor Results
Tx: Auto
Cancel Running Statements
Playground
jiminny
Sync Changes
Hide This Notification
Code changed:
Hide
8
1
3
4
Previous Highlighted Error
Next Highlighted Error
SELECT
# DISTINCT
opp.id as opp_id, opp.uuid, opp.name,
# COUNT(dr.id) AS deal_risk_count,
# dr.id,
# cfd.value,
usr.name AS owner_name,
opp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,
usr.uuid as owner_uuid,
usr.photo_path as owner_photo,
usr.id AS owner_id,
jt.name as owner_job,
opp.stage_id, opp.stage_updated_at,
acc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,
rt.business_process_id AS pipeline_id
FROM opportunities opp
LEFT JOIN record_types rt ON opp.record_type_id = rt.id
LEFT JOIN users usr ON opp.user_id = usr.id
LEFT JOIN accounts acc ON opp.account_id = acc.id
LEFT JOIN job_titles jt ON usr.job_title_id = jt.id
# LEFT JOIN group_deal_risk_types gdrt ON gdrt.group_id = usr.group_id
# LEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id AND dr.group_deal_risk_type_id = gdrt.id
LEFT JOIN crm_field_data cfd ON (cfd.object_id = opp.id and cfd.crm_field_id = 66814)
WHERE opp.user_id IS NOT NULL
AND opp.deleted_at IS NULL
AND opp.is_closed = 1
AND opp.is_won = 0
AND opp.close_date >= '2024-01-01 00:00:00'
AND opp.close_date <= '2024-12-31 23:59:59'
AND usr.team_id = 1
# and opp.id = 4823179
GROUP BY opp.id, cfd.value
ORDER BY
# cfd.value
CAST(cfd.value AS UNSIGNED)
# owner_name
# (SELECT COUNT(dr.id)
# FROM deal_risks dr
# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id
# WHERE dr.opportunity_id = opp.id
# AND dr.is_active = 1
# AND gdrt.is_enabled = 1)
DESC
LIMIT 25
# OFFSET 0
;
select * from crm_fields where crm_configuration_id = 1 and object_type = 'opportunity';
select * from crm_layout_entities where crm_layout_id = 1493;
SELECT * FROM opportunities WHERE id = 4584045;
SELECT * FROM crm_field_data WHERE object_id = 4584045;
SELECT * FROM opportunities where team_id = 1 and crm_provider_id = '0061K00000lfb9IQAQ'
SELECT
opp.id as opportunity_id,
opp.name,
COUNT(dr.id) as risk_count
FROM opportunities opp
LEFT JOIN deal_risks dr ON dr.opportunity_id = opp.id
WHERE opp.id IN (
6069574,8900938,9507638,9524799,9660490,9662824,9705675,9749758,4158460,4391812,6450439,4448422,5118945,5590675,4584045,7228149,9002408,9165534,9446720,9641778,9665149,9703344,9709280,5747948,4158491,6182565,6263970,5798120,5111315,4536978,6062352,6548383,6072095,6548225,4480986,5011422,6548381,8760540,8917554,9509986,9514392,9569009,9569011,9578490,9713604,5784397,7276612,7288405,8994421,9118219,9608148,9818911,4510535,6479693,5958049,6271674,6550448,4158331,4158483,6126571,6171615,6540943,4897466,5190896,5796182,5932762,8572433,8723698,8892697,9711001,9789264,4549188,6100831,6170064,6260799,6263653,6449936,6530871,6538978,7777651,8059269,8319918,8787049,8901150,9263153,9453207,9514738,9696700,9791062,5752018,6421452,7439134,7878923,9354763,9369285,9514396,9582506,9889949,9890216,4094311,4158495,4158496,6098128,5585661,3872564,6442149,5891604,6164746,6199593,6583474,6519684,9018490,9809006,4496897,5041324,5829430,6198319,6253504,6555763,7242914,7931055,8024125,8797814,8058559,8673347,8892695,8994420,9616219,9714970,9722004,9809439,9818918,6523177,8134147,9002915,9711422,9892713,9901719,9954210,9978435,5800810,6243518,6416114,6222251,6411974,6512456,5791953,6545606,9914780,5805540,6238986,6463838,6547680,9767049,9809437,9810885,9890855,6673493,9902036,4335521,6379871,6503799,6546077,8018765,9907556,9958433,9905855,9916179,9946741,9957877,5563344,6271838,6450815,7641128,7762567,7780592,8684810,8685786,8685787,8685788
)
GROUP BY opp.id;
SELECT COUNT(dr.id)
FROM deal_risks dr
JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id
WHERE dr.opportunity_id = 5563344
# AND gdrt.group_id = usr.group_id
EXPLAIN SELECT
opp.id as opp_id, opp.uuid, opp.name,
cfd.value,
cfv.sequence,
cfv.value,
# MAX(cfd.value) AS max_cfd_value,
usr.name AS owner_name,
opp.value, opp.currency_code, opp.close_date, opp.remotely_created_at, opp.is_closed, opp.is_won,
usr.uuid as owner_uuid,
usr.photo_path as owner_photo,
usr.id AS owner_id,
jt.name as owner_job,
opp.stage_id, opp.stage_updated_at,
acc.name AS acc_name, opp.stage_updated_at, acc.crm_provider_id AS acc_provider_id, opp.crm_provider_id AS opp_provider_id,
rt.business_process_id AS pipeline_id
FROM opportunities opp
LEFT JOIN record_types rt ON opp.record_type_id = rt.id
LEFT JOIN users usr ON opp.user_id = usr.id
LEFT JOIN accounts acc ON opp.account_id = acc.id
LEFT JOIN job_titles jt ON usr.job_title_id = jt.id
LEFT JOIN crm_field_data cfd ON cfd.id = (SELECT sub_cfd.id
FROM crm_field_data sub_cfd
WHERE sub_cfd.object_id = opp.id
AND sub_cfd.crm_field_id = 66810
ORDER BY sub_cfd.updated_at DESC
LIMIT 1)
LEFT JOIN crm_field_values cfv ON cfv.crm_field_id = 66810 AND cfv.value = cfd.value
WHERE opp.user_id IS NOT NULL
AND opp.deleted_at IS NULL
AND opp.is_closed = 0
# AND opp.is_closed = 1
# AND opp.is_won = 0
AND opp.close_date >= '2024-01-01 00:00:00'
AND opp.close_date <= '2024-12-31 23:59:59'
AND usr.team_id = 1
# and opp.id = 4823179
# GROUP BY opp.id
ORDER BY
cfv.sequence DESC,
# opp.name
# owner_name
cfd.value
# CAST(cfd.value AS UNSIGNED)
# CAST(MAX(cfd.value) AS UNSIGNED)
# (SELECT COUNT(dr.id)
# FROM deal_risks dr
# JOIN group_deal_risk_types gdrt ON dr.group_deal_risk_type_id = gdrt.id
# WHERE dr.opportunity_id = opp.id
# AND dr.is_active = 1 AND gdrt.is_enabled = 1)
DESC
# LIMIT 75, 25
;
SELECT * FROM crm_field_values WHERE crm_field_id = 66810;
SELECT f.id, f.crm_provider_id AS field_name, f.label, fd.object_id AS dealId, fd.value, fd.updated_at, fd.id, fd.created_at
FROM crm_fields f
INNER JOIN crm_field_data fd ON fd.crm_field_id = f.id
WHERE (f.crm_configuration_id = 1)
AND (f.object_type = 'opportunity')
# AND (fd.object_id IN (4158331,4158483,4158495,4158496,6069574,6263970,6171615,6540943,6545606,5829430,6198319,6263653,6548381,7242914,8797814,7228149,7439134,7878923,8134147,9002915,9118219,9165534,9354763,9369285,9446720))
AND (fd.object_id IN (4158460))
AND (f.crm_provider_id IN ('ForecastCategoryName'))
ORDER BY fd.object_id ASC, fd.updated_at DESC;
select * from crm_layouts where crm_configuration_id = 1;
select cf.* from crm_fields cf
join crm_layout_entities cle on cf.id = cle.crm_field_id
where crm_layout_id = 1493;
SELECT * FROM opportunities WHERE id = 4158460;
SELECT * FROM crm_field_data WHERE object_id = 4158460;
select * from users where team_id = 1;
SELECT * FROM users WHERE id = 7160;
select * from role_user where user_id = 3248;
select * from crm_field_values where crm_field_id = 66824;
SELECT * FROM users WHERE id = 23470;
select * from crm_configurations;
# [PASSWORD_DOTS]
select * from teams where id = 1038; # 23521, 966
select * from users where team_id = 1038;
select * from crm_configurations where id = 966;
SELECT * FROM activities WHERE uuid_to_bin('e8dc7c34-31f6-4430-bd81-2d9d8f00dd07') = uuid; # 54965762
SELECT * FROM activities WHERE uuid_to_bin('4b5727c0-69d1-428f-b8d9-b649055166e2') = uuid; # 54965764
SELECT * FROM participants WHERE activity_id = 54965764;
SELECT id, uuid, title, recording_state FROM activities WHERE uuid_to_bin('355f105d-5606-4379-b0c5-d91daf59f4ce') = uuid; # 54964075
SELECT * FROM participants WHERE activity_id = 54964075;
select f.id, slug, title, tf.team_id from team_features tf JOIN features f on tf.feature_id = f.id
where tf.team_id = 1038;
# [PASSWORD_DOTS] PD [PASSWORD_DOTS]
select * from teams where id = 1029;
SELECT * FROM crm_configurations WHERE id = 957;
SELECT * FROM activities WHERE uuid_to_bin('581a33cb-4343-44bd-ac0c-4a5cee71c5ec') = uuid; # 54963423
SELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433
SELECT * FROM activities WHERE uuid_to_bin('8b6bb2f7-e7a7-4aec-8806-fbfea7093ccd') = uuid; # 54963421
# [PASSWORD_DOTS] Close [PASSWORD_DOTS]
select * from teams where id = 1031;
SELECT * FROM crm_configurations WHERE id = 959;
SELECT * FROM activities WHERE uuid_to_bin('59c517e0-96c9-4dad-bfeb-b7bef72f8725') = uuid; # 54963517
SELECT * FROM activities WHERE uuid_to_bin('07238011-25fa-418e-838b-fb21e82b9ea2') = uuid; # 54963433
SELECT * FROM activities WHERE uuid_to_bin('d68311e3-ac34-49bd-bf04-88323a7e5352') = uuid; # 54966009
# [PASSWORD_DOTS] SF [PASSWORD_DOTS]
SELECT * FROM activities WHERE uuid_to_bin('2bd4cfa3-4eb5-4c77-84a7-9ed46a21c988') = uuid;
select * from roles;
select * from permissions;
select * from permission_role where permission_id = 136;
select * from migrations order by id desc;
select * from teams where id IN (1, 1037);
select * from crm_layouts where crm_configuration_id = 1;
SELECT * FROM crm_layout_entities WHERE crm_layout_id = 1493;
SELECT * FROM crm_fields WHERE id IN (1652,1661,66799,66814,66821,66836,66843,66846,66864,84752,182306,323580,380378);
select * from features;
select * from team_features where feature_id = 33;
select * from opportunities;
select * from teams;
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 = 1052 and sa.provider = 'hubspot';
SELECT * FROM accounts where id = 11512582;
select * from activities where account_id = 11512582;
Project
Project
New File or Directory…
Expand Selected
Collapse All
Options
Hide...
|
NULL
|
NULL
|
NULL
|
NULL
|